├── .editorconfig ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── cmake-qemu-arm.yml │ ├── cmake.yml │ ├── codeql.yml │ ├── flawfinder-analysis.yml │ ├── msbuild.yml │ └── msvc-analysis.yml ├── .gitignore ├── CMake └── modules │ └── coverage.cmake ├── CMakeLists.txt ├── CMakePresets.json ├── CNAME ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── _config.yml ├── assets ├── css │ └── style.scss └── logos │ ├── hfsm2-logo-jekyll.png │ └── hfsm2-logo-large.png ├── development └── hfsm2 │ ├── detail │ ├── config.hpp │ ├── containers │ │ ├── array.hpp │ │ ├── array.inl │ │ ├── bit_array.hpp │ │ └── bit_array.inl │ ├── features │ │ ├── logger_interface.hpp │ │ ├── structure_report.hpp │ │ ├── task.hpp │ │ ├── task_list.hpp │ │ ├── task_list.inl │ │ └── transition.hpp │ ├── root │ │ ├── control_0.hpp │ │ ├── control_0.inl │ │ ├── control_1.hpp │ │ ├── control_1.inl │ │ ├── control_2.hpp │ │ ├── control_2.inl │ │ ├── control_3.hpp │ │ ├── control_3.inl │ │ ├── control_4.hpp │ │ ├── control_4.inl │ │ ├── control_5.hpp │ │ ├── core.hpp │ │ ├── core.inl │ │ ├── plan_0.hpp │ │ ├── plan_0.inl │ │ ├── plan_1.hpp │ │ ├── plan_1.inl │ │ ├── plan_2.hpp │ │ ├── plan_2.inl │ │ ├── plan_data.hpp │ │ ├── plan_data.inl │ │ ├── registry.hpp │ │ ├── registry_1.inl │ │ └── registry_2.inl │ ├── root_0.hpp │ ├── root_0.inl │ ├── root_1.hpp │ ├── root_1.inl │ ├── root_2.hpp │ ├── root_2.inl │ ├── root_3.hpp │ ├── root_3.inl │ ├── root_4.hpp │ ├── shared │ │ ├── bit_stream.hpp │ │ ├── bit_stream.inl │ │ ├── iterator.hpp │ │ ├── macros_off.hpp │ │ ├── macros_on.hpp │ │ ├── random.hpp │ │ ├── random.inl │ │ ├── type_list.hpp │ │ └── utility.hpp │ └── structure │ │ ├── ancestors_1.hpp │ │ ├── ancestors_1.inl │ │ ├── ancestors_2.hpp │ │ ├── ancestors_2.inl │ │ ├── base.hpp │ │ ├── composite.hpp │ │ ├── composite.inl │ │ ├── composite_sub_1.hpp │ │ ├── composite_sub_1.inl │ │ ├── composite_sub_2.hpp │ │ ├── composite_sub_2.inl │ │ ├── forward.hpp │ │ ├── orthogonal.hpp │ │ ├── orthogonal.inl │ │ ├── orthogonal_sub_1.hpp │ │ ├── orthogonal_sub_1.inl │ │ ├── orthogonal_sub_2.hpp │ │ ├── orthogonal_sub_2.inl │ │ ├── reactions.inl │ │ ├── state_1.hpp │ │ ├── state_1.inl │ │ ├── state_2.hpp │ │ └── state_2.inl │ └── machine_dev.hpp ├── examples ├── advanced_event_handling │ ├── CMakeLists.txt │ └── main.cpp ├── basic_audio_player │ ├── CMakeLists.txt │ └── main.cpp ├── basic_traffic_light │ ├── CMakeLists.txt │ └── main.cpp ├── calculator │ ├── CMakeLists.txt │ └── main.cpp ├── debug_logger_interface │ ├── CMakeLists.txt │ └── main.cpp ├── snippets │ └── wiki_utility-theory.cpp └── temp │ ├── CMakeLists.txt │ └── main.cpp ├── external └── doctest │ └── doctest.h ├── hfsm2.natvis ├── include └── hfsm2 │ └── machine.hpp ├── premake.cmd ├── premake.lua ├── projects ├── code-lite │ ├── hfsm2.workspace │ └── test │ │ ├── tags │ │ └── test.project ├── premake │ ├── advanced_event_handling-14.vcxproj │ ├── advanced_event_handling-15.vcxproj │ ├── advanced_event_handling-16.vcxproj │ ├── advanced_event_handling-17.vcxproj │ ├── advanced_event_handling-clang.vcxproj │ ├── basic_audio_player-14.vcxproj │ ├── basic_audio_player-15.vcxproj │ ├── basic_audio_player-16.vcxproj │ ├── basic_audio_player-17.vcxproj │ ├── basic_audio_player-clang.vcxproj │ ├── basic_traffic_light-14.vcxproj │ ├── basic_traffic_light-15.vcxproj │ ├── basic_traffic_light-16.vcxproj │ ├── basic_traffic_light-17.vcxproj │ ├── basic_traffic_light-clang.vcxproj │ ├── calculator-14.vcxproj │ ├── calculator-15.vcxproj │ ├── calculator-16.vcxproj │ ├── calculator-17.vcxproj │ ├── calculator-clang.vcxproj │ ├── debug_logger_interface-14.vcxproj │ ├── debug_logger_interface-15.vcxproj │ ├── debug_logger_interface-16.vcxproj │ ├── debug_logger_interface-17.vcxproj │ ├── debug_logger_interface-clang.vcxproj │ ├── hfsm2-all.sln │ ├── hfsm2-lite.sln │ ├── hfsm2-vs-2019.sln │ ├── hfsm2-vs-2022.sln │ ├── snippets-14.vcxproj │ ├── snippets-14.vcxproj.filters │ ├── snippets-15.vcxproj │ ├── snippets-15.vcxproj.filters │ ├── snippets-16.vcxproj │ ├── snippets-16.vcxproj.filters │ ├── snippets-17.vcxproj │ ├── snippets-17.vcxproj.filters │ ├── snippets-clang.vcxproj │ ├── snippets-clang.vcxproj.filters │ ├── temp-14.vcxproj │ ├── temp-14.vcxproj.filters │ ├── temp-15.vcxproj │ ├── temp-15.vcxproj.filters │ ├── temp-16.vcxproj │ ├── temp-16.vcxproj.filters │ ├── temp-17.vcxproj │ ├── temp-17.vcxproj.filters │ ├── temp-clang.vcxproj │ ├── temp-clang.vcxproj.filters │ ├── test-14.vcxproj │ ├── test-14.vcxproj.filters │ ├── test-15.vcxproj │ ├── test-15.vcxproj.filters │ ├── test-16.vcxproj │ ├── test-16.vcxproj.filters │ ├── test-17.vcxproj │ ├── test-17.vcxproj.filters │ ├── test-clang.vcxproj │ ├── test-clang.vcxproj.filters │ └── tools.pyproj └── visual-studio │ ├── advanced_event_handling-14.vcxproj │ ├── advanced_event_handling-14.vcxproj.filters │ ├── advanced_event_handling-15.vcxproj │ ├── advanced_event_handling-15.vcxproj.filters │ ├── advanced_event_handling-16.vcxproj │ ├── advanced_event_handling-16.vcxproj.filters │ ├── advanced_event_handling-17.vcxproj │ ├── advanced_event_handling-17.vcxproj.filters │ ├── advanced_event_handling-clang.vcxproj │ ├── advanced_event_handling-clang.vcxproj.filters │ ├── basic_audio_player-14.vcxproj │ ├── basic_audio_player-14.vcxproj.filters │ ├── basic_audio_player-15.vcxproj │ ├── basic_audio_player-15.vcxproj.filters │ ├── basic_audio_player-16.vcxproj │ ├── basic_audio_player-16.vcxproj.filters │ ├── basic_audio_player-17.vcxproj │ ├── basic_audio_player-17.vcxproj.filters │ ├── basic_audio_player-clang.vcxproj │ ├── basic_audio_player-clang.vcxproj.filters │ ├── basic_traffic_light-14.vcxproj │ ├── basic_traffic_light-14.vcxproj.filters │ ├── basic_traffic_light-15.vcxproj │ ├── basic_traffic_light-15.vcxproj.filters │ ├── basic_traffic_light-16.vcxproj │ ├── basic_traffic_light-16.vcxproj.filters │ ├── basic_traffic_light-17.vcxproj │ ├── basic_traffic_light-17.vcxproj.filters │ ├── basic_traffic_light-clang.vcxproj │ ├── basic_traffic_light-clang.vcxproj.filters │ ├── calculator-14.vcxproj │ ├── calculator-14.vcxproj.filters │ ├── calculator-15.vcxproj │ ├── calculator-15.vcxproj.filters │ ├── calculator-16.vcxproj │ ├── calculator-16.vcxproj.filters │ ├── calculator-17.vcxproj │ ├── calculator-17.vcxproj.filters │ ├── calculator-clang.vcxproj │ ├── calculator-clang.vcxproj.filters │ ├── debug_logger_interface-14.vcxproj │ ├── debug_logger_interface-14.vcxproj.filters │ ├── debug_logger_interface-15.vcxproj │ ├── debug_logger_interface-15.vcxproj.filters │ ├── debug_logger_interface-16.vcxproj │ ├── debug_logger_interface-16.vcxproj.filters │ ├── debug_logger_interface-17.vcxproj │ ├── debug_logger_interface-17.vcxproj.filters │ ├── debug_logger_interface-clang.vcxproj │ ├── debug_logger_interface-clang.vcxproj.filters │ ├── doctest.props │ ├── hfsm2-all.sln │ ├── hfsm2-lite.sln │ ├── hfsm2-vs.sln │ ├── shared-clang-debug.props │ ├── shared-clang-release.props │ ├── shared-clang.props │ ├── shared-vs-14.props │ ├── shared-vs-15.props │ ├── shared-vs.props │ ├── temp-14.vcxproj │ ├── temp-14.vcxproj.filters │ ├── temp-15.vcxproj │ ├── temp-15.vcxproj.filters │ ├── temp-16.vcxproj │ ├── temp-16.vcxproj.filters │ ├── temp-17.vcxproj │ ├── temp-17.vcxproj.filters │ ├── temp-clang.vcxproj │ ├── temp-clang.vcxproj.filters │ ├── test-14.vcxproj │ ├── test-14.vcxproj.filters │ ├── test-15.vcxproj │ ├── test-15.vcxproj.filters │ ├── test-16.vcxproj │ ├── test-16.vcxproj.filters │ ├── test-17.vcxproj │ ├── test-17.vcxproj.filters │ ├── test-clang.vcxproj │ ├── test-clang.vcxproj.filters │ ├── tools.pyproj │ └── vs-flags.txt ├── test ├── main.cpp ├── reported │ ├── issue_49.cpp │ └── resuming_plan.cpp ├── shared │ ├── test_bit_array.cpp │ ├── test_bit_stream.cpp │ ├── test_random.cpp │ └── test_task_list.cpp ├── test_access.cpp ├── test_ancestors.cpp ├── test_composite_bst.cpp ├── test_contexts.cpp ├── test_contexts_random.cpp ├── test_debug.cpp ├── test_delayed_teardown.cpp ├── test_guards.cpp ├── test_internal_payloads.cpp ├── test_internal_transitions.cpp ├── test_manual_activation.cpp ├── test_ortho_units.cpp ├── test_orthogonal_root.cpp ├── test_plan_external.cpp ├── test_plan_external_payloads.cpp ├── test_plan_hierarchy.cpp ├── test_plans.cpp ├── test_plans_payloads.cpp ├── test_query.cpp ├── test_randomize.cpp ├── test_react_order.cpp ├── test_replication.cpp ├── test_resume.cpp ├── test_select.cpp ├── test_self_transitions.cpp ├── test_serialization.cpp ├── test_stress.cpp ├── test_types.cpp ├── test_utility_regions.cpp ├── test_utilize.cpp ├── tools.hpp ├── tools.inl ├── wiki_class_member.cpp ├── wiki_class_member.hpp ├── wiki_plans.cpp ├── wiki_serialization.cpp ├── wiki_transitions_within_hierarchy.cpp └── wiki_tutorial.cpp └── tools └── join.py /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | insert_final_newline = true 7 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: andrew-gresyk 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/cmake-qemu-arm.yml: -------------------------------------------------------------------------------- 1 | name: CMake QEMU ARM 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | env: 14 | CC: arm-linux-gnueabihf-gcc 15 | CXX: arm-linux-gnueabihf-g++ 16 | AR: arm-linux-gnueabihf-ar 17 | LD: arm-linux-gnueabihf-ld 18 | LDFLAGS: -L/usr/arm-linux-gnueabihf/lib 19 | CMAKE_CROSSCOMPILING: True 20 | QEMU_LD_PREFIX: /usr/arm-linux-gnueabihf 21 | CMAKE_CROSSCOMPILING_EMULATOR: qemu-arm 22 | 23 | strategy: 24 | matrix: 25 | BUILD_CONFIG: [ Release, Debug ] 26 | 27 | steps: 28 | - uses: actions/checkout@v4 29 | 30 | - name: Install ARM GCC on ubuntu 31 | run: | 32 | sudo apt-get update 33 | sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf qemu-user 34 | 35 | - name: Configure 36 | run: cmake -B ./build -DHFSM2_BUILD_TESTS=ON -DHFSM2_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=${{ matrix.BUILD_CONFIG }} 37 | working-directory: ${{ github.workspace }} 38 | 39 | - name: Build 40 | run: cmake --build ./build --config ${{ matrix.BUILD_CONFIG }} 41 | working-directory: ${{ github.workspace }} 42 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.PLATFORM.OS }} 12 | 13 | env: 14 | CC: ${{ matrix.PLATFORM.CC }} 15 | CXX: ${{ matrix.PLATFORM.CXX }} 16 | 17 | strategy: 18 | matrix: 19 | PLATFORM: 20 | - { 21 | OS: ubuntu-22.04, 22 | CC: gcc-9, 23 | CXX: g++-9 24 | } 25 | - { 26 | OS: ubuntu-22.04, 27 | CC: gcc-10, 28 | CXX: g++-10 29 | } 30 | - { 31 | OS: ubuntu-22.04, 32 | CC: gcc-11, 33 | CXX: g++-11 34 | } 35 | - { 36 | OS: ubuntu-22.04, 37 | CC: gcc-12, 38 | CXX: g++-12 39 | } 40 | - { 41 | OS: ubuntu-24.04, 42 | CC: gcc-13, 43 | CXX: g++-13 44 | } 45 | - { 46 | OS: ubuntu-24.04, 47 | CC: gcc-14, 48 | CXX: g++-14 49 | } 50 | - { 51 | OS: ubuntu-22.04, 52 | CC: clang-13, 53 | CXX: clang++-13 54 | } 55 | - { 56 | OS: ubuntu-22.04, 57 | CC: clang-14, 58 | CXX: clang++-14 59 | } 60 | - { 61 | OS: ubuntu-22.04, 62 | CC: clang-15, 63 | CXX: clang++-15, 64 | VERSION: '15' 65 | } 66 | - { 67 | OS: ubuntu-24.04, 68 | CC: clang-16, 69 | CXX: clang++-16, 70 | VERSION: '16' 71 | } 72 | - { 73 | OS: ubuntu-24.04, 74 | CC: clang-17, 75 | CXX: clang++-17, 76 | VERSION: '17' 77 | } 78 | - { 79 | OS: ubuntu-24.04, 80 | CC: clang-18, 81 | CXX: clang++-18, 82 | VERSION: '18' 83 | } 84 | - { 85 | OS: macos-13, 86 | CC: clang, 87 | CXX: clang++ 88 | } 89 | - { 90 | OS: macos-14, 91 | CC: clang, 92 | CXX: clang++ 93 | } 94 | - { 95 | OS: macos-15, 96 | CC: clang, 97 | CXX: clang++ 98 | } 99 | 100 | BUILD_CONFIG: [ Release, Debug ] 101 | 102 | steps: 103 | - uses: actions/checkout@v4 104 | 105 | - name: Install GCC on ubuntu 106 | if: | 107 | startsWith(matrix.PLATFORM.OS, 'ubuntu-') && 108 | startsWith(matrix.PLATFORM.CC, 'gcc-') && 109 | matrix.PLATFORM.INSTALL 110 | run: | 111 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test 112 | sudo apt-get update 113 | sudo apt-get install ${{ matrix.PLATFORM.CC }} ${{ matrix.PLATFORM.CXX }} 114 | 115 | - name: Install Clang on ubuntu 116 | if: | 117 | startsWith(matrix.PLATFORM.OS, 'ubuntu-') && 118 | startsWith(matrix.PLATFORM.CC, 'clang-') && 119 | matrix.PLATFORM.VERSION 120 | uses: egor-tensin/setup-clang@v1 121 | with: 122 | version: ${{ matrix.PLATFORM.VERSION }} 123 | 124 | - name: Configure 125 | run: cmake -B ./build -DHFSM2_BUILD_TESTS=ON -DHFSM2_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=${{ matrix.BUILD_CONFIG }} 126 | working-directory: ${{ github.workspace }} 127 | 128 | - name: Build 129 | run: cmake --build ./build --config ${{ matrix.BUILD_CONFIG }} 130 | working-directory: ${{ github.workspace }} 131 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '33 17 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp', 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | 54 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 55 | # queries: security-extended,security-and-quality 56 | 57 | 58 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 59 | # If this step fails, then you should remove it and run the build manually (see below) 60 | #- name: Autobuild 61 | # uses: github/codeql-action/autobuild@v3 62 | 63 | # Custom build 64 | - name: Configure 65 | run: cmake -B ./build -DHFSM2_BUILD_TESTS=ON -DHFSM2_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=Debug 66 | working-directory: ${{ github.workspace }} 67 | 68 | - name: Build 69 | run: cmake --build ./build --config Debug 70 | working-directory: ${{ github.workspace }} 71 | 72 | # ℹ️ Command-line programs to run using the OS shell. 73 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 74 | 75 | # If the Autobuild fails above, remove it and uncomment the following three lines. 76 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 77 | 78 | # - run: | 79 | # echo "Run, Build Application using script" 80 | # ./location_of_script_within_repo/buildscript.sh 81 | 82 | - name: Perform CodeQL Analysis 83 | uses: github/codeql-action/analyze@v3 84 | with: 85 | category: "/language:${{matrix.language}}" 86 | -------------------------------------------------------------------------------- /.github/workflows/flawfinder-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: flawfinder 7 | 8 | on: 9 | push: 10 | branches: [ master ] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [ master ] 14 | schedule: 15 | - cron: '21 21 * * 6' 16 | 17 | jobs: 18 | flawfinder: 19 | name: Flawfinder 20 | runs-on: ubuntu-latest 21 | permissions: 22 | actions: read 23 | contents: read 24 | security-events: write 25 | steps: 26 | - name: Checkout code 27 | uses: actions/checkout@v4 28 | 29 | - name: flawfinder_scan 30 | uses: david-a-wheeler/flawfinder@c57197cd6061453f10a496f30a732bc1905918d1 31 | with: 32 | arguments: '--sarif ./' 33 | output: 'flawfinder_results.sarif' 34 | 35 | - name: Upload analysis results to GitHub Security tab 36 | uses: github/codeql-action/upload-sarif@v3 37 | with: 38 | sarif_file: ${{github.workspace}}/flawfinder_results.sarif 39 | -------------------------------------------------------------------------------- /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: MSBuild 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.PLATFORM.OS }} 12 | 13 | env: 14 | SOLUTION_FILE_PATH: ${{ matrix.PLATFORM.SOLUTION_FILE_PATH }} 15 | PROJECT_FILE_NAME: ${{ matrix.PLATFORM.PROJECT_FILE_NAME }} 16 | 17 | strategy: 18 | matrix: 19 | PLATFORM: 20 | - { 21 | OS: windows-2019, 22 | SOLUTION_FILE_PATH: projects\premake\hfsm2-vs-2019.sln, 23 | PROJECT_FILE_NAME: test-15 24 | } 25 | - { 26 | OS: windows-2022, 27 | SOLUTION_FILE_PATH: projects\premake\hfsm2-vs-2022.sln, 28 | PROJECT_FILE_NAME: test-17 29 | } 30 | 31 | BUILD_CONFIG: [ Release, Debug ] 32 | BUILD_PLATFORM: [ Win32, x64 ] 33 | 34 | steps: 35 | - uses: actions/checkout@v4 36 | 37 | - name: Add MSBuild to PATH 38 | uses: microsoft/setup-msbuild@main 39 | 40 | - name: Build 41 | working-directory: ${{env.GITHUB_WORKSPACE}} 42 | run: msbuild /m /p:Configuration=${{matrix.BUILD_CONFIG}} /p:Platform=${{matrix.BUILD_PLATFORM}} ${{env.SOLUTION_FILE_PATH}} 43 | 44 | - name: Test 45 | working-directory: ${{env.GITHUB_WORKSPACE}} 46 | run: "binaries/${{env.PROJECT_FILE_NAME}}-${{matrix.BUILD_CONFIG}}-${{matrix.BUILD_PLATFORM}}.exe" 47 | -------------------------------------------------------------------------------- /.github/workflows/msvc-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # 6 | # Find more information at: 7 | # https://github.com/microsoft/msvc-code-analysis-action 8 | 9 | name: Microsoft C++ Code Analysis 10 | 11 | on: 12 | push: 13 | branches: [ master ] 14 | pull_request: 15 | branches: [ master ] 16 | schedule: 17 | - cron: '22 3 * * 3' 18 | 19 | env: 20 | # Path to the CMake build directory. 21 | build: '${{ github.workspace }}/build' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: windows-latest 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v4 31 | 32 | - name: Configure CMake 33 | run: cmake -B ${{ env.build }} 34 | 35 | # Build is not required unless generated source files are used 36 | # - name: Build CMake 37 | # run: cmake --build ${{ env.build }} 38 | 39 | - name: Initialize MSVC Code Analysis 40 | uses: microsoft/msvc-code-analysis-action@24c285ab36952c9e9182f4b78dfafbac38a7e5ee 41 | # Provide a unique ID to access the sarif output path 42 | id: run-analysis 43 | with: 44 | cmakeBuildDirectory: ${{ env.build }} 45 | # Ruleset file that will determine what checks will be run 46 | ruleset: NativeRecommendedRules.ruleset 47 | 48 | # Upload SARIF file to GitHub Code Scanning Alerts 49 | - name: Upload SARIF to GitHub 50 | uses: github/codeql-action/upload-sarif@v3 51 | with: 52 | sarif_file: ${{ steps.run-analysis.outputs.sarif }} 53 | 54 | # Upload SARIF file as an Artifact to download and view 55 | # - name: Upload SARIF as an Artifact 56 | # uses: actions/upload-artifact@v2 57 | # with: 58 | # name: sarif-file 59 | # path: ${{ steps.run-analysis.outputs.sarif }} 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .codelite 3 | .idea 4 | .vs 5 | .vscode 6 | build 7 | cmake-* 8 | 9 | *.user 10 | 11 | /binaries* 12 | /build* 13 | /hfsm_test.dir 14 | /projects/code-lite/build-* 15 | /projects/code-lite/compile_commands.json 16 | /projects/code-lite/tags 17 | /projects/code-lite/Makefile 18 | /projects/code-lite/test/compile_flags.txt 19 | /projects/code-lite/test/test.mk 20 | /projects/visual-studio/.opencppcov 21 | /projects/visual-studio/*.log 22 | /pull.cmd 23 | /push.cmd 24 | -------------------------------------------------------------------------------- /CMake/modules/coverage.cmake: -------------------------------------------------------------------------------- 1 | if (BUILD_COVERAGE) 2 | set(CMAKE_BUILD_TYPE "Debug") 3 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 4 | find_program(GCOV_PATH gcov) 5 | find_program(GENHTML_PATH genhtml) 6 | find_program(LCOV_PATH lcov) 7 | 8 | if(NOT LCOV_PATH) 9 | message(FATAL_ERROR "lcov not found.") 10 | endif(NOT LCOV_PATH) 11 | 12 | if(NOT GCOV_PATH) 13 | message(FATAL_ERROR "gcov not found.") 14 | endif(NOT GCOV_PATH) 15 | 16 | if(NOT GENHTML_PATH) 17 | message(FATAL_ERROR "GENHTML not found.") 18 | endif(NOT GENHTML_PATH) 19 | 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage -U_FORTIFY_SOURCE") 21 | 22 | add_custom_target(coverage ALL 23 | COMMAND ${LCOV_PATH} -z -d ${CMAKE_CURRENT_BINARY_DIR} 24 | COMMAND ${LCOV_PATH} --no-external -c -i -d ${CMAKE_SOURCE_DIR} -o ${TEST_PROJECT}_base.info 25 | COMMAND ${TEST_PROJECT} 26 | COMMAND ${LCOV_PATH} --no-external -c -d ${CMAKE_SOURCE_DIR} -o ${TEST_PROJECT}_test.info 27 | COMMAND ${LCOV_PATH} -a ${TEST_PROJECT}_base.info -a ${TEST_PROJECT}_test.info -o ${TEST_PROJECT}_total.info 28 | COMMAND ${LCOV_PATH} --remove ${TEST_PROJECT}_total.info '${PROJECT_BINARY_DIR}/*' -o ${TEST_PROJECT}.profdata 29 | COMMAND ${GENHTML_PATH} -o ${TEST_PROJECT}-coverage ${TEST_PROJECT}.profdata 30 | DEPENDS ${TEST_PROJECT} 31 | BYPRODUCTS ${TEST_PROJECT}_base.info ${TEST_PROJECT}_test.info ${TEST_PROJECT}_total.info ${TEST_PROJECT}.profdata 32 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 33 | ) 34 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 35 | find_program(LCOV_PATH llvm-cov) 36 | 37 | if(NOT LCOV_PATH) 38 | message(FATAL_ERROR "llvm-cov not found.") 39 | endif(NOT LCOV_PATH) 40 | 41 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-instr-generate -fcoverage-mapping") 42 | 43 | file (GLOB SOURCES "${PROJECT_SOURCE_DIR}/*.hpp" 44 | "${PROJECT_SOURCE_DIR}/*.cpp" 45 | "${PROJECT_SOURCE_DIR}/test/*.hpp" 46 | "${PROJECT_SOURCE_DIR}/test/*.cpp" 47 | ) 48 | 49 | # llvm-cov 50 | add_custom_target(${TEST_PROJECT}-ccov-preprocessing 51 | COMMAND LLVM_PROFILE_FILE=${TEST_PROJECT}.profraw $ 52 | COMMAND llvm-profdata merge -sparse ${TEST_PROJECT}.profraw -o ${TEST_PROJECT}.profdata 53 | DEPENDS ${TEST_PROJECT} 54 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 55 | 56 | add_custom_target(${TEST_PROJECT}-ccov-show 57 | COMMAND llvm-cov show $ -instr-profile=${TEST_PROJECT}.profdata -show-line-counts-or-regions 58 | DEPENDS ${TEST_PROJECT}-ccov-preprocessing 59 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 60 | 61 | add_custom_target(${TEST_PROJECT}-ccov-report 62 | COMMAND llvm-cov report $ -instr-profile=${TEST_PROJECT}.profdata ${SOURCES} 63 | DEPENDS ${TEST_PROJECT}-ccov-preprocessing 64 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 65 | 66 | add_custom_target(coverage ALL 67 | COMMAND llvm-cov show $ -instr-profile=${TEST_PROJECT}.profdata -show-line-counts-or-regions -output-dir=${CMAKE_CURRENT_BINARY_DIR}/${TEST_PROJECT}-coverage -format="html" 68 | DEPENDS ${TEST_PROJECT}-ccov-report 69 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 70 | endif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 71 | endif(BUILD_COVERAGE) 72 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(hfsm2 VERSION 2.7.0 LANGUAGES CXX) 4 | 5 | # Create an interface library (header-only) 6 | add_library(${PROJECT_NAME} INTERFACE) 7 | add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) 8 | 9 | # Set include directories for users of this library 10 | target_include_directories(${PROJECT_NAME} 11 | INTERFACE 12 | $ 13 | $ 14 | ) 15 | 16 | # Set C++11 requirement for users of this library 17 | target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_11) 18 | 19 | # Install the library 20 | install(TARGETS ${PROJECT_NAME} 21 | EXPORT ${PROJECT_NAME}Targets 22 | INCLUDES DESTINATION include 23 | ) 24 | 25 | # Install the headers 26 | install(DIRECTORY include/ DESTINATION include) 27 | 28 | # Export the targets 29 | export(EXPORT ${PROJECT_NAME}Targets 30 | FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake" 31 | NAMESPACE ${PROJECT_NAME}:: 32 | ) 33 | 34 | # Create and install package configuration files 35 | include(CMakePackageConfigHelpers) 36 | write_basic_package_version_file( 37 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" 38 | VERSION ${PROJECT_VERSION} 39 | COMPATIBILITY SameMajorVersion 40 | ) 41 | 42 | # Simple config file approach (no template required) 43 | file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 44 | "include(CMakeFindDependencyMacro) 45 | include(\"\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}Targets.cmake\") 46 | ") 47 | 48 | # Install the configuration files 49 | install(FILES 50 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 51 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" 52 | DESTINATION lib/cmake/${PROJECT_NAME} 53 | ) 54 | 55 | install(EXPORT ${PROJECT_NAME}Targets 56 | FILE ${PROJECT_NAME}Targets.cmake 57 | NAMESPACE ${PROJECT_NAME}:: 58 | DESTINATION lib/cmake/${PROJECT_NAME} 59 | ) 60 | 61 | # Testing section 62 | option(HFSM2_BUILD_TESTS "Build the HFSM2 tests" OFF) 63 | if(HFSM2_BUILD_TESTS) 64 | enable_testing() 65 | 66 | file(GLOB TEST_SOURCE_FILES 67 | "${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp" 68 | "${CMAKE_CURRENT_SOURCE_DIR}/test/*/*.cpp") 69 | add_executable(${PROJECT_NAME}_test ${TEST_SOURCE_FILES}) 70 | 71 | target_include_directories(${PROJECT_NAME}_test PRIVATE 72 | "${CMAKE_CURRENT_SOURCE_DIR}/external" 73 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 74 | 75 | target_compile_features(${PROJECT_NAME}_test PRIVATE cxx_std_11) 76 | 77 | if(MSVC) 78 | target_compile_options(${PROJECT_NAME}_test PRIVATE /W4 /WX) 79 | else() 80 | target_compile_options(${PROJECT_NAME}_test PRIVATE -Werror -Wall -Wextra -Wpedantic -Wshadow -Wold-style-cast) 81 | endif() 82 | 83 | add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test) 84 | 85 | add_custom_command(TARGET ${PROJECT_NAME}_test 86 | POST_BUILD 87 | COMMAND ${PROJECT_NAME}_test) 88 | endif() 89 | 90 | # Examples section 91 | option(HFSM2_BUILD_EXAMPLES "Build the examples" OFF) 92 | if(HFSM2_BUILD_EXAMPLES) 93 | # Check if examples directory exists 94 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples") 95 | # Get all subdirectories in examples folder 96 | file(GLOB EXAMPLE_DIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/examples" "${CMAKE_CURRENT_SOURCE_DIR}/examples/*") 97 | 98 | foreach(EXAMPLE_DIR ${EXAMPLE_DIRS}) 99 | # Check if the subdirectory contains a CMakeLists.txt 100 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/${EXAMPLE_DIR}/CMakeLists.txt") 101 | message(STATUS "Adding example: ${EXAMPLE_DIR}") 102 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/examples/${EXAMPLE_DIR}") 103 | endif() 104 | endforeach() 105 | else() 106 | message(STATUS "Examples directory not found, skipping examples") 107 | endif() 108 | endif() -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 6, 3 | "configurePresets": [ 4 | { 5 | "name": "debug", 6 | "displayName": "Debug", 7 | "generator": "Ninja", 8 | "cacheVariables": { 9 | "CMAKE_BUILD_TYPE": "Debug", 10 | "HFSM2_BUILD_TESTS": "ON", 11 | "HFSM2_BUILD_EXAMPLES": "ON" 12 | } 13 | }, 14 | { 15 | "name": "release", 16 | "displayName": "Release", 17 | "generator": "Ninja", 18 | "cacheVariables": { 19 | "CMAKE_BUILD_TYPE": "Release" 20 | } 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | hfsm.dev -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Andrew Gresyk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: HFSM2 2 | description: High-Performance Hierarchical Finite State Machine Framework 3 | url: "http://hfsm.dev" 4 | twitter_username: andrew_gresyk 5 | github_username: andrew-gresyk 6 | google_analytics: G-8CBZLEMT7W 7 | 8 | theme: jekyll-theme-minimal # https://github.com/pages-themes/minimal / https://pages.github.com/themes/ 9 | logo: assets/logos/hfsm2-logo-jekyll.png 10 | -------------------------------------------------------------------------------- /assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | 6 | a:link, a:visited { 7 | color: #0057b7; 8 | font-weight: bold; 9 | text-decoration: none; 10 | } 11 | a:hover, a:active { 12 | background-color: #ffd700; 13 | color: #0057b7; 14 | font-weight: bold; 15 | text-decoration: none; 16 | } 17 | -------------------------------------------------------------------------------- /assets/logos/hfsm2-logo-jekyll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrew-gresyk/HFSM2/1004a814fcd73673d9ed9528867b7a7cc908ba1a/assets/logos/hfsm2-logo-jekyll.png -------------------------------------------------------------------------------- /assets/logos/hfsm2-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrew-gresyk/HFSM2/1004a814fcd73673d9ed9528867b7a7cc908ba1a/assets/logos/hfsm2-logo-large.png -------------------------------------------------------------------------------- /development/hfsm2/detail/containers/array.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | template 8 | HFSM2_CONSTEXPR(14) 9 | T& 10 | StaticArrayT::operator[] (const N index) noexcept { 11 | HFSM2_ASSERT(0 <= index && index < CAPACITY); 12 | 13 | return _items[static_cast(index)]; 14 | } 15 | 16 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 17 | 18 | template 19 | template 20 | HFSM2_CONSTEXPR(14) 21 | const T& 22 | StaticArrayT::operator[] (const N index) const noexcept { 23 | HFSM2_ASSERT(0 <= index && index < CAPACITY); 24 | 25 | return _items[static_cast(index)]; 26 | } 27 | 28 | //------------------------------------------------------------------------------ 29 | 30 | template 31 | HFSM2_CONSTEXPR(14) 32 | void 33 | StaticArrayT::fill(const Item filler) noexcept { 34 | for (Item& item : _items) 35 | item = filler; 36 | } 37 | 38 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 39 | 40 | template 41 | HFSM2_CONSTEXPR(14) 42 | bool 43 | StaticArrayT::empty() const noexcept { 44 | for (const Item& item : _items) 45 | if (item != filler()) 46 | return false; 47 | 48 | return true; 49 | } 50 | 51 | //////////////////////////////////////////////////////////////////////////////// 52 | 53 | template 54 | template 55 | HFSM2_CONSTEXPR(14) 56 | typename DynamicArrayT::Index 57 | DynamicArrayT::emplace(const TArgs&... args) noexcept { 58 | HFSM2_ASSERT(_count < CAPACITY); 59 | 60 | new (&_items[_count]) Item{args...}; 61 | 62 | return _count++; 63 | } 64 | 65 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 66 | 67 | template 68 | template 69 | HFSM2_CONSTEXPR(14) 70 | typename DynamicArrayT::Index 71 | DynamicArrayT::emplace(TArgs&&... args) noexcept { 72 | HFSM2_ASSERT(_count < CAPACITY); 73 | 74 | new (&_items[_count]) Item{::hfsm2::forward(args)...}; 75 | 76 | return _count++; 77 | } 78 | 79 | //------------------------------------------------------------------------------ 80 | 81 | template 82 | template 83 | HFSM2_CONSTEXPR(14) 84 | typename DynamicArrayT::Item& 85 | DynamicArrayT::operator[] (const N index) noexcept { 86 | HFSM2_ASSERT(0 <= index && index < _count); 87 | 88 | return _items[static_cast(index)]; 89 | } 90 | 91 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 92 | 93 | template 94 | template 95 | HFSM2_CONSTEXPR(14) 96 | const typename DynamicArrayT::Item& 97 | DynamicArrayT::operator[] (const N index) const noexcept { 98 | HFSM2_ASSERT(0 <= index && index < _count); 99 | 100 | return _items[static_cast(index)]; 101 | } 102 | 103 | //------------------------------------------------------------------------------ 104 | // SPECIFIC 105 | // SPECIFIC 106 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 107 | 108 | template 109 | template 110 | HFSM2_CONSTEXPR(14) 111 | DynamicArrayT& 112 | DynamicArrayT::operator += (const DynamicArrayT& other) noexcept { 113 | for (const auto& item : other) 114 | emplace(item); 115 | 116 | return *this; 117 | } 118 | 119 | //////////////////////////////////////////////////////////////////////////////// 120 | 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /development/hfsm2/detail/containers/bit_array.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | struct Units final { 7 | HFSM2_CONSTEXPR(11) Units(Short unit_ = INVALID_SHORT, 8 | Short width_ = INVALID_SHORT) noexcept 9 | : unit {unit_ } 10 | , width{width_} 11 | {} 12 | 13 | Short unit; 14 | Short width; 15 | }; 16 | 17 | //------------------------------------------------------------------------------ 18 | 19 | template 20 | class BitArrayT final { 21 | public: 22 | using Index = UCapacity; 23 | 24 | static constexpr Index CAPACITY = NCapacity; 25 | static constexpr Index UNIT_COUNT = contain(CAPACITY, 8); 26 | 27 | using BitArray = BitArrayT; 28 | 29 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 30 | 31 | class Bits { 32 | template 33 | friend class BitArrayT; 34 | 35 | private: 36 | HFSM2_CONSTEXPR(11) explicit Bits(uint8_t* const storage, 37 | const Index width) noexcept 38 | : _storage{storage} 39 | , _width{width} 40 | {} 41 | 42 | public: 43 | HFSM2_CONSTEXPR(14) explicit operator bool() const noexcept; 44 | 45 | HFSM2_CONSTEXPR(14) void clear() noexcept; 46 | 47 | template 48 | HFSM2_CONSTEXPR(14) bool get() const noexcept; 49 | 50 | template 51 | HFSM2_CONSTEXPR(14) void set() noexcept; 52 | 53 | template 54 | HFSM2_CONSTEXPR(14) void clear() noexcept; 55 | 56 | HFSM2_CONSTEXPR(14) bool get (const Index index) const noexcept; 57 | HFSM2_CONSTEXPR(14) void set (const Index index) noexcept; 58 | HFSM2_CONSTEXPR(14) void clear(const Index index) noexcept; 59 | 60 | private: 61 | uint8_t* const _storage; 62 | const Index _width; 63 | }; 64 | 65 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 66 | 67 | class CBits { 68 | template 69 | friend class BitArrayT; 70 | 71 | private: 72 | HFSM2_CONSTEXPR(11) explicit CBits(const uint8_t* const storage, 73 | const Index width) noexcept 74 | : _storage{storage} 75 | , _width{width} 76 | {} 77 | 78 | public: 79 | HFSM2_CONSTEXPR(14) explicit operator bool() const noexcept; 80 | 81 | template 82 | HFSM2_CONSTEXPR(14) bool get() const noexcept; 83 | 84 | HFSM2_CONSTEXPR(14) bool get(const Index index) const noexcept; 85 | 86 | private: 87 | const uint8_t* const _storage; 88 | const Index _width; 89 | }; 90 | 91 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 92 | 93 | public: 94 | HFSM2_CONSTEXPR(14) BitArrayT() noexcept { clear(); } 95 | 96 | HFSM2_CONSTEXPR(14) void set() noexcept; 97 | 98 | HFSM2_CONSTEXPR(14) void clear() noexcept; 99 | 100 | template 101 | HFSM2_CONSTEXPR(14) bool get() const noexcept; 102 | 103 | template 104 | HFSM2_CONSTEXPR(14) void set() noexcept; 105 | 106 | template 107 | HFSM2_CONSTEXPR(14) void clear() noexcept; 108 | 109 | HFSM2_CONSTEXPR(14) bool empty() const noexcept; 110 | 111 | template 112 | HFSM2_CONSTEXPR(14) bool get (const TIndex index) const noexcept; 113 | 114 | template 115 | HFSM2_CONSTEXPR(14) void set (const TIndex index) noexcept; 116 | 117 | template 118 | HFSM2_CONSTEXPR(14) void clear(const TIndex index) noexcept; 119 | 120 | HFSM2_CONSTEXPR(14) bool operator & (const BitArray& other) const noexcept; 121 | 122 | HFSM2_CONSTEXPR(14) void operator &= (const BitArray& other) noexcept; 123 | 124 | template 125 | HFSM2_CONSTEXPR(14) Bits bits() noexcept; 126 | 127 | template 128 | HFSM2_CONSTEXPR(14) CBits cbits() const noexcept; 129 | 130 | HFSM2_CONSTEXPR(14) Bits bits(const Units& units) noexcept; 131 | HFSM2_CONSTEXPR(14) CBits cbits(const Units& units) const noexcept; 132 | 133 | private: 134 | uint8_t _storage[UNIT_COUNT] {}; 135 | }; 136 | 137 | //------------------------------------------------------------------------------ 138 | 139 | template <> 140 | class BitArrayT<0> final { 141 | public: 142 | HFSM2_CONSTEXPR(14) void clear() noexcept {} 143 | 144 | HFSM2_CONSTEXPR(11) bool empty() const noexcept { return true; } 145 | }; 146 | 147 | //////////////////////////////////////////////////////////////////////////////// 148 | 149 | } 150 | } 151 | 152 | #include "bit_array.inl" 153 | -------------------------------------------------------------------------------- /development/hfsm2/detail/features/logger_interface.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | 3 | //------------------------------------------------------------------------------ 4 | 5 | struct HFSM2_EMPTY_BASES EmptyContext {}; 6 | 7 | #if HFSM2_LOG_INTERFACE_AVAILABLE() 8 | 9 | //////////////////////////////////////////////////////////////////////////////// 10 | 11 | template < 12 | FeatureTag NFeatureTag = HFSM2_FEATURE_TAG 13 | , typename TContext = EmptyContext 14 | HFSM2_IF_UTILITY_THEORY(, typename TUtilty = float) 15 | > 16 | struct LoggerInterfaceT { 17 | using Context = TContext; 18 | 19 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 20 | using Utilty = TUtilty; 21 | #endif 22 | 23 | using Method = ::hfsm2::Method; 24 | using Prong = ::hfsm2::Prong; 25 | using StateID = ::hfsm2::StateID; 26 | using TransitionType = ::hfsm2::TransitionType; 27 | 28 | #if HFSM2_PLANS_AVAILABLE() 29 | using StatusEvent = ::hfsm2::StatusEvent; 30 | #endif 31 | 32 | HFSM2_CONSTEXPR(NO) 33 | virtual 34 | void 35 | recordMethod(const Context& HFSM2_UNUSED(context), 36 | const StateID HFSM2_UNUSED(origin), 37 | const Method HFSM2_UNUSED(method)) 38 | {} 39 | 40 | HFSM2_CONSTEXPR(NO) 41 | virtual 42 | void 43 | recordTransition(const Context& HFSM2_UNUSED(context), 44 | const StateID HFSM2_UNUSED(origin), 45 | const TransitionType HFSM2_UNUSED(transitionType), 46 | const StateID HFSM2_UNUSED(target)) 47 | {} 48 | 49 | #if HFSM2_PLANS_AVAILABLE() 50 | 51 | HFSM2_CONSTEXPR(NO) 52 | virtual 53 | void 54 | recordTaskStatus(const Context& HFSM2_UNUSED(context), 55 | const StateID HFSM2_UNUSED(region), 56 | const StateID HFSM2_UNUSED(origin), 57 | const StatusEvent HFSM2_UNUSED(event)) 58 | {} 59 | 60 | HFSM2_CONSTEXPR(NO) 61 | virtual 62 | void 63 | recordPlanStatus(const Context& HFSM2_UNUSED(context), 64 | const StateID HFSM2_UNUSED(region), 65 | const StatusEvent HFSM2_UNUSED(event)) 66 | {} 67 | 68 | #endif 69 | 70 | HFSM2_CONSTEXPR(NO) 71 | virtual 72 | void 73 | recordCancelledPending(const Context& HFSM2_UNUSED(context), 74 | const StateID HFSM2_UNUSED(origin)) 75 | {} 76 | 77 | HFSM2_CONSTEXPR(NO) 78 | virtual 79 | void 80 | recordSelectResolution(const Context& HFSM2_UNUSED(context), 81 | const StateID HFSM2_UNUSED(head), 82 | const Prong HFSM2_UNUSED(prong)) 83 | {} 84 | 85 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 86 | 87 | HFSM2_CONSTEXPR(NO) 88 | virtual 89 | void 90 | recordUtilityResolution(const Context& HFSM2_UNUSED(context), 91 | const StateID HFSM2_UNUSED(head), 92 | const Prong HFSM2_UNUSED(prong), 93 | const Utilty HFSM2_UNUSED(utilty)) 94 | {} 95 | 96 | HFSM2_CONSTEXPR(NO) 97 | virtual 98 | void 99 | recordRandomResolution(const Context& HFSM2_UNUSED(context), 100 | const StateID HFSM2_UNUSED(head), 101 | const Prong HFSM2_UNUSED(prong), 102 | const Utilty HFSM2_UNUSED(utilty)) 103 | {} 104 | 105 | #endif 106 | }; 107 | 108 | //////////////////////////////////////////////////////////////////////////////// 109 | 110 | #else 111 | 112 | template < 113 | FeatureTag NFeatureTag = HFSM2_FEATURE_TAG 114 | , typename TContext = EmptyContext 115 | HFSM2_IF_UTILITY_THEORY(, typename TUtilty = float) 116 | > 117 | using LoggerInterfaceT = void; 118 | 119 | #endif 120 | 121 | using LoggerInterface = LoggerInterfaceT<>; 122 | 123 | } 124 | -------------------------------------------------------------------------------- /development/hfsm2/detail/features/structure_report.hpp: -------------------------------------------------------------------------------- 1 | #if HFSM2_STRUCTURE_REPORT_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | 5 | //------------------------------------------------------------------------------ 6 | 7 | struct StructureEntry final { 8 | bool isActive; 9 | const wchar_t* prefix; 10 | const char* name; 11 | }; 12 | 13 | namespace detail { 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | enum class RegionType { 18 | COMPOSITE, 19 | ORTHOGONAL, 20 | 21 | COUNT 22 | }; 23 | 24 | //------------------------------------------------------------------------------ 25 | 26 | struct StructureStateInfo final { 27 | StructureStateInfo() noexcept = default; 28 | 29 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 30 | 31 | HFSM2_CONSTEXPR(11) 32 | StructureStateInfo(const Long parent_, 33 | const RegionType regionType_, 34 | const Short depth_, 35 | const char* const name_) noexcept 36 | : name{name_} 37 | , parent{parent_} 38 | , regionType{regionType_ } 39 | , depth{depth_} 40 | {} 41 | 42 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 43 | 44 | const char* name = nullptr; 45 | Long parent = INVALID_LONG; 46 | RegionType regionType = RegionType::COUNT; 47 | Short depth = INVALID_SHORT; 48 | }; 49 | 50 | //////////////////////////////////////////////////////////////////////////////// 51 | 52 | } 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /development/hfsm2/detail/features/task.hpp: -------------------------------------------------------------------------------- 1 | #if HFSM2_PLANS_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | struct TaskBase { 9 | static_assert(sizeof(Long) == sizeof(StateID), ""); 10 | 11 | HFSM2_CONSTEXPR(11) TaskBase() noexcept {} 12 | 13 | HFSM2_CONSTEXPR(11) TaskBase(const StateID origin_, 14 | const StateID destination_, 15 | const TransitionType type_) noexcept 16 | : origin{origin_} 17 | , destination{destination_} 18 | , type{type_} 19 | {} 20 | 21 | HFSM2_CONSTEXPR(11) bool cyclic() const noexcept { return origin == destination; } 22 | 23 | union { 24 | StateID origin = INVALID_STATE_ID; 25 | Long prev; 26 | }; 27 | 28 | union { 29 | StateID destination = INVALID_STATE_ID; 30 | Long next; 31 | }; 32 | 33 | TransitionType type = TransitionType::COUNT; 34 | }; 35 | 36 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 37 | 38 | HFSM2_CONSTEXPR(11) 39 | bool 40 | operator == (const TaskBase& lhs, 41 | const TaskBase& rhs) noexcept 42 | { 43 | return lhs.origin == rhs.origin && 44 | lhs.destination == rhs.destination && 45 | lhs.type == rhs.type; 46 | } 47 | 48 | //------------------------------------------------------------------------------ 49 | 50 | template 51 | struct TaskT final 52 | : TaskBase 53 | { 54 | using Payload = TPayload; 55 | using Storage = uint8_t[sizeof(Payload)]; 56 | 57 | using TaskBase::TaskBase; 58 | 59 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 60 | 61 | HFSM2_CONSTEXPR(14) TaskT() noexcept { 62 | new (&storage) Payload{}; 63 | } 64 | 65 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 66 | 67 | HFSM2_CONSTEXPR(14) TaskT(const StateID origin_, 68 | const StateID destination_, 69 | const TransitionType type_, 70 | const Payload& payload) noexcept 71 | : TaskBase{origin_, destination_, type_} 72 | , payloadSet{true} 73 | { 74 | new (&storage) Payload{payload}; 75 | } 76 | 77 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 78 | 79 | HFSM2_CONSTEXPR(11) 80 | const Payload* 81 | payload() const noexcept { 82 | return payloadSet ? 83 | reinterpret_cast(&storage) : nullptr; 84 | } 85 | 86 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 87 | 88 | #ifdef _MSC_VER 89 | #pragma warning(push) 90 | #pragma warning(disable: 4324) // structure was padded due to alignment specifier 91 | #endif 92 | 93 | alignas(Payload) Storage storage {}; 94 | 95 | #ifdef _MSC_VER 96 | #pragma warning(pop) 97 | #endif 98 | 99 | bool payloadSet = false; 100 | }; 101 | 102 | //------------------------------------------------------------------------------ 103 | 104 | template <> 105 | struct TaskT final 106 | : TaskBase 107 | { 108 | using TaskBase::TaskBase; 109 | }; 110 | 111 | //////////////////////////////////////////////////////////////////////////////// 112 | 113 | } 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /development/hfsm2/detail/features/task_list.hpp: -------------------------------------------------------------------------------- 1 | #if HFSM2_PLANS_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | template 9 | class TaskListT { 10 | public: 11 | using Index = Long; 12 | 13 | static constexpr Index CAPACITY = NCapacity; 14 | static constexpr Index INVALID = Index (-1); 15 | 16 | private: 17 | using Payload = TPayload; 18 | using Item = TaskT; 19 | 20 | public: 21 | HFSM2_CONSTEXPR(14) void clear() noexcept; 22 | 23 | template 24 | HFSM2_CONSTEXPR(14) Index emplace(TArgs&&... args) noexcept; 25 | 26 | HFSM2_CONSTEXPR(14) void remove(const Index i) noexcept; 27 | 28 | HFSM2_CONSTEXPR(14) Item& operator[] (const Index i) noexcept; 29 | HFSM2_CONSTEXPR(11) const Item& operator[] (const Index i) const noexcept; 30 | 31 | HFSM2_CONSTEXPR(11) Index count() const noexcept { return _count; } 32 | HFSM2_CONSTEXPR(11) bool empty() const noexcept { return _count == 0; } 33 | 34 | private: 35 | HFSM2_IF_ASSERT(void verifyStructure(const Index occupied = INVALID) const noexcept); 36 | 37 | private: 38 | Index _vacantHead = 0; 39 | Index _vacantTail = 0; 40 | Index _last = 0; 41 | Index _count = 0; 42 | Item _items[CAPACITY] {}; 43 | }; 44 | 45 | //------------------------------------------------------------------------------ 46 | 47 | template 48 | class TaskListT {}; 49 | 50 | //////////////////////////////////////////////////////////////////////////////// 51 | 52 | } 53 | } 54 | 55 | #include "task_list.inl" 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /development/hfsm2/detail/features/task_list.inl: -------------------------------------------------------------------------------- 1 | #if HFSM2_PLANS_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | template 9 | HFSM2_CONSTEXPR(14) 10 | void 11 | TaskListT::clear() noexcept { 12 | _vacantHead = 0; 13 | _vacantTail = 0; 14 | _last = 0; 15 | _count = 0; 16 | } 17 | 18 | //------------------------------------------------------------------------------ 19 | 20 | template 21 | template 22 | HFSM2_CONSTEXPR(14) 23 | Long 24 | TaskListT::emplace(TA_&&... args) noexcept { 25 | HFSM2_ASSERT(_last <= CAPACITY); 26 | 27 | if (_count < CAPACITY) { 28 | HFSM2_ASSERT(_vacantHead < CAPACITY); 29 | HFSM2_ASSERT(_vacantTail < CAPACITY); 30 | 31 | const Index index = _vacantHead; 32 | Item& item = _items[index]; 33 | 34 | if (_vacantHead != _vacantTail) { 35 | // recycle 36 | HFSM2_ASSERT(item.prev == INVALID); 37 | HFSM2_ASSERT(item.next != INVALID); 38 | 39 | _vacantHead = item.next; 40 | 41 | Item& head = _items[_vacantHead]; 42 | HFSM2_ASSERT(head.prev == index); 43 | head.prev = INVALID; 44 | } else if (_last < CAPACITY - 1) { 45 | // grow 46 | ++_last; 47 | _vacantHead = _last; 48 | _vacantTail = _last; 49 | 50 | Item& vacant = _items[_vacantHead]; 51 | vacant.prev = INVALID; 52 | vacant.next = INVALID; 53 | } else { 54 | // last 55 | HFSM2_ASSERT(_count == CAPACITY - 1); 56 | 57 | _last = CAPACITY; 58 | _vacantHead = INVALID; 59 | _vacantTail = INVALID; 60 | } 61 | 62 | new (&item) Item{::hfsm2::forward(args)...}; 63 | ++_count; 64 | 65 | HFSM2_IF_ASSERT(verifyStructure()); 66 | 67 | return index; 68 | } else { 69 | // full 70 | HFSM2_ASSERT(_vacantHead == INVALID); 71 | HFSM2_ASSERT(_vacantTail == INVALID); 72 | HFSM2_ASSERT(_count == CAPACITY); 73 | HFSM2_BREAK(); 74 | 75 | return INVALID; 76 | } 77 | } 78 | 79 | //------------------------------------------------------------------------------ 80 | 81 | template 82 | HFSM2_CONSTEXPR(14) 83 | void 84 | TaskListT::remove(const Index i) noexcept { 85 | HFSM2_ASSERT(i < CAPACITY && _count); 86 | 87 | Item& item = _items[i]; 88 | 89 | if (_count < CAPACITY) { 90 | HFSM2_ASSERT(_vacantHead < CAPACITY); 91 | HFSM2_ASSERT(_vacantTail < CAPACITY); 92 | 93 | item.prev = INVALID; 94 | item.next = _vacantHead; 95 | 96 | Item& head = _items[_vacantHead]; 97 | head.prev = i; 98 | 99 | _vacantHead = i; 100 | } else { 101 | // 0 -> 1 102 | HFSM2_ASSERT(_count == CAPACITY); 103 | HFSM2_ASSERT(_vacantHead == INVALID); 104 | HFSM2_ASSERT(_vacantTail == INVALID); 105 | 106 | item.prev = INVALID; 107 | item.next = INVALID; 108 | 109 | _vacantHead = i; 110 | _vacantTail = i; 111 | } 112 | 113 | --_count; 114 | 115 | HFSM2_IF_ASSERT(verifyStructure()); 116 | } 117 | 118 | //------------------------------------------------------------------------------ 119 | 120 | template 121 | HFSM2_CONSTEXPR(14) 122 | typename TaskListT::Item& 123 | TaskListT::operator[] (const Index i) noexcept { 124 | HFSM2_IF_ASSERT(verifyStructure()); 125 | 126 | return _items[i]; 127 | } 128 | 129 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 130 | 131 | template 132 | HFSM2_CONSTEXPR(11) 133 | const typename TaskListT::Item& 134 | TaskListT::operator[] (const Index i) const noexcept { 135 | HFSM2_IF_ASSERT(verifyStructure()); 136 | 137 | return _items[i]; 138 | } 139 | 140 | //------------------------------------------------------------------------------ 141 | 142 | #if HFSM2_ASSERT_AVAILABLE() 143 | 144 | template 145 | void 146 | TaskListT::verifyStructure(const Index occupied) const noexcept { 147 | if (_count < CAPACITY) { 148 | HFSM2_ASSERT(_vacantHead < CAPACITY); 149 | HFSM2_ASSERT(_vacantTail < CAPACITY); 150 | 151 | HFSM2_ASSERT(_items[_vacantHead].prev == INVALID); 152 | HFSM2_ASSERT(_items[_vacantTail].next == INVALID); 153 | 154 | Index emptyCount = 1; 155 | 156 | for (Index c = _vacantHead; c != _vacantTail; ) { 157 | HFSM2_ASSERT(occupied != c); 158 | 159 | const Item& current = _items[c]; 160 | 161 | const Long f = current.next; 162 | if (f != INVALID) { 163 | // next 164 | const Item& following = _items[f]; 165 | 166 | HFSM2_ASSERT(following.prev == c); 167 | 168 | c = f; 169 | continue; 170 | } else { 171 | // end 172 | HFSM2_ASSERT(_vacantTail == c); 173 | HFSM2_ASSERT(_count == CAPACITY - emptyCount); 174 | 175 | break; 176 | } 177 | } 178 | } else { 179 | HFSM2_ASSERT(_vacantHead == INVALID); 180 | HFSM2_ASSERT(_vacantTail == INVALID); 181 | } 182 | } 183 | 184 | #endif 185 | 186 | //////////////////////////////////////////////////////////////////////////////// 187 | 188 | } 189 | } 190 | 191 | #endif 192 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/control_0.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | HFSM2_CONSTEXPR(14) 8 | ConstControlT::Origin::Origin(ConstControlT& control_, 9 | const StateID stateId_) noexcept 10 | : control{control_} 11 | , prevId{control._originId} 12 | { 13 | HFSM2_ASSERT(stateId_ < StateList::SIZE); 14 | control._originId = stateId_; 15 | } 16 | 17 | //------------------------------------------------------------------------------ 18 | 19 | template 20 | HFSM2_CONSTEXPR(20) 21 | ConstControlT::Origin::~Origin() noexcept { 22 | control._originId = prevId; 23 | } 24 | 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | template 28 | HFSM2_CONSTEXPR(14) 29 | ConstControlT::Region::Region(ConstControlT& control_, 30 | const RegionID regionId_) noexcept 31 | : control{control_} 32 | , prevId{control._regionId} 33 | { 34 | control.setRegion(regionId_); 35 | } 36 | 37 | //------------------------------------------------------------------------------ 38 | 39 | template 40 | HFSM2_CONSTEXPR(20) 41 | ConstControlT::Region::~Region() noexcept { 42 | control.resetRegion(prevId); 43 | } 44 | 45 | //////////////////////////////////////////////////////////////////////////////// 46 | 47 | template 48 | HFSM2_CONSTEXPR(14) 49 | void 50 | ConstControlT::setRegion(const RegionID regionId_) noexcept { 51 | HFSM2_ASSERT(_regionId <= regionId_ && regionId_ < RegionList::SIZE); 52 | 53 | _regionId = regionId_; 54 | } 55 | 56 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 57 | 58 | template 59 | HFSM2_CONSTEXPR(14) 60 | void 61 | ConstControlT::resetRegion(const RegionID regionId_) noexcept { 62 | HFSM2_ASSERT(regionId_ <= _regionId && _regionId < RegionList::SIZE); 63 | 64 | _regionId = regionId_; 65 | } 66 | 67 | //////////////////////////////////////////////////////////////////////////////// 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/control_1.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | HFSM2_CONSTEXPR(14) 8 | ControlT::Origin::Origin(ControlT& control_, 9 | const StateID stateId_) noexcept 10 | : control{control_} 11 | , prevId{control._originId} 12 | { 13 | HFSM2_ASSERT(stateId_ < StateList::SIZE); 14 | control._originId = stateId_; 15 | } 16 | 17 | //------------------------------------------------------------------------------ 18 | 19 | template 20 | HFSM2_CONSTEXPR(20) 21 | ControlT::Origin::~Origin() noexcept { 22 | control._originId = prevId; 23 | } 24 | 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | template 28 | HFSM2_CONSTEXPR(14) 29 | ControlT::Region::Region(ControlT& control_, 30 | const RegionID regionId_) noexcept 31 | : control{control_} 32 | , prevId{control._regionId} 33 | { 34 | control.setRegion(regionId_); 35 | } 36 | 37 | //------------------------------------------------------------------------------ 38 | 39 | template 40 | HFSM2_CONSTEXPR(20) 41 | ControlT::Region::~Region() noexcept { 42 | control.resetRegion(prevId); 43 | } 44 | 45 | //////////////////////////////////////////////////////////////////////////////// 46 | 47 | template 48 | HFSM2_CONSTEXPR(14) 49 | void 50 | ControlT::setRegion(const RegionID regionId_) noexcept { 51 | HFSM2_ASSERT(_regionId <= regionId_ && regionId_ < RegionList::SIZE); 52 | 53 | _regionId = regionId_; 54 | } 55 | 56 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 57 | 58 | template 59 | HFSM2_CONSTEXPR(14) 60 | void 61 | ControlT::resetRegion(const RegionID regionId_) noexcept { 62 | HFSM2_ASSERT(regionId_ <= _regionId && _regionId < RegionList::SIZE); 63 | 64 | _regionId = regionId_; 65 | } 66 | 67 | //------------------------------------------------------------------------------ 68 | 69 | #if HFSM2_TRANSITION_HISTORY_AVAILABLE() 70 | 71 | template 72 | HFSM2_CONSTEXPR(14) 73 | void 74 | ControlT::pinLastTransition(const StateID stateId_, 75 | const Short index) noexcept 76 | { 77 | if (index != INVALID_SHORT) { 78 | HFSM2_ASSERT(index < TransitionSets::CAPACITY); 79 | 80 | if (!_core.registry.isActive(stateId_)) 81 | _core.transitionTargets[stateId_] = index; 82 | } 83 | } 84 | 85 | //------------------------------------------------------------------------------ 86 | 87 | template 88 | HFSM2_CONSTEXPR(14) 89 | const typename ControlT::Transition* 90 | ControlT::lastTransitionTo(const StateID stateId_) const noexcept { 91 | if (HFSM2_CHECKED(stateId_ < StateList::SIZE)) { 92 | const Short index = _core.transitionTargets[stateId_]; 93 | 94 | if (index < _core.previousTransitions.count()) 95 | return &_core.previousTransitions[index]; 96 | } 97 | 98 | return nullptr; 99 | } 100 | 101 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 102 | 103 | template 104 | HFSM2_CONSTEXPR(14) 105 | const typename ControlT::Transition* 106 | ControlT::lastTransition() const noexcept { 107 | HFSM2_ASSERT(_originId < _core.transitionTargets.CAPACITY); 108 | 109 | return lastTransitionTo(_originId); 110 | } 111 | 112 | #endif 113 | 114 | //////////////////////////////////////////////////////////////////////////////// 115 | 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/control_2.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | class PlanControlT 8 | : public ControlT 9 | { 10 | template 11 | friend struct S_; 12 | 13 | template 14 | friend struct C_; 15 | 16 | template 17 | friend struct O_; 18 | 19 | template 20 | friend class R_; 21 | 22 | template 23 | friend class RV_; 24 | 25 | protected: 26 | using Control = ControlT; 27 | 28 | using typename Control::StateList; 29 | using typename Control::RegionList; 30 | 31 | using typename Control::Core; 32 | 33 | using TransitionSets = typename Core::TransitionSets; 34 | 35 | #if HFSM2_PLANS_AVAILABLE() 36 | using typename Control::PlanData; 37 | #endif 38 | 39 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 40 | 41 | struct Region { 42 | HFSM2_CONSTEXPR(14) Region(PlanControlT& control, 43 | const RegionID regionId_, 44 | const StateID index, 45 | const Long size) noexcept; 46 | 47 | HFSM2_CONSTEXPR(20) ~Region() noexcept; 48 | 49 | PlanControlT& control; 50 | const RegionID prevId; 51 | const Long prevIndex; 52 | const Long prevSize; 53 | }; 54 | 55 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 56 | 57 | HFSM2_CONSTEXPR(11) PlanControlT(Core& core, 58 | const TransitionSets& currentTransitions) noexcept 59 | : Control{core} 60 | , _currentTransitions{currentTransitions} 61 | {} 62 | 63 | HFSM2_CONSTEXPR(14) void setRegion(const RegionID regionId_, 64 | const StateID index, 65 | const Long size) noexcept; 66 | 67 | HFSM2_CONSTEXPR(14) void resetRegion(const RegionID regionId_, 68 | const StateID index, 69 | const Long size) noexcept; 70 | 71 | public: 72 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 73 | 74 | #if HFSM2_PLANS_AVAILABLE() 75 | using typename Control::CPlan; 76 | 77 | using Plan = PayloadPlanT; 78 | 79 | /// @brief Access plan for the current region 80 | /// @return Plan for the current region 81 | /// @see `HFSM2_ENABLE_PLANS` 82 | HFSM2_CONSTEXPR(14) Plan plan() noexcept { return Plan{_core.registry, _core.planData, _regionId }; } 83 | 84 | // COMMON 85 | 86 | /// @brief Access plan for a region 87 | /// @param `regionId` Region identifier 88 | /// @return Plan for the region 89 | /// @see `HFSM2_ENABLE_PLANS` 90 | HFSM2_CONSTEXPR(14) Plan plan(const RegionID regionId_) noexcept { return Plan{_core.registry, _core.planData, regionId_ }; } 91 | 92 | /// @brief Access plan for a region 93 | /// @tparam `TRegion` Region head state type 94 | /// @return Plan for the region 95 | /// @see `HFSM2_ENABLE_PLANS` 96 | template 97 | HFSM2_CONSTEXPR(14) Plan plan() noexcept { return Plan{_core.registry, _core.planData, Control::template regionId()}; } 98 | 99 | // COMMON 100 | 101 | /// @brief Access plan for the current region 102 | /// @return Plan for the current region 103 | /// @see `HFSM2_ENABLE_PLANS` 104 | HFSM2_CONSTEXPR(11) CPlan plan() const noexcept { return CPlan{_core.registry, _core.planData, _regionId }; } 105 | 106 | // COMMON 107 | 108 | /// @brief Access plan for a region 109 | /// @param `regionId` 110 | /// @return Plan for the region 111 | /// @see `HFSM2_ENABLE_PLANS` 112 | HFSM2_CONSTEXPR(11) CPlan plan(const RegionID regionId_) const noexcept { return CPlan{_core.registry, _core.planData, regionId_ }; } 113 | 114 | /// @brief Access plan for a region 115 | /// @tparam `TRegion` Region head state type 116 | /// @return Plan for the region 117 | /// @see `HFSM2_ENABLE_PLANS` 118 | template 119 | HFSM2_CONSTEXPR(11) CPlan plan() const noexcept { return CPlan{_core.registry, _core.planData, Control::template regionId()}; } 120 | 121 | #endif 122 | 123 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 124 | 125 | /// @brief Get current transition requests 126 | /// @return DynamicArrayT of pending transition requests 127 | HFSM2_CONSTEXPR(11) const TransitionSets& currentTransitions() const noexcept { return _currentTransitions; } 128 | 129 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 130 | 131 | protected: 132 | using Control::_core; 133 | using Control::_regionId; 134 | 135 | const TransitionSets& _currentTransitions; 136 | 137 | StateID _regionStateId = 0; 138 | Long _regionSize = StateList::SIZE; 139 | TaskStatus _taskStatus; 140 | }; 141 | 142 | //////////////////////////////////////////////////////////////////////////////// 143 | 144 | } 145 | } 146 | 147 | #include "control_2.inl" 148 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/control_2.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | HFSM2_CONSTEXPR(14) 8 | PlanControlT::Region::Region(PlanControlT& control_, 9 | const RegionID regionId_, 10 | const StateID index, 11 | const Long size) noexcept 12 | : control {control_} 13 | , prevId {control._regionId} 14 | , prevIndex{control._regionStateId} 15 | , prevSize {control._regionSize} 16 | { 17 | control.setRegion(regionId_, index, size); 18 | } 19 | 20 | //------------------------------------------------------------------------------ 21 | 22 | template 23 | HFSM2_CONSTEXPR(20) 24 | PlanControlT::Region::~Region() noexcept { 25 | control.resetRegion(prevId, prevIndex, prevSize); 26 | } 27 | 28 | //////////////////////////////////////////////////////////////////////////////// 29 | 30 | template 31 | HFSM2_CONSTEXPR(14) 32 | void 33 | PlanControlT::setRegion(const RegionID regionId_, 34 | const StateID index, 35 | const Long size) noexcept 36 | { 37 | HFSM2_ASSERT(_regionId <= regionId_ && regionId_ < RegionList::SIZE); 38 | HFSM2_ASSERT(_regionStateId <= index && index + size <= _regionStateId + _regionSize); 39 | 40 | _regionId = regionId_; 41 | _regionStateId = index; 42 | _regionSize = size; 43 | } 44 | 45 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 46 | 47 | template 48 | HFSM2_CONSTEXPR(14) 49 | void 50 | PlanControlT::resetRegion(const RegionID regionId_, 51 | const StateID index, 52 | const Long size) noexcept 53 | { 54 | HFSM2_ASSERT(regionId_ <= _regionId && _regionId < RegionList::SIZE); 55 | HFSM2_ASSERT(index <= _regionStateId && _regionStateId + _regionSize <= index + size); 56 | 57 | _regionId = regionId_; 58 | _regionStateId = index; 59 | _regionSize = size; 60 | 61 | _taskStatus.clear(); 62 | } 63 | 64 | //////////////////////////////////////////////////////////////////////////////// 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/control_4.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | class GuardControlT final 8 | : public FullControlT 9 | { 10 | template 11 | friend struct S_; 12 | 13 | template 14 | friend class R_; 15 | 16 | using FullControl = FullControlT; 17 | 18 | using typename FullControl::Core; 19 | using typename FullControl::Context; 20 | 21 | using typename FullControl::Registry; 22 | using typename FullControl::TransitionSet; 23 | using typename FullControl::TransitionSets; 24 | 25 | #if HFSM2_TRANSITION_HISTORY_AVAILABLE() 26 | using typename FullControl::TransitionTargets; 27 | #endif 28 | 29 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 30 | using typename FullControl::RNG; 31 | #endif 32 | 33 | #if HFSM2_PLANS_AVAILABLE() 34 | using typename FullControl::PlanData; 35 | #endif 36 | 37 | #if HFSM2_LOG_INTERFACE_AVAILABLE() 38 | using typename FullControl::Logger; 39 | #endif 40 | 41 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 42 | 43 | HFSM2_CONSTEXPR(11) GuardControlT(Core& core, 44 | const TransitionSets& currentTransitions, 45 | const TransitionSet& pendingTransitions) noexcept 46 | : FullControl{core, currentTransitions} 47 | , _pendingTransitions{pendingTransitions} 48 | {} 49 | 50 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 51 | 52 | public: 53 | using FullControl::context; 54 | 55 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 56 | 57 | /// @brief Check if a state is going to be activated or deactivated 58 | /// @param `stateId` State identifier 59 | /// @return State pending activation/deactivation status 60 | HFSM2_CONSTEXPR(11) bool isPendingChange(const StateID stateId_) const noexcept { return _core.registry.isPendingChange(stateId_); } 61 | 62 | /// @brief Check if a state is going to be activated or deactivated 63 | /// @tparam `TState` State type 64 | /// @return State pending activation/deactivation status 65 | template 66 | HFSM2_CONSTEXPR(11) bool isPendingChange() const noexcept { return isPendingChange(FullControl::template stateId()); } 67 | 68 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 69 | 70 | /// @brief Check if a state is going to be activated 71 | /// @param `stateId` State identifier 72 | /// @return State pending activation status 73 | HFSM2_CONSTEXPR(11) bool isPendingEnter (const StateID stateId_) const noexcept { return _core.registry.isPendingEnter (stateId_); } 74 | 75 | /// @brief Check if a state is going to be activated 76 | /// @tparam `TState` State type 77 | /// @return State pending activation status 78 | template 79 | HFSM2_CONSTEXPR(11) bool isPendingEnter () const noexcept { return isPendingEnter (FullControl::template stateId()); } 80 | 81 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 82 | 83 | /// @brief Check if a state is going to be deactivated 84 | /// @param `stateId` State identifier 85 | /// @return State pending deactivation status 86 | HFSM2_CONSTEXPR(11) bool isPendingExit (const StateID stateId_) const noexcept { return _core.registry.isPendingExit (stateId_); } 87 | 88 | /// @brief Check if a state is going to be deactivated 89 | /// @tparam `TState` State type 90 | /// @return State pending deactivation status 91 | template 92 | HFSM2_CONSTEXPR(11) bool isPendingExit () const noexcept { return isPendingExit (FullControl::template stateId()); } 93 | 94 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 95 | // COMMON 96 | 97 | /// @brief Get pending transition requests 98 | /// @return Array of pending transition requests 99 | HFSM2_CONSTEXPR(11) const TransitionSet& pendingTransitions() const noexcept { return _pendingTransitions; } 100 | 101 | /// @brief Cancel pending transition requests 102 | /// (can be used to substitute a transition into the current state with a different one) 103 | HFSM2_CONSTEXPR(14) void cancelPendingTransitions() noexcept; 104 | 105 | private: 106 | using FullControl::_core; 107 | using FullControl::_originId; 108 | 109 | const TransitionSet& _pendingTransitions; 110 | 111 | bool _cancelled = false; 112 | }; 113 | 114 | //////////////////////////////////////////////////////////////////////////////// 115 | 116 | } 117 | } 118 | 119 | #include "control_4.inl" 120 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/control_4.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | HFSM2_CONSTEXPR(14) 8 | void 9 | GuardControlT::cancelPendingTransitions() noexcept { 10 | _cancelled = true; 11 | 12 | HFSM2_LOG_CANCELLED_PENDING(context(), _originId); 13 | } 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/control_5.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | class EventControlT final 8 | : public FullControlT 9 | { 10 | template 11 | friend class R_; 12 | 13 | template 14 | friend struct PreReactWrapperT; 15 | 16 | template 17 | friend struct ReactWrapperT; 18 | 19 | template 20 | friend struct PostReactWrapperT; 21 | 22 | using FullControl = FullControlT; 23 | 24 | using FullControl::FullControl; 25 | 26 | public: 27 | using FullControl::context; 28 | 29 | /// @brief Stops processing of the current event down the hierarchy 30 | /// @see `Config::BottomUpReactions` 31 | HFSM2_CONSTEXPR(14) void consumeEvent() noexcept { _consumed = true; } 32 | 33 | private: 34 | bool _consumed = false; 35 | }; 36 | 37 | //////////////////////////////////////////////////////////////////////////////// 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/core.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | struct CoreT { 8 | using Context = typename TArgs::Context; 9 | using PureContext = typename TArgs::PureContext; 10 | 11 | using Registry = RegistryT; 12 | 13 | using Payload = typename TArgs::Payload; 14 | using Transition = TransitionT; 15 | using TransitionSet = DynamicArrayT; 16 | using TransitionSets = DynamicArrayT; 17 | 18 | #if HFSM2_PLANS_AVAILABLE() 19 | using PlanData = PlanDataT; 20 | #endif 21 | 22 | #if HFSM2_TRANSITION_HISTORY_AVAILABLE() 23 | using TransitionTargets = StaticArrayT; 24 | #endif 25 | 26 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 27 | using RNG = typename TArgs::RNG; 28 | #endif 29 | 30 | #if HFSM2_LOG_INTERFACE_AVAILABLE() 31 | using Logger = typename TArgs::Logger; 32 | #endif 33 | 34 | HFSM2_CONSTEXPR(14) explicit CoreT(Context& context_ 35 | HFSM2_IF_UTILITY_THEORY(, RNG& rng_) 36 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger_ = nullptr)) noexcept; 37 | 38 | HFSM2_CONSTEXPR(14) explicit CoreT(PureContext&& context_ 39 | HFSM2_IF_UTILITY_THEORY(, RNG& rng_) 40 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger_ = nullptr)) noexcept; 41 | 42 | HFSM2_CONSTEXPR(14) CoreT(const CoreT& other) noexcept; 43 | HFSM2_CONSTEXPR(14) CoreT( CoreT&& other) noexcept; 44 | 45 | Context context; 46 | Registry registry; 47 | TransitionSet requests; 48 | HFSM2_IF_PLANS(PlanData planData); 49 | HFSM2_IF_TRANSITION_HISTORY(TransitionTargets transitionTargets); 50 | HFSM2_IF_TRANSITION_HISTORY(TransitionSets previousTransitions); 51 | HFSM2_IF_UTILITY_THEORY(RNG& rng); 52 | HFSM2_IF_LOG_INTERFACE(Logger* logger); 53 | }; 54 | 55 | //////////////////////////////////////////////////////////////////////////////// 56 | 57 | } 58 | } 59 | 60 | #include "core.inl" 61 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/core.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | HFSM2_CONSTEXPR(14) 8 | CoreT::CoreT(Context& context_ 9 | HFSM2_IF_UTILITY_THEORY(, RNG& rng_) 10 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger_)) noexcept 11 | : context{context_} 12 | HFSM2_IF_UTILITY_THEORY(, rng{rng_}) 13 | HFSM2_IF_LOG_INTERFACE(, logger{logger_}) 14 | {} 15 | 16 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 17 | 18 | template 19 | HFSM2_CONSTEXPR(14) 20 | CoreT::CoreT(PureContext&& context_ 21 | HFSM2_IF_UTILITY_THEORY(, RNG& rng_) 22 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger_)) noexcept 23 | : context{move(context_)} 24 | HFSM2_IF_UTILITY_THEORY(, rng {rng_ }) 25 | HFSM2_IF_LOG_INTERFACE (, logger{logger_}) 26 | {} 27 | 28 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 29 | 30 | template 31 | HFSM2_CONSTEXPR(14) 32 | CoreT::CoreT(const CoreT& other) noexcept 33 | : context {other.context } 34 | , registry{other.registry} 35 | , requests{other.requests} 36 | HFSM2_IF_PLANS (, planData {other.planData }) 37 | HFSM2_IF_TRANSITION_HISTORY(, transitionTargets {other.transitionTargets }) 38 | HFSM2_IF_TRANSITION_HISTORY(, previousTransitions{other.previousTransitions}) 39 | HFSM2_IF_UTILITY_THEORY (, rng {other.rng }) 40 | HFSM2_IF_LOG_INTERFACE (, logger {other.logger }) 41 | {} 42 | 43 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 44 | 45 | template 46 | HFSM2_CONSTEXPR(14) 47 | CoreT::CoreT(CoreT&& other) noexcept 48 | : context {move(other.context )} 49 | , registry{move(other.registry)} 50 | , requests{move(other.requests)} 51 | HFSM2_IF_PLANS (, planData {move(other.planData )}) 52 | HFSM2_IF_TRANSITION_HISTORY(, transitionTargets {move(other.transitionTargets )}) 53 | HFSM2_IF_TRANSITION_HISTORY(, previousTransitions{move(other.previousTransitions)}) 54 | HFSM2_IF_UTILITY_THEORY (, rng {move(other.rng )}) 55 | HFSM2_IF_LOG_INTERFACE (, logger {move(other.logger )}) 56 | {} 57 | 58 | //////////////////////////////////////////////////////////////////////////////// 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/plan_0.hpp: -------------------------------------------------------------------------------- 1 | #if HFSM2_PLANS_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | template 9 | class CPlanT { 10 | template 11 | friend class ControlT; 12 | 13 | template 14 | friend class PlanControlT; 15 | 16 | template 17 | friend class FullControlT; 18 | 19 | template 20 | friend class GuardControlT; 21 | 22 | template 23 | friend class R_; 24 | 25 | using Args = TArgs; 26 | using Context = typename Args::Context; 27 | using StateList = typename Args::StateList; 28 | using RegionList = typename Args::RegionList; 29 | 30 | static constexpr Long TASK_CAPACITY = Args::TASK_CAPACITY; 31 | 32 | public: 33 | using PlanData = PlanDataT; 34 | using Task = typename PlanData::Task; 35 | using TaskLinks = typename PlanData::TaskLinks; 36 | 37 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 38 | 39 | struct Iterator final { 40 | HFSM2_CONSTEXPR(14) Iterator(const CPlanT& plan) noexcept; 41 | 42 | HFSM2_CONSTEXPR(14) explicit operator bool() const noexcept; 43 | 44 | HFSM2_CONSTEXPR(14) void operator ++() noexcept; 45 | 46 | HFSM2_CONSTEXPR(11) bool operator != (const Iterator) const noexcept { return operator bool(); } 47 | 48 | HFSM2_CONSTEXPR(11) const Task& operator *() const noexcept { return _plan._planData.tasks[_curr]; } 49 | HFSM2_CONSTEXPR(11) const Task* operator ->() const noexcept { return &_plan._planData.tasks[_curr]; } 50 | 51 | HFSM2_CONSTEXPR(14) Long next() const noexcept; 52 | 53 | const CPlanT& _plan; 54 | Long _curr; 55 | Long _next; 56 | }; 57 | 58 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 59 | 60 | private: 61 | HFSM2_CONSTEXPR(11) CPlanT(const PlanData& planData, 62 | const RegionID regionId_) noexcept 63 | : _planData{planData} 64 | , _bounds{planData.taskBounds[regionId_]} 65 | {} 66 | 67 | template 68 | static 69 | HFSM2_CONSTEXPR(11) StateID stateId() noexcept { return index(); } 70 | 71 | template 72 | static 73 | HFSM2_CONSTEXPR(11) RegionID regionId() noexcept { return static_cast(index()); } 74 | 75 | public: 76 | HFSM2_CONSTEXPR(14) explicit operator bool() const noexcept; 77 | 78 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 79 | 80 | /// @brief Begin iteration over plan tasks 81 | /// @return CIterator to the first task 82 | HFSM2_CONSTEXPR(14) Iterator begin() noexcept { return Iterator{*this}; } 83 | 84 | /// @brief Iteration terminator 85 | /// @return Dummy Iterator 86 | HFSM2_CONSTEXPR(14) Iterator end () noexcept { return Iterator{*this}; } 87 | 88 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 89 | 90 | /// @brief First task 91 | /// @return First task 92 | HFSM2_CONSTEXPR(14) const Task& first() const noexcept; 93 | 94 | /// @brief Last task 95 | /// @return Last task 96 | HFSM2_CONSTEXPR(14) const Task& last() const noexcept; 97 | 98 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 99 | 100 | private: 101 | const PlanData& _planData; 102 | const Bounds& _bounds; 103 | }; 104 | 105 | //////////////////////////////////////////////////////////////////////////////// 106 | 107 | } 108 | } 109 | 110 | #endif 111 | 112 | #include "plan_0.inl" 113 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/plan_0.inl: -------------------------------------------------------------------------------- 1 | #if HFSM2_PLANS_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | template 9 | HFSM2_CONSTEXPR(14) 10 | CPlanT::Iterator::Iterator(const CPlanT& plan) noexcept 11 | : _plan{plan} 12 | , _curr{plan._bounds.first} 13 | { 14 | _next = next(); 15 | } 16 | 17 | //------------------------------------------------------------------------------ 18 | 19 | template 20 | HFSM2_CONSTEXPR(14) 21 | CPlanT::Iterator::operator bool() const noexcept { 22 | HFSM2_ASSERT(_curr < CPlanT::TASK_CAPACITY || 23 | _curr == INVALID_LONG); 24 | 25 | return _curr < CPlanT::TASK_CAPACITY; 26 | } 27 | 28 | //------------------------------------------------------------------------------ 29 | 30 | template 31 | HFSM2_CONSTEXPR(14) 32 | void 33 | CPlanT::Iterator::operator ++() noexcept { 34 | _curr = _next; 35 | _next = next(); 36 | } 37 | 38 | //------------------------------------------------------------------------------ 39 | 40 | template 41 | HFSM2_CONSTEXPR(14) 42 | Long 43 | CPlanT::Iterator::next() const noexcept { 44 | if (_curr < CPlanT::TASK_CAPACITY) { 45 | const TaskLink& link = _plan._planData.taskLinks[_curr]; 46 | 47 | return link.next; 48 | } else { 49 | HFSM2_ASSERT(_curr == INVALID_LONG); 50 | 51 | return INVALID_LONG; 52 | } 53 | } 54 | 55 | //////////////////////////////////////////////////////////////////////////////// 56 | 57 | template 58 | HFSM2_CONSTEXPR(14) 59 | CPlanT::operator bool() const noexcept { 60 | HFSM2_ASSERT(_bounds.first < TASK_CAPACITY && 61 | _bounds.last < TASK_CAPACITY || 62 | _bounds.last == INVALID_LONG); 63 | 64 | return _bounds.first < TASK_CAPACITY; 65 | } 66 | 67 | //------------------------------------------------------------------------------ 68 | 69 | template 70 | HFSM2_CONSTEXPR(14) 71 | const typename CPlanT::Task& 72 | CPlanT::first() const noexcept { 73 | HFSM2_ASSERT(_bounds.first < TASK_CAPACITY); 74 | 75 | return _planData.tasks[_bounds.first]; 76 | } 77 | 78 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 79 | 80 | template 81 | HFSM2_CONSTEXPR(14) 82 | const typename CPlanT::Task& 83 | CPlanT::last() const noexcept { 84 | HFSM2_ASSERT(_bounds.last < TASK_CAPACITY); 85 | 86 | return _planData.tasks[_bounds.last]; 87 | } 88 | 89 | //////////////////////////////////////////////////////////////////////////////// 90 | 91 | } 92 | } 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root/plan_2.inl: -------------------------------------------------------------------------------- 1 | #if HFSM2_PLANS_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | template 9 | HFSM2_CONSTEXPR(14) 10 | bool 11 | PayloadPlanT>:: append(const StateID origin, 12 | const StateID destination, 13 | const TransitionType transitionType, 14 | const Payload& payload) noexcept 15 | { 16 | if (_planData.tasks.count() < TASK_CAPACITY) { 17 | _planData.planExists.set(_regionId); 18 | 19 | return linkTask(_planData.tasks.emplace(origin, destination, transitionType, payload)); 20 | } else 21 | return false; 22 | } 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root_3.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | HFSM2_CONSTEXPR(14) 8 | RC_, TA_>::RC_(Context& context 9 | HFSM2_IF_UTILITY_THEORY(, RNG& rng) 10 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger)) noexcept 11 | : Base{context 12 | HFSM2_IF_UTILITY_THEORY(, rng) 13 | HFSM2_IF_LOG_INTERFACE(, logger)} 14 | {} 15 | 16 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 17 | 18 | template 19 | HFSM2_CONSTEXPR(14) 20 | RC_, TA_>::RC_(PureContext&& context 21 | HFSM2_IF_UTILITY_THEORY(, RNG& rng) 22 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger)) noexcept 23 | : Base{move(context) 24 | HFSM2_IF_UTILITY_THEORY(, rng) 25 | HFSM2_IF_LOG_INTERFACE(, logger)} 26 | {} 27 | 28 | //////////////////////////////////////////////////////////////////////////////// 29 | 30 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 31 | 32 | template 33 | HFSM2_CONSTEXPR(14) 34 | RC_, TA_>::RC_(Context context 35 | , RNG& rng 36 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger)) noexcept 37 | : Base{context 38 | , rng 39 | HFSM2_IF_LOG_INTERFACE(, logger)} 40 | {} 41 | 42 | #else 43 | 44 | template 45 | HFSM2_CONSTEXPR(14) 46 | RC_, TA_>::RC_(Context context 47 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger)) noexcept 48 | : Base{context 49 | HFSM2_IF_LOG_INTERFACE(, logger)} 50 | {} 51 | 52 | #endif 53 | 54 | //////////////////////////////////////////////////////////////////////////////// 55 | 56 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 57 | 58 | template 59 | HFSM2_CONSTEXPR(14) 60 | RC_, TA_>::RC_(RNG& rng 61 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger)) noexcept 62 | : Base{static_cast(*this) 63 | , rng 64 | HFSM2_IF_LOG_INTERFACE(, logger)} 65 | {} 66 | 67 | #else 68 | 69 | template 70 | HFSM2_CONSTEXPR(14) 71 | RC_, TA_>::RC_(HFSM2_IF_LOG_INTERFACE(Logger* const logger)) noexcept 72 | : Base{static_cast(*this) 73 | HFSM2_IF_LOG_INTERFACE(, logger)} 74 | {} 75 | 76 | #endif 77 | 78 | //////////////////////////////////////////////////////////////////////////////// 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /development/hfsm2/detail/root_4.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | /// @brief FSM Root 7 | /// @tparam `TConfig` Type configuration 8 | /// @tparam `TApex` Root region type 9 | template < 10 | typename TConfig 11 | , typename TApex 12 | > 13 | class HFSM2_EMPTY_BASES InstanceT final 14 | : public RC_ 15 | { 16 | using Base = RC_; 17 | 18 | public: 19 | using Base::Base; 20 | }; 21 | 22 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 23 | 24 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 25 | // TRNG == RNGT 26 | 27 | /// @brief FSM Root 28 | /// @tparam `TConfig` Type configuration 29 | /// @tparam `TApex` Root region type 30 | template < 31 | FeatureTag NFeatureTag 32 | , typename TContext 33 | , typename TActivation 34 | , typename TReactOrder 35 | , typename TRank 36 | , typename TUtility 37 | , Short NSubstitutionLimit 38 | HFSM2_IF_PLANS(, Long NTaskCapacity) 39 | , typename TPayload 40 | , typename TApex 41 | > 42 | class HFSM2_EMPTY_BASES InstanceT< 43 | G_< 44 | NFeatureTag 45 | , TContext 46 | , TActivation 47 | , TReactOrder 48 | , TRank 49 | , TUtility 50 | , RNGT 51 | , NSubstitutionLimit 52 | HFSM2_IF_PLANS(, NTaskCapacity) 53 | , TPayload 54 | > 55 | , TApex 56 | > final 57 | : public RC_< 58 | G_< 59 | NFeatureTag 60 | , TContext 61 | , TActivation 62 | , TReactOrder 63 | , TRank 64 | , TUtility 65 | , RNGT 66 | , NSubstitutionLimit 67 | HFSM2_IF_PLANS(, NTaskCapacity) 68 | , TPayload 69 | > 70 | , TApex 71 | > 72 | , public RNGT 73 | { 74 | using Base = RC_< 75 | G_< 76 | NFeatureTag 77 | , TContext 78 | , TActivation 79 | , TReactOrder 80 | , TRank 81 | , TUtility 82 | , RNGT 83 | , NSubstitutionLimit 84 | HFSM2_IF_PLANS(, NTaskCapacity) 85 | , TPayload 86 | > 87 | , TApex 88 | >; 89 | 90 | public: 91 | static constexpr FeatureTag FEATURE_TAG = Base::FEATURE_TAG; 92 | 93 | using typename Base::Context; 94 | 95 | #if HFSM2_LOG_INTERFACE_AVAILABLE() 96 | using typename Base::Logger; 97 | #endif 98 | 99 | public: 100 | HFSM2_CONSTEXPR(14) explicit InstanceT(Context& context 101 | HFSM2_IF_LOG_INTERFACE(, Logger* const logger = nullptr)) noexcept 102 | : Base{context 103 | , static_cast&>(*this) 104 | HFSM2_IF_LOG_INTERFACE(, logger)} 105 | , RNGT{0} 106 | {} 107 | }; 108 | 109 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 110 | // TContext == EmptyContext 111 | // TRNG == RNGT 112 | 113 | /// @brief FSM Root 114 | /// @tparam `TConfig` Type configuration 115 | /// @tparam `TApex` Root region type 116 | template < 117 | FeatureTag NFeatureTag 118 | , typename TActivation 119 | , typename TReactOrder 120 | , typename TRank 121 | , typename TUtility 122 | , Short NSubstitutionLimit 123 | HFSM2_IF_PLANS(, Long NTaskCapacity) 124 | , typename TPayload 125 | , typename TApex 126 | > 127 | class HFSM2_EMPTY_BASES InstanceT< 128 | G_< 129 | NFeatureTag 130 | , EmptyContext 131 | , TActivation 132 | , TReactOrder 133 | , TRank 134 | , TUtility 135 | , RNGT 136 | , NSubstitutionLimit 137 | HFSM2_IF_PLANS(, NTaskCapacity) 138 | , TPayload 139 | > 140 | , TApex 141 | > final 142 | : public RC_< 143 | G_< 144 | NFeatureTag 145 | , EmptyContext 146 | , TActivation 147 | , TReactOrder 148 | , TRank 149 | , TUtility 150 | , RNGT 151 | , NSubstitutionLimit 152 | HFSM2_IF_PLANS(, NTaskCapacity) 153 | , TPayload 154 | > 155 | , TApex 156 | > 157 | , public RNGT 158 | { 159 | using Base = RC_< 160 | G_< 161 | NFeatureTag 162 | , EmptyContext 163 | , TActivation 164 | , TReactOrder 165 | , TRank 166 | , TUtility 167 | , RNGT 168 | , NSubstitutionLimit 169 | HFSM2_IF_PLANS(, NTaskCapacity) 170 | , TPayload 171 | > 172 | , TApex 173 | >; 174 | 175 | public: 176 | static constexpr FeatureTag FEATURE_TAG = Base::FEATURE_TAG; 177 | 178 | #if HFSM2_LOG_INTERFACE_AVAILABLE() 179 | using typename Base::Logger; 180 | #endif 181 | 182 | public: 183 | HFSM2_CONSTEXPR(14) explicit InstanceT(HFSM2_IF_LOG_INTERFACE(Logger* const logger = nullptr)) noexcept 184 | : Base{static_cast&>(*this) 185 | HFSM2_IF_LOG_INTERFACE(, logger)} 186 | , RNGT{0} 187 | {} 188 | }; 189 | 190 | #endif 191 | 192 | //////////////////////////////////////////////////////////////////////////////// 193 | 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /development/hfsm2/detail/shared/bit_stream.hpp: -------------------------------------------------------------------------------- 1 | #if HFSM2_SERIALIZATION_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //------------------------------------------------------------------------------ 7 | 8 | template 9 | class BitWriteStreamT; 10 | 11 | template 12 | class BitReadStreamT; 13 | 14 | //////////////////////////////////////////////////////////////////////////////// 15 | 16 | template 17 | class StreamBufferT { 18 | template 19 | friend class BitWriteStreamT; 20 | 21 | template 22 | friend class BitReadStreamT; 23 | 24 | public: 25 | static constexpr Long BIT_CAPACITY = NBitCapacity; 26 | static constexpr Long BYTE_COUNT = contain(BIT_CAPACITY, 8u); 27 | 28 | using StreamBuffer = StreamBufferT; 29 | using Data = uint8_t [BYTE_COUNT ]; 30 | 31 | HFSM2_CONSTEXPR(14) void clear() noexcept { fill(_data, 0); } 32 | 33 | HFSM2_CONSTEXPR(14) Data& data() noexcept { return _data; } 34 | HFSM2_CONSTEXPR(11) const Data& data() const noexcept { return _data; } 35 | 36 | HFSM2_CONSTEXPR(14) bool operator == (const StreamBuffer& s) const noexcept; 37 | HFSM2_CONSTEXPR(14) bool operator != (const StreamBuffer& s) const noexcept; 38 | 39 | private: 40 | Data _data {}; 41 | }; 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | 45 | template 46 | class BitWriteStreamT final { 47 | public: 48 | static constexpr Long BIT_CAPACITY = NBitCapacity; 49 | 50 | using Buffer = StreamBufferT; 51 | 52 | public: 53 | HFSM2_CONSTEXPR(14) explicit BitWriteStreamT(Buffer& buffer, 54 | const Long cursor = 0) noexcept 55 | : _buffer{buffer} 56 | , _cursor{cursor} 57 | { 58 | _buffer.clear(); 59 | } 60 | 61 | template 62 | HFSM2_CONSTEXPR(14) void write(const UBitWidth item) noexcept; 63 | 64 | HFSM2_CONSTEXPR(11) Long cursor() const noexcept { return _cursor; } 65 | 66 | private: 67 | Buffer& _buffer; 68 | 69 | Long _cursor = 0; 70 | }; 71 | 72 | //------------------------------------------------------------------------------ 73 | 74 | template 75 | class BitReadStreamT final { 76 | public: 77 | static constexpr Long BIT_CAPACITY = NBitCapacity; 78 | 79 | using Buffer = StreamBufferT; 80 | 81 | public: 82 | HFSM2_CONSTEXPR(11) explicit BitReadStreamT(const Buffer& buffer, 83 | const Long cursor = 0) noexcept 84 | : _buffer{buffer} 85 | , _cursor{cursor} 86 | {} 87 | 88 | template 89 | HFSM2_CONSTEXPR(14) UBitWidth read() noexcept; 90 | 91 | HFSM2_CONSTEXPR(11) Long cursor() const noexcept { return _cursor; } 92 | 93 | private: 94 | const Buffer& _buffer; 95 | 96 | Long _cursor; 97 | }; 98 | 99 | //////////////////////////////////////////////////////////////////////////////// 100 | 101 | } 102 | } 103 | 104 | #include "bit_stream.inl" 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /development/hfsm2/detail/shared/bit_stream.inl: -------------------------------------------------------------------------------- 1 | #if HFSM2_SERIALIZATION_AVAILABLE() 2 | 3 | namespace hfsm2 { 4 | namespace detail { 5 | 6 | //////////////////////////////////////////////////////////////////////////////// 7 | 8 | template 9 | HFSM2_CONSTEXPR(14) 10 | bool 11 | StreamBufferT::operator == (const StreamBuffer& buffer) const noexcept { 12 | for (Long i = 0; i < BYTE_COUNT; ++i) 13 | if (_data[i] != buffer._data[i]) 14 | return false; 15 | 16 | return true; 17 | } 18 | 19 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20 | 21 | template 22 | HFSM2_CONSTEXPR(14) 23 | bool 24 | StreamBufferT::operator != (const StreamBuffer& buffer) const noexcept { 25 | for (Long i = 0; i < BYTE_COUNT; ++i) 26 | if (_data[i] != buffer._data[i]) 27 | return true; 28 | 29 | return false; 30 | } 31 | 32 | //////////////////////////////////////////////////////////////////////////////// 33 | 34 | template 35 | template 36 | HFSM2_CONSTEXPR(14) 37 | void 38 | BitWriteStreamT::write(const UBitWidth item) noexcept { 39 | constexpr Short BIT_WIDTH = NBitWidth; 40 | static_assert(BIT_WIDTH > 0, "STATIC ASSERT"); 41 | 42 | HFSM2_ASSERT(_cursor + BIT_WIDTH <= BIT_CAPACITY); 43 | 44 | using Item = UBitWidth; 45 | 46 | Item itemBits = item; 47 | 48 | for (Short itemWidth = BIT_WIDTH; itemWidth; ) { 49 | const Long byteIndex = _cursor >> 3; 50 | uint8_t& byte = _buffer._data[byteIndex]; 51 | 52 | const Short byteChunkStart = _cursor & 0x7; 53 | const Short byteDataWidth = 8 - byteChunkStart; 54 | const Short byteChunkWidth = min(byteDataWidth, itemWidth); 55 | const Item byteChunk = itemBits << byteChunkStart; 56 | 57 | byte |= byteChunk; 58 | itemBits >>= byteChunkWidth; 59 | itemWidth -= byteChunkWidth; 60 | _cursor += byteChunkWidth; 61 | } 62 | } 63 | 64 | //////////////////////////////////////////////////////////////////////////////// 65 | 66 | template 67 | template 68 | HFSM2_CONSTEXPR(14) 69 | UBitWidth 70 | BitReadStreamT::read() noexcept { 71 | constexpr Short BIT_WIDTH = NBitWidth; 72 | static_assert(BIT_WIDTH > 0, "STATIC ASSERT"); 73 | 74 | HFSM2_ASSERT(_cursor + BIT_WIDTH <= BIT_CAPACITY); 75 | 76 | using Item = UBitWidth; 77 | 78 | Item item = 0; 79 | 80 | for (Short itemCursor = 0, itemWidth = BIT_WIDTH; itemWidth; ) { 81 | const Long byteIndex = _cursor >> 3; 82 | const uint8_t& byte = _buffer._data[byteIndex]; 83 | 84 | const Short byteChunkStart = _cursor & 0x7; 85 | const Short byteDataWidth = 8 - byteChunkStart; 86 | const Short byteChunkWidth = min(byteDataWidth, itemWidth); 87 | const Short byteChunkMask = (1 << byteChunkWidth) - 1; 88 | 89 | const Item byteChunk = (byte >> byteChunkStart) & byteChunkMask; 90 | const Item itemChunk = byteChunk << itemCursor; 91 | 92 | item |= itemChunk; 93 | itemCursor += byteChunkWidth; 94 | itemWidth -= byteChunkWidth; 95 | _cursor += byteChunkWidth; 96 | } 97 | 98 | return item; 99 | } 100 | 101 | //////////////////////////////////////////////////////////////////////////////// 102 | 103 | } 104 | } 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /development/hfsm2/detail/shared/iterator.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | class IteratorT { 8 | public: 9 | using Container = TContainer; 10 | using Item = typename Container::Item; 11 | using Index = typename Container::Index; 12 | 13 | template 14 | friend class DynamicArrayT; 15 | 16 | private: 17 | HFSM2_CONSTEXPR(11) IteratorT(Container& container, 18 | const Index cursor) noexcept 19 | : _container{container} 20 | , _cursor{cursor} 21 | {} 22 | 23 | public: 24 | HFSM2_CONSTEXPR(14) bool operator != (const IteratorT& HFSM2_IF_ASSERT(other)) const noexcept { 25 | HFSM2_ASSERT(&_container == &other._container); 26 | 27 | return _cursor != _container.limit(); 28 | } 29 | 30 | HFSM2_CONSTEXPR(14) IteratorT& operator ++() noexcept { 31 | _cursor = _container.next(_cursor); 32 | 33 | return *this; 34 | } 35 | 36 | HFSM2_CONSTEXPR(14) Item& operator *() noexcept { return _container[_cursor]; } 37 | HFSM2_CONSTEXPR(11) const Item& operator *() const noexcept { return _container[_cursor]; } 38 | 39 | HFSM2_CONSTEXPR(14) Item* operator->() noexcept { return &_container[_cursor]; } 40 | HFSM2_CONSTEXPR(11) const Item* operator->() const noexcept { return &_container[_cursor]; } 41 | 42 | private: 43 | Container& _container; 44 | 45 | Index _cursor; 46 | }; 47 | 48 | //------------------------------------------------------------------------------ 49 | 50 | template 51 | class IteratorT { 52 | public: 53 | using Container = TContainer; 54 | using Item = typename Container::Item; 55 | using Index = typename Container::Index; 56 | 57 | template 58 | friend class DynamicArrayT; 59 | 60 | private: 61 | HFSM2_CONSTEXPR(11) IteratorT(const Container& container, 62 | const Index cursor) noexcept 63 | : _container{container} 64 | , _cursor{cursor} 65 | {} 66 | 67 | public: 68 | HFSM2_CONSTEXPR(14) bool operator != (const IteratorT& HFSM2_IF_ASSERT(other)) const noexcept { 69 | HFSM2_ASSERT(&_container == &other._container); 70 | 71 | return _cursor != _container.limit(); 72 | } 73 | 74 | HFSM2_CONSTEXPR(14) IteratorT& operator ++() noexcept { 75 | _cursor = _container.next(_cursor); 76 | 77 | return *this; 78 | } 79 | 80 | HFSM2_CONSTEXPR(11) const Item& operator *() const noexcept { return _container[_cursor]; } 81 | 82 | HFSM2_CONSTEXPR(11) const Item* operator->() const noexcept { return &operator *(); } 83 | 84 | private: 85 | const Container& _container; 86 | 87 | Index _cursor; 88 | }; 89 | 90 | //////////////////////////////////////////////////////////////////////////////// 91 | 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /development/hfsm2/detail/shared/macros_off.hpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | 3 | #if defined(__GNUC__) || defined(__GNUG__) 4 | #pragma GCC diagnostic pop 5 | #endif 6 | 7 | #ifdef __clang__ 8 | #pragma clang diagnostic pop 9 | #endif 10 | 11 | #if _MSC_VER == 1900 12 | #pragma warning(pop) 13 | #endif 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | #undef HFSM2_UNUSED 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | #undef HFSM2_ATTRIBUTE 22 | 23 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 24 | 25 | #undef HFSM2_ATTRIBUTE_FALLTHROUGH 26 | 27 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 28 | 29 | #undef HFSM2_ATTRIBUTE_NO_UNIQUE_ADDRESS 30 | 31 | //------------------------------------------------------------------------------ 32 | 33 | #undef HFSM2_CONSTEXPR 34 | 35 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 36 | 37 | #undef HFSM2_CONSTEXPR_NO 38 | 39 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 40 | 41 | #undef HFSM2_CONSTEXPR_11 42 | 43 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 44 | 45 | #undef HFSM2_CONSTEXPR_14 46 | 47 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 48 | 49 | #undef HFSM2_CONSTEXPR_17 50 | 51 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 52 | 53 | #undef HFSM2_CONSTEXPR_20 54 | 55 | //------------------------------------------------------------------------------ 56 | 57 | //#undef HFSM2_EMPTY_BASES 58 | 59 | //------------------------------------------------------------------------------ 60 | 61 | //#undef HFSM2_ARCHITECTURE 62 | //#undef HFSM2_ARCHITECTURE_64 63 | //#undef HFSM2_ARCHITECTURE_32 64 | #undef HFSM2_64BIT_OR_32BIT 65 | 66 | //------------------------------------------------------------------------------ 67 | 68 | //#undef HFSM2_BREAK 69 | #undef HFSM2_BREAK_AVAILABLE 70 | 71 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 72 | 73 | #undef HFSM2_IF_DEBUG 74 | #undef HFSM2_UNLESS_DEBUG 75 | #undef HFSM2_DEBUG_OR 76 | 77 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 78 | 79 | //#undef HFSM2_ASSERT_AVAILABLE 80 | #undef HFSM2_IF_ASSERT 81 | //#undef HFSM2_CHECKED 82 | #undef HFSM2_ASSERT 83 | #undef HFSM2_ASSERT_OR 84 | 85 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 86 | 87 | #undef HFSM2_EXPLICIT_MEMBER_SPECIALIZATION_AVAILABLE 88 | 89 | //////////////////////////////////////////////////////////////////////////////// 90 | //------------------------------------------------------------------------------ 91 | 92 | #undef HFSM2_IF_TYPEINDEX 93 | #undef HFSM2_TYPEINDEX_AVAILABLE 94 | #undef HFSM2_IF_TYPEINDEX 95 | 96 | //------------------------------------------------------------------------------ 97 | 98 | //#undef HFSM2_DEBUG_STATE_TYPE_AVAILABLE 99 | 100 | //------------------------------------------------------------------------------ 101 | 102 | #undef HFSM2_PLANS_AVAILABLE 103 | #undef HFSM2_IF_PLANS 104 | 105 | //------------------------------------------------------------------------------ 106 | 107 | #undef HFSM2_SERIALIZATION_AVAILABLE 108 | #undef HFSM2_IF_SERIALIZATION 109 | 110 | //------------------------------------------------------------------------------ 111 | 112 | #undef HFSM2_STRUCTURE_REPORT_AVAILABLE 113 | #undef HFSM2_IF_STRUCTURE_REPORT 114 | 115 | //------------------------------------------------------------------------------ 116 | 117 | #undef HFSM2_TRANSITION_HISTORY_AVAILABLE 118 | #undef HFSM2_IF_TRANSITION_HISTORY 119 | 120 | //------------------------------------------------------------------------------ 121 | 122 | #undef HFSM2_UTILITY_THEORY_AVAILABLE 123 | #undef HFSM2_IF_UTILITY_THEORY 124 | 125 | //////////////////////////////////////////////////////////////////////////////// 126 | 127 | #undef HFSM2_VERBOSE_DEBUG_LOG_AVAILABLE 128 | 129 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 130 | 131 | #undef HFSM2_LOG_INTERFACE_AVAILABLE 132 | #undef HFSM2_IF_LOG_INTERFACE 133 | 134 | #undef HFSM2_LOG_TRANSITION 135 | 136 | #ifdef HFSM2_ENABLE_PLANS 137 | #undef HFSM2_LOG_TASK_STATUS 138 | #undef HFSM2_LOG_PLAN_STATUS 139 | #endif 140 | 141 | #undef HFSM2_LOG_CANCELLED_PENDING 142 | 143 | #ifdef HFSM2_UTILITY_THEORY_AVAILABLE 144 | #undef HFSM2_LOG_UTILITY_RESOLUTION 145 | #undef HFSM2_LOG_RANDOM_RESOLUTION 146 | #endif 147 | 148 | #undef HFSM2_LOG_STATE_METHOD 149 | 150 | //////////////////////////////////////////////////////////////////////////////// 151 | -------------------------------------------------------------------------------- /development/hfsm2/detail/shared/type_list.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | // SPECIFIC 6 | 7 | template 8 | struct TL_ final { 9 | static constexpr Long SIZE = sizeof...(Ts); 10 | }; 11 | 12 | // SPECIFIC 13 | //------------------------------------------------------------------------------ 14 | 15 | template 16 | struct Const { 17 | static constexpr Long VALUE = N; 18 | }; 19 | 20 | //------------------------------------------------------------------------------ 21 | 22 | template 23 | struct PrependT; 24 | 25 | template 26 | struct PrependT> final { 27 | using Type = TL_; 28 | }; 29 | 30 | template 31 | using PrependTypes = typename PrependT::Type; 32 | 33 | //------------------------------------------------------------------------------ 34 | 35 | template 36 | struct MergeT; 37 | 38 | template 39 | struct MergeT, TL_> final { 40 | using Type = TL_; 41 | }; 42 | 43 | template 44 | using Merge = typename MergeT::Type; 45 | 46 | //------------------------------------------------------------------------------ 47 | 48 | template 49 | struct LowerT; 50 | 51 | template 52 | using LowerTypes = typename LowerT::Type; 53 | 54 | template 55 | struct LowerT final { 56 | using LTypeList = typename LowerT::Type; 57 | 58 | using Type = Conditional< 59 | (NIndex < NHalf), 60 | PrependTypes, 61 | LTypeList 62 | >; 63 | }; 64 | 65 | template 66 | struct LowerT final { 67 | using Type = TL_<>; 68 | }; 69 | 70 | template 71 | using LHalfTypes = LowerTypes; 72 | 73 | //------------------------------------------------------------------------------ 74 | 75 | template 76 | struct UpperT; 77 | 78 | template 79 | using UpperTypes = typename UpperT::Type; 80 | 81 | template 82 | struct UpperT final { 83 | using Type = Conditional< 84 | (NIndex < NHalf), 85 | UpperTypes, 86 | TL_ 87 | >; 88 | }; 89 | 90 | template 91 | struct UpperT final { 92 | using Type = TL_<>; 93 | }; 94 | 95 | template 96 | using RHalfTypes = UpperTypes; 97 | 98 | //------------------------------------------------------------------------------ 99 | 100 | template 101 | struct FindImpl 102 | : Const 103 | {}; 104 | 105 | template 106 | struct FindImpl 107 | : FindImpl 108 | {}; 109 | 110 | template 111 | struct FindImpl 112 | : Const 113 | {}; 114 | 115 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 116 | 117 | template 118 | struct Find; 119 | 120 | template 121 | struct Find, T> final 122 | : FindImpl<0, T, Ts...> 123 | {}; 124 | 125 | //////////////////////////////////////////////////////////////////////////////// 126 | // SPECIFIC 127 | 128 | } 129 | 130 | template 131 | constexpr Long index () noexcept { return detail::Find::VALUE; } 132 | 133 | template 134 | constexpr bool contains() noexcept { return index() != INVALID_LONG; } 135 | 136 | // SPECIFIC 137 | //------------------------------------------------------------------------------ 138 | 139 | } 140 | -------------------------------------------------------------------------------- /development/hfsm2/detail/structure/ancestors_1.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | struct A_; 8 | 9 | template 10 | using EmptyT = A_>; 11 | 12 | //------------------------------------------------------------------------------ 13 | 14 | template 15 | struct HFSM2_EMPTY_BASES A_ 16 | : TFirst 17 | , A_ 18 | { 19 | using First = TFirst; 20 | using typename First::Context; 21 | 22 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 23 | using typename First::Rank; 24 | using typename First::Utility; 25 | #endif 26 | 27 | using typename First::StateList; 28 | using typename First::RegionList; 29 | 30 | using typename First::ConstControl; 31 | using typename First::Control; 32 | using typename First::PlanControl; 33 | 34 | #if HFSM2_PLANS_AVAILABLE() 35 | using typename First::Plan; 36 | #endif 37 | 38 | using typename First::FullControl; 39 | using typename First::GuardControl; 40 | using typename First::EventControl; 41 | 42 | using First::stateId; 43 | using First::regionId; 44 | 45 | using Rest = A_; 46 | 47 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 48 | 49 | HFSM2_CONSTEXPR(14) void wideEntryGuard(GuardControl& control) noexcept; 50 | 51 | HFSM2_CONSTEXPR(14) void wideEnter ( PlanControl& control) noexcept; 52 | HFSM2_CONSTEXPR(14) void wideReenter ( PlanControl& control) noexcept; 53 | 54 | HFSM2_CONSTEXPR(14) void widePreUpdate ( FullControl& control) noexcept; 55 | HFSM2_CONSTEXPR(14) void wideUpdate ( FullControl& control) noexcept; 56 | HFSM2_CONSTEXPR(14) void widePostUpdate( FullControl& control) noexcept; 57 | 58 | template 59 | HFSM2_CONSTEXPR(14) void widePreReact (const TEvent& event , 60 | EventControl& control) noexcept; 61 | 62 | template 63 | HFSM2_CONSTEXPR(14) void wideReact (const TEvent& event , 64 | EventControl& control) noexcept; 65 | 66 | template 67 | HFSM2_CONSTEXPR(14) void widePostReact (const TEvent& event , 68 | EventControl& control) noexcept; 69 | 70 | template 71 | HFSM2_CONSTEXPR(14) void wideQuery ( TEvent& event , 72 | ConstControl& control) const noexcept; 73 | 74 | HFSM2_CONSTEXPR(14) void wideExitGuard (GuardControl& control) noexcept; 75 | 76 | HFSM2_CONSTEXPR(14) void wideExit ( PlanControl& control) noexcept; 77 | 78 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 79 | }; 80 | 81 | //////////////////////////////////////////////////////////////////////////////// 82 | 83 | } 84 | } 85 | 86 | #include "ancestors_1.inl" 87 | -------------------------------------------------------------------------------- /development/hfsm2/detail/structure/ancestors_1.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | HFSM2_CONSTEXPR(14) 8 | void 9 | A_::wideEntryGuard(GuardControl& control) noexcept { 10 | First:: entryGuard(control); 11 | Rest ::wideEntryGuard(control); 12 | } 13 | 14 | //------------------------------------------------------------------------------ 15 | 16 | template 17 | HFSM2_CONSTEXPR(14) 18 | void 19 | A_::wideEnter(PlanControl& control) noexcept { 20 | First:: enter(control); 21 | Rest ::wideEnter(control); 22 | } 23 | 24 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 25 | 26 | template 27 | HFSM2_CONSTEXPR(14) 28 | void 29 | A_::wideReenter(PlanControl& control) noexcept { 30 | First:: reenter(control); 31 | Rest ::wideReenter(control); 32 | } 33 | 34 | //------------------------------------------------------------------------------ 35 | 36 | template 37 | HFSM2_CONSTEXPR(14) 38 | void 39 | A_::widePreUpdate(FullControl& control) noexcept { 40 | First:: preUpdate(control); 41 | Rest ::widePreUpdate(control); 42 | } 43 | 44 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 45 | 46 | template 47 | HFSM2_CONSTEXPR(14) 48 | void 49 | A_::wideUpdate(FullControl& control) noexcept { 50 | First:: update(control); 51 | Rest ::wideUpdate(control); 52 | } 53 | 54 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 55 | 56 | template 57 | HFSM2_CONSTEXPR(14) 58 | void 59 | A_::widePostUpdate(FullControl& control) noexcept { 60 | Rest ::widePostUpdate(control); 61 | First:: postUpdate(control); 62 | } 63 | 64 | //------------------------------------------------------------------------------ 65 | 66 | template 67 | template 68 | HFSM2_CONSTEXPR(14) 69 | void 70 | A_::widePreReact(const TEvent& event, 71 | EventControl& control) noexcept 72 | { 73 | First:: preReact(event, control); 74 | Rest ::widePreReact(event, control); 75 | } 76 | 77 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 78 | 79 | template 80 | template 81 | HFSM2_CONSTEXPR(14) 82 | void 83 | A_::wideReact(const TEvent& event, 84 | EventControl& control) noexcept 85 | { 86 | First:: react(event, control); 87 | Rest ::wideReact(event, control); 88 | } 89 | 90 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 91 | 92 | template 93 | template 94 | HFSM2_CONSTEXPR(14) 95 | void 96 | A_::widePostReact(const TEvent& event, 97 | EventControl& control) noexcept 98 | { 99 | Rest ::widePostReact(event, control); 100 | First:: postReact(event, control); 101 | } 102 | 103 | //------------------------------------------------------------------------------ 104 | 105 | template 106 | template 107 | HFSM2_CONSTEXPR(14) 108 | void 109 | A_::wideQuery(TEvent& event, 110 | ConstControl& control) const noexcept 111 | { 112 | First:: query(event, control); 113 | Rest ::wideQuery(event, control); 114 | } 115 | 116 | //------------------------------------------------------------------------------ 117 | 118 | template 119 | HFSM2_CONSTEXPR(14) 120 | void 121 | A_::wideExitGuard(GuardControl& control) noexcept { 122 | Rest ::wideExitGuard(control); 123 | First:: exitGuard(control); 124 | } 125 | 126 | //------------------------------------------------------------------------------ 127 | 128 | template 129 | HFSM2_CONSTEXPR(14) 130 | void 131 | A_::wideExit(PlanControl& control) noexcept { 132 | Rest ::wideExit(control); 133 | First:: exit(control); 134 | } 135 | 136 | //////////////////////////////////////////////////////////////////////////////// 137 | 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /development/hfsm2/detail/structure/ancestors_2.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | struct HFSM2_EMPTY_BASES A_ 8 | : TFirst 9 | { 10 | using First = TFirst; 11 | using typename First::Context; 12 | 13 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 14 | using typename First::Rank; 15 | using typename First::Utility; 16 | #endif 17 | 18 | using typename First::StateList; 19 | using typename First::RegionList; 20 | 21 | using typename First::Payload; 22 | using typename First::Transition; 23 | 24 | using typename First::ConstControl; 25 | using typename First::Control; 26 | using typename First::PlanControl; 27 | 28 | #if HFSM2_PLANS_AVAILABLE() 29 | using typename First::Plan; 30 | #endif 31 | 32 | using typename First::FullControl; 33 | using typename First::GuardControl; 34 | using typename First::EventControl; 35 | 36 | using First::stateId; 37 | using First::regionId; 38 | 39 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 40 | 41 | HFSM2_CONSTEXPR(14) Prong select (const Control& ) noexcept { return 0; } 42 | 43 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 44 | HFSM2_CONSTEXPR(14) Rank rank (const Control& ) noexcept { return Rank {0}; } 45 | HFSM2_CONSTEXPR(14) Utility utility (const Control& ) noexcept { return Utility{1}; } 46 | #endif 47 | 48 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 49 | 50 | HFSM2_CONSTEXPR(14) void entryGuard (GuardControl& ) noexcept {} 51 | 52 | HFSM2_CONSTEXPR(14) void enter ( PlanControl& ) noexcept {} 53 | HFSM2_CONSTEXPR(14) void reenter ( PlanControl& ) noexcept {} 54 | 55 | HFSM2_CONSTEXPR(14) void preUpdate ( FullControl& ) noexcept {} 56 | HFSM2_CONSTEXPR(14) void update ( FullControl& ) noexcept {} 57 | HFSM2_CONSTEXPR(14) void postUpdate ( FullControl& ) noexcept {} 58 | 59 | template 60 | HFSM2_CONSTEXPR(14) void preReact (const TEvent& , 61 | EventControl& ) noexcept {} 62 | 63 | template 64 | HFSM2_CONSTEXPR(14) void react (const TEvent& , 65 | EventControl& ) noexcept {} 66 | 67 | template 68 | HFSM2_CONSTEXPR(14) void postReact (const TEvent& , 69 | EventControl& ) noexcept {} 70 | 71 | template 72 | HFSM2_CONSTEXPR(14) void query ( TEvent& , 73 | ConstControl& ) const noexcept {} 74 | 75 | HFSM2_CONSTEXPR(14) void exitGuard (GuardControl& ) noexcept {} 76 | 77 | HFSM2_CONSTEXPR(14) void exit ( PlanControl& ) noexcept {} 78 | 79 | #if HFSM2_PLANS_AVAILABLE() 80 | HFSM2_CONSTEXPR(14) void planSucceeded ( FullControl& control) noexcept; 81 | HFSM2_CONSTEXPR(14) void planFailed ( FullControl& control) noexcept; 82 | #endif 83 | 84 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 85 | 86 | HFSM2_CONSTEXPR(14) void wideEntryGuard(GuardControl& control) noexcept; 87 | 88 | HFSM2_CONSTEXPR(14) void wideEnter ( PlanControl& control) noexcept; 89 | HFSM2_CONSTEXPR(14) void wideReenter ( PlanControl& control) noexcept; 90 | 91 | HFSM2_CONSTEXPR(14) void widePreUpdate ( FullControl& control) noexcept; 92 | HFSM2_CONSTEXPR(14) void wideUpdate ( FullControl& control) noexcept; 93 | HFSM2_CONSTEXPR(14) void widePostUpdate( FullControl& control) noexcept; 94 | 95 | template 96 | HFSM2_CONSTEXPR(14) void widePreReact (const TEvent& event , 97 | EventControl& control) noexcept; 98 | 99 | template 100 | HFSM2_CONSTEXPR(14) void wideReact (const TEvent& event , 101 | EventControl& control) noexcept; 102 | 103 | template 104 | HFSM2_CONSTEXPR(14) void widePostReact (const TEvent& event , 105 | EventControl& control) noexcept; 106 | 107 | template 108 | HFSM2_CONSTEXPR(14) void wideQuery ( TEvent& event , 109 | ConstControl& control) const noexcept; 110 | 111 | HFSM2_CONSTEXPR(14) void wideExitGuard (GuardControl& control) noexcept; 112 | 113 | HFSM2_CONSTEXPR(14) void wideExit ( PlanControl& control) noexcept; 114 | 115 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 116 | }; 117 | 118 | //////////////////////////////////////////////////////////////////////////////// 119 | 120 | } 121 | } 122 | 123 | #include "ancestors_2.inl" 124 | -------------------------------------------------------------------------------- /development/hfsm2/detail/structure/ancestors_2.inl: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | #if HFSM2_PLANS_AVAILABLE() 7 | 8 | template 9 | HFSM2_CONSTEXPR(14) 10 | void 11 | A_::planSucceeded(FullControl& control) noexcept { 12 | control.succeed(); 13 | } 14 | 15 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 16 | 17 | template 18 | HFSM2_CONSTEXPR(14) 19 | void 20 | A_::planFailed(FullControl& control) noexcept { 21 | control.fail(); 22 | } 23 | 24 | #endif 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | template 29 | HFSM2_CONSTEXPR(14) 30 | void 31 | A_::wideEntryGuard(GuardControl& control) noexcept { 32 | First:: entryGuard(control); 33 | } 34 | 35 | //------------------------------------------------------------------------------ 36 | 37 | template 38 | HFSM2_CONSTEXPR(14) 39 | void 40 | A_::wideEnter(PlanControl& control) noexcept { 41 | First:: enter(control); 42 | } 43 | 44 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 45 | 46 | template 47 | HFSM2_CONSTEXPR(14) 48 | void 49 | A_::wideReenter(PlanControl& control) noexcept { 50 | First:: reenter(control); 51 | } 52 | 53 | //------------------------------------------------------------------------------ 54 | 55 | template 56 | HFSM2_CONSTEXPR(14) 57 | void 58 | A_::widePreUpdate(FullControl& control) noexcept { 59 | First:: preUpdate(control); 60 | } 61 | 62 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 63 | 64 | template 65 | HFSM2_CONSTEXPR(14) 66 | void 67 | A_::wideUpdate(FullControl& control) noexcept { 68 | First:: update(control); 69 | } 70 | 71 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 72 | 73 | template 74 | HFSM2_CONSTEXPR(14) 75 | void 76 | A_::widePostUpdate(FullControl& control) noexcept { 77 | First:: postUpdate(control); 78 | } 79 | 80 | //------------------------------------------------------------------------------ 81 | 82 | template 83 | template 84 | HFSM2_CONSTEXPR(14) 85 | void 86 | A_::widePreReact(const TEvent& event, 87 | EventControl& control) noexcept 88 | { 89 | First:: preReact(event, control); 90 | } 91 | 92 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 93 | 94 | template 95 | template 96 | HFSM2_CONSTEXPR(14) 97 | void 98 | A_::wideReact(const TEvent& event, 99 | EventControl& control) noexcept 100 | { 101 | First:: react(event, control); 102 | } 103 | 104 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 105 | 106 | template 107 | template 108 | HFSM2_CONSTEXPR(14) 109 | void 110 | A_::widePostReact(const TEvent& event, 111 | EventControl& control) noexcept 112 | { 113 | First:: postReact(event, control); 114 | } 115 | 116 | //------------------------------------------------------------------------------ 117 | 118 | template 119 | template 120 | HFSM2_CONSTEXPR(14) 121 | void 122 | A_::wideQuery(TEvent& event, 123 | ConstControl& control) const noexcept 124 | { 125 | First:: query(event, control); 126 | } 127 | 128 | //------------------------------------------------------------------------------ 129 | 130 | template 131 | HFSM2_CONSTEXPR(14) 132 | void 133 | A_::wideExitGuard(GuardControl& control) noexcept { 134 | First:: exitGuard(control); 135 | } 136 | 137 | //------------------------------------------------------------------------------ 138 | 139 | template 140 | HFSM2_CONSTEXPR(14) 141 | void 142 | A_::wideExit(PlanControl& control) noexcept { 143 | First:: exit(control); 144 | } 145 | 146 | //////////////////////////////////////////////////////////////////////////////// 147 | 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /development/hfsm2/detail/structure/base.hpp: -------------------------------------------------------------------------------- 1 | namespace hfsm2 { 2 | namespace detail { 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | template 7 | class B_ { 8 | template 9 | friend struct A_; 10 | 11 | protected: 12 | using Context = typename TArgs::Context; 13 | 14 | using Short = ::hfsm2::Short; 15 | using Prong = ::hfsm2::Prong; 16 | 17 | #if HFSM2_UTILITY_THEORY_AVAILABLE() 18 | using Rank = typename TArgs::Rank; 19 | using Utility = typename TArgs::Utility; 20 | #endif 21 | 22 | using StateList = typename TArgs::StateList; 23 | using RegionList = typename TArgs::RegionList; 24 | 25 | using Payload = typename TArgs::Payload; 26 | using Transition = TransitionT; 27 | 28 | using ConstControl = ConstControlT; 29 | using Control = ControlT ; 30 | using PlanControl = PlanControlT ; 31 | using FullControl = FullControlT ; 32 | using GuardControl = GuardControlT; 33 | using EventControl = EventControlT; 34 | 35 | #if HFSM2_PLANS_AVAILABLE() 36 | using Plan = PayloadPlanT ; 37 | #endif 38 | 39 | public: 40 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 41 | 42 | HFSM2_CONSTEXPR(14) void entryGuard (GuardControl& ) noexcept {} 43 | 44 | HFSM2_CONSTEXPR(14) void enter ( PlanControl& ) noexcept {} 45 | HFSM2_CONSTEXPR(14) void reenter ( PlanControl& ) noexcept {} 46 | 47 | HFSM2_CONSTEXPR(14) void preUpdate ( FullControl& ) noexcept {} 48 | HFSM2_CONSTEXPR(14) void update ( FullControl& ) noexcept {} 49 | HFSM2_CONSTEXPR(14) void postUpdate ( FullControl& ) noexcept {} 50 | 51 | template 52 | HFSM2_CONSTEXPR(14) void preReact (const TEvent& , 53 | EventControl& ) noexcept {} 54 | 55 | template 56 | HFSM2_CONSTEXPR(14) void react (const TEvent& , 57 | EventControl& ) noexcept {} 58 | 59 | template 60 | HFSM2_CONSTEXPR(14) void postReact (const TEvent& , 61 | EventControl& ) noexcept {} 62 | 63 | template 64 | HFSM2_CONSTEXPR(14) void query ( TEvent& , 65 | ConstControl& ) const noexcept {} 66 | 67 | HFSM2_CONSTEXPR(14) void exitGuard (GuardControl& ) noexcept {} 68 | 69 | HFSM2_CONSTEXPR(14) void exit ( PlanControl& ) noexcept {} 70 | 71 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 72 | 73 | template 74 | static 75 | HFSM2_CONSTEXPR(11) StateID stateId() noexcept { return index() ; } 76 | 77 | template 78 | static 79 | HFSM2_CONSTEXPR(11) RegionID regionId() noexcept { return static_cast(index()); } 80 | }; 81 | 82 | //////////////////////////////////////////////////////////////////////////////// 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /development/hfsm2/machine_dev.hpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // 2.7.1 (2025-05-27) 3 | // 4 | // Created by Andrew Gresyk 5 | // 6 | // Licensed under the MIT License; 7 | // you may not use this file except in compliance with the License. 8 | // 9 | // 10 | // MIT License 11 | // 12 | // Copyright (c) 2025 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #pragma once 33 | 34 | #define HFSM2_VERSION_MAJOR 2 35 | #define HFSM2_VERSION_MINOR 7 36 | #define HFSM2_VERSION_PATCH 1 37 | 38 | #define HFSM2_VERSION (10000 * HFSM2_VERSION_MAJOR + 100 * HFSM2_VERSION_MINOR + HFSM2_VERSION_PATCH) 39 | 40 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 41 | 42 | #include // uint32_t, uint64_t 43 | #include // memcpy_s() 44 | 45 | #include 46 | #ifndef HFSM2_DISABLE_TYPEINDEX 47 | #include 48 | #endif 49 | 50 | #if defined _DEBUG && _MSC_VER 51 | #include // __debugbreak() 52 | #endif 53 | 54 | //------------------------------------------------------------------------------ 55 | 56 | #include "detail/shared/macros_on.hpp" 57 | 58 | #include "detail/shared/utility.hpp" 59 | #include "detail/shared/iterator.hpp" 60 | #include "detail/shared/bit_stream.hpp" 61 | #include "detail/shared/random.hpp" 62 | #include "detail/shared/type_list.hpp" 63 | 64 | #include "detail/containers/array.hpp" 65 | #include "detail/containers/bit_array.hpp" 66 | 67 | #include "detail/features/transition.hpp" 68 | #include "detail/features/logger_interface.hpp" 69 | #include "detail/features/structure_report.hpp" 70 | #include "detail/features/task.hpp" 71 | #include "detail/features/task_list.hpp" 72 | 73 | #include "detail/root/registry.hpp" 74 | #include "detail/root/plan_data.hpp" 75 | #include "detail/root/plan_0.hpp" 76 | #include "detail/root/plan_1.hpp" 77 | #include "detail/root/plan_2.hpp" 78 | #include "detail/root/core.hpp" 79 | #include "detail/root/control_0.hpp" 80 | #include "detail/root/control_1.hpp" 81 | #include "detail/root/control_2.hpp" 82 | #include "detail/root/control_3.hpp" 83 | #include "detail/root/control_4.hpp" 84 | #include "detail/root/control_5.hpp" 85 | 86 | #include "detail/structure/base.hpp" 87 | #include "detail/structure/ancestors_1.hpp" 88 | #include "detail/structure/ancestors_2.hpp" 89 | #include "detail/structure/state_1.hpp" 90 | #include "detail/structure/state_2.hpp" 91 | #include "detail/structure/forward.hpp" 92 | #include "detail/structure/reactions.inl" 93 | #include "detail/structure/composite_sub_1.hpp" 94 | #include "detail/structure/composite_sub_2.hpp" 95 | #include "detail/structure/composite.hpp" 96 | #include "detail/structure/orthogonal_sub_1.hpp" 97 | #include "detail/structure/orthogonal_sub_2.hpp" 98 | #include "detail/structure/orthogonal.hpp" 99 | 100 | #include "detail/config.hpp" 101 | #include "detail/root_0.hpp" 102 | #include "detail/root_1.hpp" 103 | #include "detail/root_2.hpp" 104 | #include "detail/root_3.hpp" 105 | #include "detail/root_4.hpp" 106 | 107 | #include "detail/shared/macros_off.hpp" 108 | -------------------------------------------------------------------------------- /examples/advanced_event_handling/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | get_filename_component(EXAMPLE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | project(${EXAMPLE_NAME}_example) 5 | 6 | file(GLOB SOURCE_FILES "*.cpp") 7 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 8 | 9 | target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) 10 | 11 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11) 12 | 13 | if(MSVC) 14 | target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) 15 | else() 16 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples/basic_audio_player/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | get_filename_component(EXAMPLE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | project(${EXAMPLE_NAME}_example) 5 | 6 | file(GLOB SOURCE_FILES "*.cpp") 7 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 8 | 9 | target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) 10 | 11 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11) 12 | 13 | if(MSVC) 14 | target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) 15 | else() 16 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples/basic_audio_player/main.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | // 4 | // An HFSM2 port of https://gist.github.com/martinmoene/797b1923f9c6c1ae355bb2d6870be25e 5 | // by Martin Moene (see https://twitter.com/MartinMoene/status/1118453128834232320) 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #define HFSM2_ENABLE_LOG_INTERFACE 13 | #define HFSM2_ENABLE_STRUCTURE_REPORT 14 | #include 15 | 16 | //------------------------------------------------------------------------------ 17 | 18 | // events 19 | struct Play { std::string title; }; 20 | struct Pause {}; 21 | struct Resume {}; 22 | struct Stop {}; 23 | 24 | // shared data stored externally to the fsm 25 | using Context = std::string; 26 | using M = hfsm2::MachineT>; 27 | 28 | #if 0 29 | 30 | // states need to be forward declared to be used in FSM struct declaration 31 | struct Idle; 32 | struct Playing; 33 | struct Paused; 34 | 35 | using FSM = M::PeerRoot< 36 | Idle, 37 | Playing, 38 | Paused 39 | >; 40 | 41 | #else 42 | 43 | // alternatively, some macro magic can be invoked to simplify FSM structure declaration 44 | #define S(s) struct s 45 | 46 | using FSM = M::PeerRoot< 47 | S(Idle), 48 | S(Playing), 49 | S(Paused) 50 | >; 51 | 52 | #undef S 53 | 54 | #endif 55 | 56 | //------------------------------------------------------------------------------ 57 | 58 | // double-check state ids for Logger::stateName() 59 | static_assert(FSM::stateId() == 1, ""); 60 | static_assert(FSM::stateId() == 2, ""); 61 | static_assert(FSM::stateId() == 3, ""); 62 | 63 | // custom logger for recording all transitions 64 | struct Logger 65 | : M::LoggerInterface 66 | { 67 | static const char* stateName(const StateID stateId) { 68 | switch (stateId) { 69 | case 1: 70 | return "Idle"; 71 | case 2: 72 | return "Playing"; 73 | case 3: 74 | return "Paused"; 75 | default: 76 | assert(false); 77 | return ""; 78 | } 79 | } 80 | 81 | void recordTransition(const Context& /*context*/, 82 | const StateID origin, 83 | const TransitionType /*transition*/, 84 | const StateID target) override 85 | { 86 | std::cout << stateName(origin) << " -> " << stateName(target) << "\n"; 87 | } 88 | }; 89 | 90 | //------------------------------------------------------------------------------ 91 | 92 | // state helper for error reporting 93 | struct Base 94 | : FSM::State 95 | { 96 | template 97 | void react(const Event&, EventControl&) { 98 | std::cout << "[unsupported transition]\n"; 99 | } 100 | }; 101 | 102 | // states 103 | struct Idle 104 | : Base 105 | { 106 | using Base::react; 107 | 108 | void react(const Play& event, EventControl& control) { 109 | control.context() = event.title; 110 | control.changeTo(); 111 | } 112 | }; 113 | 114 | struct Playing 115 | : Base 116 | { 117 | using Base::react; 118 | 119 | void react(const Pause&, EventControl& control) { 120 | control.changeTo(); 121 | } 122 | 123 | void react(const Stop&, EventControl& control) { 124 | control.changeTo(); 125 | } 126 | }; 127 | 128 | struct Paused 129 | : Base 130 | { 131 | using Base::react; 132 | 133 | void react(const Resume&, EventControl& control) { 134 | control.changeTo(); 135 | } 136 | 137 | void react(const Stop&, EventControl& control) { 138 | control.changeTo(); 139 | } 140 | }; 141 | 142 | //------------------------------------------------------------------------------ 143 | 144 | int main() { 145 | // construct everything 146 | Context title; 147 | Logger logger; 148 | FSM::Instance machine(title, &logger); 149 | 150 | // do the work :) 151 | machine.react(Play{"any"}); // Idle -> Playing 152 | machine.react(Stop{}); // Playing -> Idle 153 | 154 | machine.react(Play{"optional"}); // Idle -> Playing 155 | machine.react(Pause{}); // Playing -> Paused 156 | machine.react(Stop{}); // Paused -> Idle 157 | 158 | machine.react(Play{"variant"}); // Idle -> Playing 159 | machine.react(Pause{}); // Playing -> Paused 160 | machine.react(Resume{}); // Paused -> Playing 161 | machine.react(Stop{}); // Playing -> Idle 162 | 163 | machine.react(Pause{}); // [unsupported transition] 164 | machine.react(Resume{}); // [unsupported transition] 165 | machine.react(Stop{}); // [unsupported transition] 166 | 167 | return 0; 168 | } 169 | 170 | //------------------------------------------------------------------------------ 171 | -------------------------------------------------------------------------------- /examples/basic_traffic_light/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | get_filename_component(EXAMPLE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | project(${EXAMPLE_NAME}_example) 5 | 6 | file(GLOB SOURCE_FILES "*.cpp") 7 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 8 | 9 | target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) 10 | 11 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11) 12 | 13 | if(MSVC) 14 | target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) 15 | else() 16 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples/basic_traffic_light/main.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | // 4 | // Traffic light example: 5 | // Cycle between R-Y-G-Y-B three times, then turn off 6 | 7 | // State structure: 8 | // 9 | // Root 10 | // ├ On 11 | // │ ├ Red 12 | // │ ├ YellowDownwards 13 | // │ ├ YellowUpwards 14 | // │ └ Green 15 | // └ Off 16 | 17 | // Output: 18 | // 19 | // On 20 | // Red 21 | // Yellow v 22 | // Green 23 | // Yellow ^ 24 | // Red 25 | // Yellow v 26 | // Green 27 | // Yellow ^ 28 | // Red 29 | // Yellow v 30 | // Green 31 | // Yellow ^ 32 | // Red 33 | // Off 34 | 35 | // optional: enable FSM structure report in debugger 36 | #define HFSM2_ENABLE_STRUCTURE_REPORT 37 | #include 38 | 39 | #include 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | // data shared between FSM states and outside code 44 | struct Context { 45 | unsigned cycleCount = 0; 46 | }; 47 | 48 | // convenience typedef 49 | using M = hfsm2::MachineT>; 50 | 51 | #if 0 52 | 53 | // states need to be forward declared to be used in FSM struct declaration 54 | struct On; 55 | struct Red; 56 | struct YellowDownwards; 57 | struct YellowUpwards; 58 | struct Green; 59 | struct Off; 60 | 61 | using FSM = M::PeerRoot< 62 | // sub-machine .. 63 | M::Composite, 70 | Off 71 | >; 72 | 73 | #else 74 | 75 | // alternatively, some macro magic can be invoked to simplify FSM structure declaration 76 | #define S(s) struct s 77 | 78 | // state machine structure 79 | using FSM = M::PeerRoot< 80 | // sub-machine .. 81 | M::Composite, 88 | S(Off) 89 | >; 90 | 91 | #undef S 92 | 93 | #endif 94 | 95 | //------------------------------------------------------------------------------ 96 | 97 | static_assert(FSM::regionId() == 1, ""); 98 | 99 | static_assert(FSM::stateId() == 1, ""); 100 | static_assert(FSM::stateId() == 2, ""); 101 | static_assert(FSM::stateId() == 3, ""); 102 | static_assert(FSM::stateId() == 4, ""); 103 | static_assert(FSM::stateId() == 5, ""); 104 | static_assert(FSM::stateId() == 6, ""); 105 | 106 | //////////////////////////////////////////////////////////////////////////////// 107 | 108 | // top-level region in the hierarchy 109 | struct On 110 | : FSM::State // necessary boilerplate! 111 | { 112 | // called on state entry 113 | void enter(Control& control) { 114 | control.context().cycleCount = 0; 115 | std::cout << "On" << std::endl; 116 | } 117 | }; 118 | 119 | //------------------------------------------------------------------------------ 120 | 121 | // sub-states 122 | struct Red 123 | : FSM::State 124 | { 125 | void enter(Control& control) { 126 | ++control.context().cycleCount; 127 | std::cout << " Red" << std::endl; 128 | } 129 | 130 | // state can initiate transitions to _any_ other state 131 | void update(FullControl& control) { 132 | // multiple transitions can be initiated, can be useful in a hierarchy 133 | if (control.context().cycleCount > 3) 134 | control.changeTo(); 135 | else 136 | control.changeTo(); 137 | } 138 | }; 139 | 140 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 141 | 142 | struct YellowDownwards 143 | : FSM::State 144 | { 145 | void enter(Control&) { 146 | std::cout << " Yellow v" << std::endl; 147 | } 148 | 149 | void update(FullControl& control) { 150 | control.changeTo(); 151 | } 152 | }; 153 | 154 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 155 | 156 | struct YellowUpwards 157 | : FSM::State 158 | { 159 | void enter(Control&) { 160 | std::cout << " Yellow ^" << std::endl; 161 | } 162 | 163 | void update(FullControl& control) { 164 | control.changeTo(); 165 | } 166 | }; 167 | 168 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 169 | 170 | struct Green 171 | : FSM::State 172 | { 173 | void enter(Control&) { 174 | std::cout << " Green" << std::endl; 175 | } 176 | 177 | void update(FullControl& control) { 178 | control.changeTo(); 179 | } 180 | }; 181 | 182 | //------------------------------------------------------------------------------ 183 | 184 | // another top-level state 185 | struct Off 186 | : FSM::State 187 | { 188 | void enter(Control&) { 189 | std::cout << "Off" << std::endl; 190 | } 191 | }; 192 | 193 | //////////////////////////////////////////////////////////////////////////////// 194 | 195 | int main() { 196 | // shared data storage instance 197 | Context context; 198 | 199 | FSM::Instance machine{context}; 200 | 201 | while (machine.isActive() == false) 202 | machine.update(); 203 | 204 | return 0; 205 | } 206 | 207 | //////////////////////////////////////////////////////////////////////////////// 208 | -------------------------------------------------------------------------------- /examples/calculator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | get_filename_component(EXAMPLE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | project(${EXAMPLE_NAME}_example) 5 | 6 | file(GLOB SOURCE_FILES "*.cpp") 7 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 8 | 9 | target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) 10 | 11 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) 12 | 13 | if(MSVC) 14 | target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) 15 | else() 16 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples/debug_logger_interface/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | get_filename_component(EXAMPLE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | project(${EXAMPLE_NAME}_example) 5 | 6 | file(GLOB SOURCE_FILES "*.cpp") 7 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 8 | 9 | target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) 10 | 11 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11) 12 | 13 | if(MSVC) 14 | target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) 15 | else() 16 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples/temp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | get_filename_component(EXAMPLE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | project(${EXAMPLE_NAME}_example) 5 | 6 | file(GLOB SOURCE_FILES "*.cpp") 7 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 8 | 9 | target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) 10 | 11 | target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) 12 | 13 | if(MSVC) 14 | target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) 15 | else() 16 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples/temp/main.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | //////////////////////////////////////////////////////////////////////////////// 5 | 6 | int main() { 7 | return 0; 8 | } 9 | 10 | //////////////////////////////////////////////////////////////////////////////// 11 | -------------------------------------------------------------------------------- /premake.cmd: -------------------------------------------------------------------------------- 1 | premake5.exe --file=premake.lua vs2022 2 | -------------------------------------------------------------------------------- /projects/code-lite/hfsm2.workspace: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/code-lite/test/tags: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrew-gresyk/HFSM2/1004a814fcd73673d9ed9528867b7a7cc908ba1a/projects/code-lite/test/tags -------------------------------------------------------------------------------- /projects/premake/snippets-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/snippets-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/snippets-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/snippets-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/snippets-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/temp-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/temp-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/temp-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/temp-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/temp-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/premake/tools.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 2347027e-e5de-43c4-8ef9-5f1411ade33b 6 | . 7 | ..\..\tools\join.py 8 | 9 | 10 | ../../tools 11 | Global|PythonCore|3.9 12 | Standard Python launcher 13 | . 14 | HFSM-tools 15 | HFSM-tools 16 | False 17 | False 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | true 25 | false 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /projects/visual-studio/advanced_event_handling-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/advanced_event_handling-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/advanced_event_handling-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/advanced_event_handling-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/advanced_event_handling-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_audio_player-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_audio_player-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_audio_player-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_audio_player-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_audio_player-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_traffic_light-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_traffic_light-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_traffic_light-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_traffic_light-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/basic_traffic_light-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/calculator-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/calculator-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/calculator-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/calculator-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/calculator-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/debug_logger_interface-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/debug_logger_interface-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/debug_logger_interface-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/debug_logger_interface-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/debug_logger_interface-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {f36e39b3-d6a6-4d9f-be7c-7081167a0b62} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /projects/visual-studio/doctest.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | $(SolutionDir)../../external;%(AdditionalIncludeDirectories) 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /projects/visual-studio/shared-clang-debug.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DebugFull 9 | 10 | 11 | -------------------------------------------------------------------------------- /projects/visual-studio/shared-clang-release.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | false 9 | 10 | 11 | -------------------------------------------------------------------------------- /projects/visual-studio/shared-clang.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -Wshadow -Wold-style-cast -Wpedantic %(AdditionalOptions) 9 | false 10 | 11 | 12 | Default 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/visual-studio/shared-vs-14.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/visual-studio/shared-vs-15.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | /permissive- 10 | stdcpp14 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /projects/visual-studio/shared-vs.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(SolutionDir)..\..\binaries-$(PlatformTarget)\ 6 | $(BUILD_ROOT)\$(SolutionName)-$(PlatformTarget)\$(ProjectName)-$(Configuration)\ 7 | $(ProjectName)-$(Configuration)-$(PlatformTarget) 8 | 9 | 10 | 11 | $(SolutionDir)../../development;$(SolutionDir)../../include;%(AdditionalIncludeDirectories) 12 | Level4 13 | true 14 | _UNICODE;UNICODE;_CONSOLE;%(PreprocessorDefinitions) 15 | 16 | 17 | Console 18 | 19 | 20 | -------------------------------------------------------------------------------- /projects/visual-studio/temp-14.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/temp-15.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/temp-16.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/temp-17.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/temp-clang.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/visual-studio/tools.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 2347027e-e5de-43c4-8ef9-5f1411ade33b 6 | . 7 | ..\..\tools\join.py 8 | 9 | 10 | ../../tools 11 | Global|PythonCore|3.9 12 | Standard Python launcher 13 | . 14 | HFSM-tools 15 | HFSM-tools 16 | False 17 | False 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | true 25 | false 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /projects/visual-studio/vs-flags.txt: -------------------------------------------------------------------------------- 1 | /d1reportAllClassLayout 2 | /d1reportSingleClassLayoutNAME 3 | 4 | /Bt 5 | 6 | /d2cgsummary (compiler) 7 | /d2:-cgsummary (linker) 8 | 9 | /cgthreads# 10 | 11 | /d2FuncCache# (compiler) 12 | /d2:-FuncCache# (linker) 13 | 14 | /d2:-notypeopt (linker) -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 5 | #include 6 | 7 | #define HFSM2_ENABLE_ALL 8 | -------------------------------------------------------------------------------- /test/reported/issue_49.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | // Issue reported in https://github.com/andrew-gresyk/HFSM2/issues/49 5 | 6 | #define HFSM2_ENABLE_PLANS 7 | #include 8 | 9 | #include 10 | 11 | using Config = hfsm2::Config 12 | ::TaskCapacityN<3>; 13 | 14 | using M = hfsm2::MachineT; 15 | 16 | using FSM = M::PeerRoot< 17 | struct Disabled, 18 | M::Composite, 25 | struct Idle 26 | > 27 | >; 28 | 29 | // Events 30 | struct Enable {}; 31 | struct Disable {}; 32 | 33 | struct Disabled : FSM::State 34 | { 35 | void update(FullControl& control) 36 | { 37 | control.changeTo(); 38 | } 39 | 40 | void react(const Enable&, EventControl& control) 41 | { 42 | control.changeTo(); 43 | } 44 | 45 | using FSM::State::react; 46 | }; 47 | 48 | struct Enabled : FSM::State 49 | { 50 | void react(const Disable&, EventControl& control) 51 | { 52 | control.changeTo(); 53 | } 54 | 55 | using FSM::State::react; 56 | }; 57 | 58 | struct Active : FSM::State 59 | { 60 | void planSucceeded(FullControl& control) 61 | { 62 | control.changeTo(); 63 | } 64 | }; 65 | 66 | struct Idle : FSM::State 67 | { 68 | void update(FullControl& control) 69 | { 70 | control.changeTo(); 71 | } 72 | }; 73 | 74 | struct A : FSM::State 75 | { 76 | void enter(PlanControl& control) 77 | { 78 | auto plan = control.plan(); 79 | plan.clear(); 80 | 81 | plan.change(); 82 | plan.change(); 83 | plan.change(); 84 | } 85 | 86 | void update(FullControl& control) { control.succeed(); } 87 | }; 88 | 89 | struct B : FSM::State 90 | { 91 | void update(FullControl& control) { control.succeed(); } 92 | }; 93 | 94 | struct C : FSM::State 95 | { 96 | void update(FullControl& control) { control.succeed(); } 97 | }; 98 | 99 | struct D : FSM::State 100 | { 101 | void update(FullControl& control) { control.succeed(); } 102 | }; 103 | 104 | TEST_CASE("FSM.Reported.issue_49") 105 | { 106 | FSM::Instance fsm; 107 | 108 | REQUIRE(fsm.isActive()); 109 | 110 | fsm.update(); 111 | REQUIRE(fsm.isActive()); 112 | REQUIRE(fsm.isActive()); 113 | REQUIRE(fsm.isActive()); 114 | 115 | fsm.update(); 116 | REQUIRE(fsm.isActive()); 117 | 118 | fsm.update(); 119 | REQUIRE(fsm.isActive()); 120 | 121 | fsm.update(); 122 | REQUIRE(fsm.isActive()); 123 | 124 | fsm.update(); 125 | REQUIRE(fsm.isActive()); 126 | 127 | fsm.update(); 128 | REQUIRE(fsm.isActive()); 129 | 130 | fsm.update(); 131 | REQUIRE(fsm.isActive()); 132 | 133 | // uncomment to make test pass 134 | //fsm.update(); 135 | //REQUIRE(fsm.isActive()); 136 | 137 | fsm.react(Disable{}); 138 | REQUIRE(fsm.isActive()); 139 | 140 | fsm.react(Enable{}); 141 | REQUIRE(fsm.isActive()); 142 | REQUIRE(fsm.isActive()); 143 | REQUIRE(fsm.isActive()); 144 | 145 | fsm.update(); 146 | REQUIRE(fsm.isActive()); 147 | } 148 | -------------------------------------------------------------------------------- /test/reported/resuming_plan.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | // Issue reported in https://discord.com/channels/755015945269018695/759099438353350696/1334175930188300348 5 | 6 | #define HFSM2_ENABLE_PLANS 7 | #include 8 | 9 | #include 10 | 11 | using M = hfsm2::Machine; 12 | 13 | struct Manual; 14 | struct Automatic; 15 | struct Idling; 16 | struct WaitInput; 17 | struct WorkOnBox; 18 | struct BoxA; 19 | struct BoxB; 20 | struct BoxC; 21 | 22 | enum class Input { retry, stop }; 23 | 24 | struct BoxPresent { }; 25 | 26 | // clang-format off 27 | using FSM = M::PeerRoot< 28 | Manual, 29 | M::Composite 37 | > 38 | >; 39 | // clang-format on 40 | 41 | struct Manual : FSM::State { }; 42 | 43 | struct Automatic : FSM::State { }; 44 | 45 | struct Idling : FSM::State { 46 | using FSM::State::react; 47 | 48 | void react(const BoxPresent&, EventControl& c) 49 | { 50 | auto plan = c.plan(); 51 | 52 | plan.change(); 53 | plan.change(); 54 | 55 | c.changeTo(); 56 | } 57 | }; 58 | 59 | struct WaitInput : FSM::State { 60 | using FSM::State::react; 61 | 62 | void react(const Input& e, EventControl& c) 63 | { 64 | if (e == Input::retry) 65 | c.resume(); 66 | else 67 | c.changeTo(); 68 | } 69 | }; 70 | 71 | struct WorkOnBox : FSM::State { 72 | void planSucceeded(FullControl& c) 73 | { 74 | c.changeTo(); 75 | } 76 | 77 | void planFailed(FullControl& c) 78 | { 79 | c.changeTo(); 80 | } 81 | }; 82 | 83 | struct BoxA : FSM::State { 84 | void update(FullControl& c) 85 | { 86 | c.succeed(); 87 | } 88 | }; 89 | 90 | struct BoxB : FSM::State { 91 | bool should_fail = true; 92 | 93 | void update(FullControl& c) 94 | { 95 | if (should_fail) 96 | c.fail(); 97 | else 98 | c.succeed(); 99 | 100 | should_fail = !should_fail; 101 | } 102 | }; 103 | 104 | struct BoxC : FSM::State { 105 | void update(FullControl& c) 106 | { 107 | c.succeed(); 108 | } 109 | }; 110 | 111 | TEST_CASE("FSM.Reported.Resuming Plan") { 112 | FSM::Instance machine; 113 | 114 | machine.immediateChangeTo(); 115 | REQUIRE(machine.isActive()); 116 | REQUIRE(machine.isActive()); 117 | 118 | machine.react(BoxPresent {}); 119 | REQUIRE(machine.isActive()); 120 | REQUIRE(machine.isActive()); 121 | REQUIRE(machine.isActive()); 122 | 123 | machine.update(); 124 | REQUIRE(machine.isActive()); 125 | REQUIRE(machine.isActive()); 126 | REQUIRE(machine.isActive()); 127 | 128 | machine.update(); 129 | REQUIRE(machine.isActive()); 130 | REQUIRE(machine.isActive()); 131 | 132 | machine.react(Input::retry); 133 | REQUIRE(machine.isActive()); 134 | REQUIRE(machine.isActive()); 135 | REQUIRE(machine.isActive()); 136 | 137 | machine.update(); 138 | REQUIRE(machine.isActive()); 139 | REQUIRE(machine.isActive()); 140 | REQUIRE(machine.isActive()); 141 | } 142 | -------------------------------------------------------------------------------- /test/shared/test_bit_array.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #include "../tools.hpp" 5 | 6 | namespace test_bit_array { 7 | 8 | //////////////////////////////////////////////////////////////////////////////// 9 | 10 | using BitArray = hfsm2::detail::BitArrayT<32>; 11 | using Bits = typename BitArray::Bits; 12 | 13 | TEST_CASE("Shared.BitArrayT<>") { 14 | BitArray bitArray; 15 | REQUIRE(bitArray.empty()); 16 | 17 | WHEN("Static methods") { 18 | { 19 | const Bits bits = bitArray.bits<3, 7>(); 20 | REQUIRE(!bits); 21 | 22 | REQUIRE(!bits.get<0>()); 23 | REQUIRE(!bits.get<1>()); 24 | REQUIRE(!bits.get<2>()); 25 | REQUIRE(!bits.get<3>()); 26 | REQUIRE(!bits.get<4>()); 27 | REQUIRE(!bits.get<5>()); 28 | REQUIRE(!bits.get<6>()); 29 | } 30 | 31 | { 32 | Bits bits = bitArray.bits<3, 7>(); 33 | bits.set<4>(); 34 | } 35 | 36 | { 37 | const Bits bits = bitArray.bits<2, 13>(); 38 | REQUIRE(!bits.get< 0>()); 39 | REQUIRE(!bits.get< 1>()); 40 | REQUIRE(!bits.get< 2>()); 41 | REQUIRE(!bits.get< 3>()); 42 | REQUIRE(!bits.get< 4>()); 43 | REQUIRE(!bits.get< 5>()); 44 | REQUIRE(!bits.get< 6>()); 45 | REQUIRE(!bits.get< 7>()); 46 | REQUIRE(!bits.get< 8>()); 47 | REQUIRE(!bits.get< 9>()); 48 | REQUIRE(!bits.get<10>()); 49 | REQUIRE(!bits.get<11>()); 50 | REQUIRE( bits.get<12>()); 51 | } 52 | 53 | { 54 | Bits bits = bitArray.bits<2, 13>(); 55 | bits.clear<12>(); 56 | } 57 | 58 | { 59 | const Bits bits = bitArray.bits<3, 7>(); 60 | REQUIRE(!bits); 61 | 62 | REQUIRE(!bits.get<0>()); 63 | REQUIRE(!bits.get<1>()); 64 | REQUIRE(!bits.get<2>()); 65 | REQUIRE(!bits.get<3>()); 66 | REQUIRE(!bits.get<4>()); 67 | REQUIRE(!bits.get<5>()); 68 | REQUIRE(!bits.get<6>()); 69 | } 70 | 71 | bitArray.clear(); 72 | REQUIRE(bitArray.empty()); 73 | } 74 | 75 | WHEN("Dynamic methods") { 76 | { 77 | const Bits bits = bitArray.bits<3, 7>(); 78 | REQUIRE(!bits); 79 | 80 | REQUIRE(!bits.get(0)); 81 | REQUIRE(!bits.get(1)); 82 | REQUIRE(!bits.get(2)); 83 | REQUIRE(!bits.get(3)); 84 | REQUIRE(!bits.get(4)); 85 | REQUIRE(!bits.get(5)); 86 | REQUIRE(!bits.get(6)); 87 | } 88 | 89 | { 90 | Bits bits = bitArray.bits<3, 7>(); 91 | bits.set<4>(); 92 | } 93 | 94 | { 95 | const Bits bits = bitArray.bits<2, 13>(); 96 | REQUIRE(!bits.get( 0)); 97 | REQUIRE(!bits.get( 1)); 98 | REQUIRE(!bits.get( 2)); 99 | REQUIRE(!bits.get( 3)); 100 | REQUIRE(!bits.get( 4)); 101 | REQUIRE(!bits.get( 5)); 102 | REQUIRE(!bits.get( 6)); 103 | REQUIRE(!bits.get( 7)); 104 | REQUIRE(!bits.get( 8)); 105 | REQUIRE(!bits.get( 9)); 106 | REQUIRE(!bits.get(10)); 107 | REQUIRE(!bits.get(11)); 108 | REQUIRE( bits.get(12)); 109 | } 110 | 111 | { 112 | Bits bits = bitArray.bits<2, 13>(); 113 | bits.clear<12>(); 114 | } 115 | 116 | { 117 | const Bits bits = bitArray.bits<3, 7>(); 118 | REQUIRE(!bits); 119 | 120 | REQUIRE(!bits.get(0)); 121 | REQUIRE(!bits.get(1)); 122 | REQUIRE(!bits.get(2)); 123 | REQUIRE(!bits.get(3)); 124 | REQUIRE(!bits.get(4)); 125 | REQUIRE(!bits.get(5)); 126 | REQUIRE(!bits.get(6)); 127 | } 128 | 129 | bitArray.clear(); 130 | REQUIRE(bitArray.empty()); 131 | } 132 | } 133 | 134 | //////////////////////////////////////////////////////////////////////////////// 135 | 136 | } 137 | -------------------------------------------------------------------------------- /test/shared/test_bit_stream.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_SERIALIZATION 5 | #include "../tools.hpp" 6 | 7 | namespace test_bit_stream { 8 | 9 | //////////////////////////////////////////////////////////////////////////////// 10 | 11 | using WriteStream = hfsm2::detail::BitWriteStreamT<45>; 12 | using ReadStream = hfsm2::detail::BitReadStreamT <45>; 13 | using StreamBuffer = typename WriteStream::Buffer; 14 | 15 | //------------------------------------------------------------------------------ 16 | 17 | TEST_CASE("Shared.BitStream<>") { 18 | StreamBuffer buffer; 19 | 20 | WriteStream writeStream{buffer}; 21 | writeStream.write< 5>(static_cast( 27)); 22 | writeStream.write< 4>(static_cast( 11)); 23 | writeStream.write< 3>(static_cast( 5)); 24 | writeStream.write<12>(static_cast( 1472)); 25 | writeStream.write<21>(static_cast(1000000)); 26 | REQUIRE(writeStream.cursor() == 45); 27 | 28 | ReadStream readStream{buffer}; 29 | REQUIRE(readStream.read< 5>() == 27); 30 | REQUIRE(readStream.read< 4>() == 11); 31 | REQUIRE(readStream.read< 3>() == 5); 32 | REQUIRE(readStream.read<12>() == 1472); 33 | REQUIRE(readStream.read<21>() == 1000000); 34 | REQUIRE(readStream.cursor() == 45); 35 | } 36 | 37 | //////////////////////////////////////////////////////////////////////////////// 38 | 39 | } 40 | -------------------------------------------------------------------------------- /test/shared/test_random.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_UTILITY_THEORY 5 | #include "../tools.hpp" 6 | 7 | namespace test_random { 8 | 9 | //////////////////////////////////////////////////////////////////////////////// 10 | 11 | template 12 | void 13 | testUniformity(const int average) { 14 | using Type = T; 15 | using Random = hfsm2::RNGT; 16 | 17 | Random random{0}; 18 | int histogram[10] = {0}; 19 | 20 | for (int i = 0; i < 10 * average; ++i) { 21 | const float real = random.next(); 22 | REQUIRE(real >= Type{0.0}); 23 | REQUIRE(real < Type{1.0}); 24 | 25 | const unsigned n = static_cast(10.0f * real); 26 | REQUIRE(n < hfsm2::count(histogram)); 27 | 28 | ++histogram[n]; 29 | } 30 | 31 | for (unsigned i = 1; i < hfsm2::count(histogram); ++i) { 32 | const int delta = abs(average - histogram[i]); 33 | const float relative = 1.0f * delta / average; 34 | 35 | REQUIRE(relative < 0.2f); 36 | } 37 | } 38 | 39 | //------------------------------------------------------------------------------ 40 | 41 | TEST_CASE("Shared.RandomT<>") { 42 | testUniformity(100); 43 | } 44 | 45 | //////////////////////////////////////////////////////////////////////////////// 46 | 47 | } 48 | -------------------------------------------------------------------------------- /test/shared/test_task_list.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_PLANS 5 | #include "../tools.hpp" 6 | 7 | namespace test_task_list { 8 | 9 | //////////////////////////////////////////////////////////////////////////////// 10 | 11 | using List = hfsm2::detail::TaskListT; 12 | 13 | //------------------------------------------------------------------------------ 14 | 15 | TEST_CASE("Shared.List<>") { 16 | List list; 17 | constexpr auto CAPACITY = List::CAPACITY; 18 | 19 | REQUIRE(list.count() == 0); 20 | 21 | WHEN("fill, delete and re-insert an element") { 22 | for (List::Index i = 0; i < CAPACITY; ++i) { 23 | const auto index = list.emplace(static_cast(i), 24 | static_cast(i), 25 | hfsm2::TransitionType::COUNT); 26 | 27 | REQUIRE(index == i); 28 | REQUIRE(list.count() == i + 1); 29 | } 30 | 31 | for (List::Index i = 0; i < CAPACITY; ++i) 32 | REQUIRE(list[i] == hfsm2::detail::TaskBase{static_cast(i), 33 | static_cast(i), 34 | hfsm2::TransitionType::COUNT}); 35 | 36 | THEN("at the start") { 37 | REQUIRE(list.count() == CAPACITY); 38 | 39 | list.remove(0); 40 | REQUIRE(list.count() == CAPACITY - 1); 41 | 42 | const auto index = list.emplace(static_cast(0u), 43 | static_cast(0u), 44 | hfsm2::TransitionType::COUNT); 45 | REQUIRE(index == 0); 46 | REQUIRE(list.count() == CAPACITY); 47 | } 48 | 49 | AND_THEN("at the mid") { 50 | REQUIRE(list.count() == CAPACITY); 51 | 52 | constexpr List::Index mid = CAPACITY / 2; 53 | list.remove(mid); 54 | REQUIRE(list.count() == CAPACITY - 1); 55 | 56 | const auto index = list.emplace(static_cast(mid), 57 | static_cast(mid), 58 | hfsm2::TransitionType::COUNT); 59 | REQUIRE(index == mid); 60 | REQUIRE(list.count() == CAPACITY); 61 | } 62 | 63 | AND_THEN("at the end") { 64 | REQUIRE(list.count() == CAPACITY); 65 | 66 | constexpr List::Index end = CAPACITY - 1; 67 | list.remove(end); 68 | REQUIRE(list.count() == CAPACITY - 1); 69 | 70 | const auto index = list.emplace(static_cast(end), 71 | static_cast(end), 72 | hfsm2::TransitionType::COUNT); 73 | REQUIRE(index == end); 74 | REQUIRE(list.count() == CAPACITY); 75 | } 76 | } 77 | 78 | WHEN("fill, delete all and re-insert all elements") { 79 | for (List::Index i = 0; i < CAPACITY; ++i) { 80 | const auto index = list.emplace(static_cast(i), 81 | static_cast(i), 82 | hfsm2::TransitionType::COUNT); 83 | 84 | REQUIRE(index == i); 85 | REQUIRE(list.count() == i + 1); 86 | } 87 | 88 | for (List::Index i = 0; i < CAPACITY; ++i) 89 | REQUIRE(list[i] == hfsm2::detail::TaskBase{static_cast(i), 90 | static_cast(i), 91 | hfsm2::TransitionType::COUNT}); 92 | 93 | THEN("from the start") { 94 | REQUIRE(list.count() == CAPACITY); 95 | 96 | for (List::Index i = 0; i < CAPACITY; ++i) { 97 | list.remove(i); 98 | REQUIRE(list.count() == CAPACITY - 1 - i); 99 | } 100 | 101 | for (List::Index i = 0; i < CAPACITY; ++i) { 102 | const auto index = list.emplace(static_cast(i), 103 | static_cast(i), 104 | hfsm2::TransitionType::COUNT); 105 | 106 | REQUIRE(index == CAPACITY - 1 - i); 107 | REQUIRE(list.count() == i + 1); 108 | } 109 | } 110 | 111 | AND_THEN("at the mid") { 112 | REQUIRE(list.count() == CAPACITY); 113 | } 114 | 115 | AND_THEN("from the end") { 116 | REQUIRE(list.count() == CAPACITY); 117 | 118 | for (List::Index i = 0; i < CAPACITY; ++i) { 119 | list.remove(CAPACITY - 1 - i); 120 | REQUIRE(list.count() == CAPACITY - 1 - i); 121 | } 122 | 123 | for (List::Index i = 0; i < CAPACITY; ++i) { 124 | const auto index = list.emplace(static_cast(i), 125 | static_cast(i), 126 | hfsm2::TransitionType::COUNT); 127 | 128 | REQUIRE(index == i); 129 | REQUIRE(list.count() == i + 1); 130 | } 131 | } 132 | } 133 | } 134 | 135 | //////////////////////////////////////////////////////////////////////////////// 136 | 137 | } 138 | -------------------------------------------------------------------------------- /test/test_access.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_VERBOSE_DEBUG_LOG 5 | #include "tools.hpp" 6 | 7 | using namespace test_tools; 8 | 9 | namespace test_access { 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | using M = hfsm2::Machine; 14 | 15 | //------------------------------------------------------------------------------ 16 | 17 | #define S(s) struct s 18 | 19 | using FSM = M::PeerRoot< 20 | M::Composite 26 | >, 27 | M::Orthogonal, 32 | M::Composite 36 | > 37 | >; 38 | 39 | #undef S 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | static_assert(FSM::regionId() == 1, ""); 44 | static_assert(FSM::regionId() == 2, ""); 45 | static_assert(FSM::regionId() == 3, ""); 46 | static_assert(FSM::regionId() == 4, ""); 47 | static_assert(FSM::regionId() == 5, ""); 48 | 49 | static_assert(FSM::stateId() == 1, ""); 50 | static_assert(FSM::stateId() == 2, ""); 51 | static_assert(FSM::stateId() == 3, ""); 52 | static_assert(FSM::stateId() == 4, ""); 53 | static_assert(FSM::stateId() == 5, ""); 54 | static_assert(FSM::stateId() == 6, ""); 55 | static_assert(FSM::stateId() == 7, ""); 56 | static_assert(FSM::stateId() == 8, ""); 57 | static_assert(FSM::stateId() == 9, ""); 58 | static_assert(FSM::stateId() == 10, ""); 59 | static_assert(FSM::stateId() == 11, ""); 60 | static_assert(FSM::stateId() == 12, ""); 61 | 62 | //////////////////////////////////////////////////////////////////////////////// 63 | 64 | struct A : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 65 | struct A_1 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 66 | struct A_2 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 67 | struct A_2_1 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 68 | struct A_2_2 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 69 | struct B : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 70 | struct B_1 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 71 | struct B_1_1 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 72 | struct B_1_2 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 73 | struct B_2 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 74 | struct B_2_1 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 75 | struct B_2_2 : FSM::State { const hfsm2::StateID id = FSM::stateId(); }; 76 | 77 | //////////////////////////////////////////////////////////////////////////////// 78 | 79 | static_assert(FSM::Instance::Info::STATE_COUNT == 13, "STATE_COUNT"); 80 | static_assert(FSM::Instance::Info::REGION_COUNT == 6, "REGION_COUNT"); 81 | static_assert(FSM::Instance::Info::COMPO_COUNT == 5, "COMPO_COUNT"); 82 | static_assert(FSM::Instance::Info::COMPO_PRONGS == 10, "COMPO_PRONGS"); 83 | static_assert(FSM::Instance::Info::ORTHO_COUNT == 1, "ORTHO_COUNT"); 84 | static_assert(FSM::Instance::Info::ORTHO_UNITS == 1, "ORTHO_UNITS"); 85 | 86 | //////////////////////////////////////////////////////////////////////////////// 87 | 88 | TEST_CASE("FSM.Access") { 89 | FSM::Instance machine; 90 | 91 | REQUIRE(machine.access().id == FSM::stateId()); 92 | REQUIRE(machine.access().id == FSM::stateId()); 93 | REQUIRE(machine.access().id == FSM::stateId()); 94 | REQUIRE(machine.access().id == FSM::stateId()); 95 | REQUIRE(machine.access().id == FSM::stateId()); 96 | REQUIRE(machine.access().id == FSM::stateId()); 97 | REQUIRE(machine.access().id == FSM::stateId()); 98 | REQUIRE(machine.access().id == FSM::stateId()); 99 | REQUIRE(machine.access().id == FSM::stateId()); 100 | REQUIRE(machine.access().id == FSM::stateId()); 101 | REQUIRE(machine.access().id == FSM::stateId()); 102 | REQUIRE(machine.access().id == FSM::stateId()); 103 | } 104 | 105 | //////////////////////////////////////////////////////////////////////////////// 106 | 107 | } 108 | -------------------------------------------------------------------------------- /test/test_composite_bst.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_VERBOSE_DEBUG_LOG 5 | #include "tools.hpp" 6 | 7 | using namespace test_tools; 8 | 9 | namespace test_composite_bst { 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | using M = hfsm2::Machine; 14 | 15 | //------------------------------------------------------------------------------ 16 | 17 | #define S(s) struct s 18 | 19 | using FSM = M::Root; 31 | 32 | #undef S 33 | 34 | //------------------------------------------------------------------------------ 35 | 36 | static_assert(FSM::regionId() == 0, ""); 37 | 38 | static_assert(FSM::stateId() == 0, ""); 39 | static_assert(FSM::stateId() == 1, ""); 40 | static_assert(FSM::stateId() == 2, ""); 41 | static_assert(FSM::stateId() == 3, ""); 42 | static_assert(FSM::stateId() == 4, ""); 43 | static_assert(FSM::stateId() == 5, ""); 44 | static_assert(FSM::stateId() == 6, ""); 45 | static_assert(FSM::stateId() == 7, ""); 46 | static_assert(FSM::stateId() == 8, ""); 47 | static_assert(FSM::stateId() == 9, ""); 48 | static_assert(FSM::stateId() == 10, ""); 49 | 50 | //////////////////////////////////////////////////////////////////////////////// 51 | 52 | struct Apex : FSM::State {}; 53 | struct S0 : FSM::State {}; 54 | struct S1 : FSM::State {}; 55 | struct S2 : FSM::State {}; 56 | struct S3 : FSM::State {}; 57 | struct S4 : FSM::State {}; 58 | struct S5 : FSM::State {}; 59 | struct S6 : FSM::State {}; 60 | struct S7 : FSM::State {}; 61 | struct S8 : FSM::State {}; 62 | struct S9 : FSM::State {}; 63 | 64 | //////////////////////////////////////////////////////////////////////////////// 65 | 66 | static_assert(FSM::Instance::Info::STATE_COUNT == 11, "STATE_COUNT"); 67 | static_assert(FSM::Instance::Info::REGION_COUNT == 1, "REGION_COUNT"); 68 | static_assert(FSM::Instance::Info::COMPO_COUNT == 1, "COMPO_COUNT"); 69 | static_assert(FSM::Instance::Info::COMPO_PRONGS == 10, "COMPO_PRONGS"); 70 | static_assert(FSM::Instance::Info::ORTHO_COUNT == 0, "ORTHO_COUNT"); 71 | static_assert(FSM::Instance::Info::ORTHO_UNITS == 0, "ORTHO_UNITS"); 72 | 73 | //////////////////////////////////////////////////////////////////////////////// 74 | 75 | const Types all = { 76 | FSM::stateId(), 77 | FSM::stateId(), 78 | FSM::stateId(), 79 | FSM::stateId(), 80 | FSM::stateId(), 81 | FSM::stateId(), 82 | FSM::stateId(), 83 | FSM::stateId(), 84 | FSM::stateId(), 85 | FSM::stateId(), 86 | }; 87 | 88 | //------------------------------------------------------------------------------ 89 | 90 | TEST_CASE("FSM.Composite BST") { 91 | Logger logger; 92 | 93 | { 94 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 95 | 96 | FSM::Instance machine{&logger}; 97 | { 98 | logger.assertSequence({ 99 | { FSM::stateId(), Event::Type::ENTRY_GUARD }, 100 | { FSM::stateId(), Event::Type::ENTRY_GUARD }, 101 | 102 | { FSM::stateId(), Event::Type::ENTER }, 103 | { FSM::stateId(), Event::Type::ENTER }, 104 | }); 105 | 106 | assertActive(machine, all, { 107 | FSM::stateId(), 108 | }); 109 | 110 | assertResumable(machine, all, {}); 111 | } 112 | 113 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 114 | 115 | machine.immediateChangeTo(); 116 | { 117 | logger.assertSequence({ 118 | { Event::Type::CHANGE, FSM::stateId() }, 119 | 120 | { FSM::stateId(), Event::Type::EXIT_GUARD }, 121 | { FSM::stateId(), Event::Type::ENTRY_GUARD }, 122 | 123 | { FSM::stateId(), Event::Type::EXIT }, 124 | { FSM::stateId(), Event::Type::ENTER }, 125 | }); 126 | 127 | assertActive(machine, all, { 128 | FSM::stateId(), 129 | }); 130 | 131 | assertResumable(machine, all, { 132 | FSM::stateId(), 133 | }); 134 | } 135 | 136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 137 | } 138 | 139 | logger.assertSequence({ 140 | { FSM::stateId(), Event::Type::EXIT }, 141 | { hfsm2::StateID{0}, Event::Type::EXIT }, 142 | }); 143 | } 144 | 145 | //////////////////////////////////////////////////////////////////////////////// 146 | 147 | } 148 | -------------------------------------------------------------------------------- /test/test_contexts_random.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_UTILITY_THEORY 5 | #include "tools.hpp" 6 | 7 | using namespace test_tools; 8 | 9 | namespace test_contexts_random { 10 | 11 | //------------------------------------------------------------------------------ 12 | 13 | using Context = int; 14 | 15 | struct DummyRNG { 16 | inline float next() { return 0.0f; } 17 | }; 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | 21 | namespace value_context { 22 | 23 | using Config = hfsm2::Config 24 | ::ContextT 25 | ::RandomT; 26 | 27 | using M = hfsm2::MachineT; 28 | 29 | struct A; 30 | struct B; 31 | 32 | using FSM = M::PeerRoot; 33 | 34 | struct A : FSM::State {}; 35 | struct B : FSM::State {}; 36 | 37 | } 38 | 39 | //////////////////////////////////////////////////////////////////////////////// 40 | 41 | namespace reference_context { 42 | 43 | using Config = hfsm2::Config 44 | ::ContextT 45 | ::RandomT; 46 | 47 | using M = hfsm2::MachineT; 48 | 49 | struct A; 50 | struct B; 51 | 52 | using FSM = M::PeerRoot; 53 | 54 | struct A : FSM::State {}; 55 | struct B : FSM::State {}; 56 | 57 | } 58 | 59 | //////////////////////////////////////////////////////////////////////////////// 60 | 61 | namespace pointer_context { 62 | 63 | using Config = hfsm2::Config 64 | ::ContextT 65 | ::RandomT; 66 | 67 | using M = hfsm2::MachineT; 68 | 69 | struct A; 70 | struct B; 71 | 72 | using FSM = M::PeerRoot; 73 | 74 | struct A : FSM::State {}; 75 | struct B : FSM::State {}; 76 | 77 | } 78 | 79 | //////////////////////////////////////////////////////////////////////////////// 80 | 81 | namespace no_context { 82 | 83 | using Config = hfsm2::Config 84 | ::RandomT; 85 | 86 | using M = hfsm2::MachineT; 87 | 88 | struct A; 89 | struct B; 90 | 91 | using FSM = M::PeerRoot; 92 | 93 | struct A : FSM::State {}; 94 | struct B : FSM::State {}; 95 | 96 | } 97 | 98 | //////////////////////////////////////////////////////////////////////////////// 99 | 100 | TEST_CASE("FSM.Contexts Random") { 101 | Context primary = 7; 102 | Context secondary = -39; 103 | DummyRNG rng; 104 | 105 | // context is a value 106 | { 107 | using Instance = value_context::FSM::Instance; 108 | static_assert(std::is_same::value, ""); 109 | 110 | //Instance defaultConstructed; 111 | 112 | const Instance constant{primary, rng}; 113 | REQUIRE(constant.context() == primary); 114 | 115 | Instance machine{primary, rng}; 116 | REQUIRE(machine.context() == primary); 117 | } 118 | 119 | // context is a reference 120 | { 121 | using Instance = reference_context::FSM::Instance; 122 | static_assert(std::is_same::value, ""); 123 | 124 | const Instance constant{primary, rng}; 125 | REQUIRE(constant.context() == primary); 126 | 127 | Instance machine{primary, rng}; 128 | REQUIRE(machine.context() == primary); 129 | } 130 | 131 | // context is a pointer 132 | { 133 | using Instance = pointer_context::FSM::Instance; 134 | static_assert(std::is_same::value, ""); 135 | 136 | pointer_context::FSM::Instance defaultConstructed(nullptr, rng); 137 | REQUIRE(defaultConstructed.context() == nullptr); 138 | 139 | const Instance constant{&primary, rng}; 140 | REQUIRE(constant.context() == &primary); 141 | 142 | Instance machine{&primary, rng}; 143 | REQUIRE(machine.context() == &primary); 144 | 145 | machine.setContext(&secondary); 146 | REQUIRE(machine.context() == &secondary); 147 | } 148 | 149 | // empty context 150 | { 151 | no_context::FSM::Instance defaultConstructed(rng); 152 | static_assert(std::is_same::value, ""); 153 | } 154 | } 155 | 156 | //////////////////////////////////////////////////////////////////////////////// 157 | 158 | } 159 | -------------------------------------------------------------------------------- /test/test_manual_activation.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_VERBOSE_DEBUG_LOG 5 | #include "tools.hpp" 6 | 7 | using namespace test_tools; 8 | 9 | namespace test_manual_activation { 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | using Config = hfsm2::Config 14 | ::ManualActivation; 15 | 16 | using M = hfsm2::MachineT; 17 | 18 | using Logger = LoggerT; 19 | 20 | //------------------------------------------------------------------------------ 21 | 22 | #define S(s) struct s 23 | 24 | using FSM = M::PeerRoot< 25 | S(A), 26 | S(B) 27 | >; 28 | 29 | #undef S 30 | 31 | //------------------------------------------------------------------------------ 32 | 33 | static_assert(FSM::stateId() == 1, ""); 34 | static_assert(FSM::stateId() == 2, ""); 35 | 36 | //////////////////////////////////////////////////////////////////////////////// 37 | 38 | struct A 39 | : FSM::State 40 | { 41 | void entryGuard(GuardControl& control) { 42 | control.changeTo(); 43 | } 44 | }; 45 | 46 | //------------------------------------------------------------------------------ 47 | 48 | struct B 49 | : FSM::State 50 | {}; 51 | 52 | //////////////////////////////////////////////////////////////////////////////// 53 | 54 | const Types all = { 55 | FSM::stateId(), 56 | FSM::stateId(), 57 | }; 58 | 59 | //------------------------------------------------------------------------------ 60 | 61 | TEST_CASE("FSM.Manual Activation") { 62 | Logger logger; 63 | 64 | { 65 | FSM::Instance machine{&logger}; 66 | 67 | logger.assertSequence({}); 68 | assertActive(machine, all, {}); 69 | 70 | machine.enter(); 71 | 72 | logger.assertSequence({ 73 | { hfsm2::StateID{0}, Event::Type::ENTRY_GUARD }, 74 | { FSM::stateId(), Event::Type::ENTRY_GUARD }, 75 | 76 | { FSM::stateId(), Event::Type::CHANGE, FSM::stateId() }, 77 | 78 | { hfsm2::StateID{0}, Event::Type::ENTRY_GUARD }, 79 | { FSM::stateId(), Event::Type::ENTRY_GUARD }, 80 | 81 | { hfsm2::StateID{0}, Event::Type::ENTER }, 82 | { FSM::stateId(), Event::Type::ENTER }, 83 | }); 84 | 85 | assertActive(machine, all, { 86 | FSM::stateId(), 87 | }); 88 | 89 | machine.exit(); 90 | 91 | logger.assertSequence({ 92 | { FSM::stateId(), Event::Type::EXIT }, 93 | { hfsm2::StateID{0}, Event::Type::EXIT }, 94 | }); 95 | 96 | assertActive(machine, all, {}); 97 | } 98 | 99 | logger.assertSequence({}); 100 | } 101 | 102 | //////////////////////////////////////////////////////////////////////////////// 103 | 104 | } 105 | -------------------------------------------------------------------------------- /test/test_query.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #include "tools.hpp" 5 | 6 | using namespace test_tools; 7 | 8 | namespace test_query { 9 | 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | using M = hfsm2::Machine; 13 | 14 | //------------------------------------------------------------------------------ 15 | 16 | #define S(s) struct s 17 | 18 | using FSM = M::PeerRoot< 19 | S(A), 20 | S(B), 21 | S(C), 22 | S(D), 23 | S(E) 24 | >; 25 | 26 | #undef S 27 | 28 | //------------------------------------------------------------------------------ 29 | 30 | static_assert(FSM::stateId() == 1, ""); 31 | static_assert(FSM::stateId() == 2, ""); 32 | static_assert(FSM::stateId() == 3, ""); 33 | static_assert(FSM::stateId() == 4, ""); 34 | static_assert(FSM::stateId() == 5, ""); 35 | 36 | //////////////////////////////////////////////////////////////////////////////// 37 | 38 | template 39 | struct BaseT 40 | : public FSM::State 41 | { 42 | void query(hfsm2::StateID& stateId_, 43 | ConstControl&) const 44 | { 45 | stateId_ = stateId(); 46 | } 47 | }; 48 | 49 | //////////////////////////////////////////////////////////////////////////////// 50 | 51 | struct A : FSM::StateT> {}; 52 | struct B : FSM::StateT> {}; 53 | struct C : FSM::StateT> {}; 54 | struct D : FSM::StateT> {}; 55 | struct E : FSM::StateT> {}; 56 | 57 | //////////////////////////////////////////////////////////////////////////////// 58 | 59 | TEST_CASE("FSM.Query") { 60 | FSM::Instance machine; 61 | hfsm2::StateID stateId; 62 | 63 | machine.query(stateId); 64 | REQUIRE(stateId == FSM::stateId()); 65 | 66 | machine.immediateChangeTo(); 67 | machine.query(stateId); 68 | REQUIRE(stateId == FSM::stateId()); 69 | 70 | machine.immediateChangeTo(); 71 | machine.query(stateId); 72 | REQUIRE(stateId == FSM::stateId()); 73 | 74 | machine.immediateChangeTo(); 75 | machine.query(stateId); 76 | REQUIRE(stateId == FSM::stateId()); 77 | 78 | machine.immediateChangeTo(); 79 | machine.query(stateId); 80 | REQUIRE(stateId == FSM::stateId()); 81 | } 82 | 83 | //////////////////////////////////////////////////////////////////////////////// 84 | 85 | } 86 | -------------------------------------------------------------------------------- /test/test_react_order.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_PLANS 5 | #include "tools.hpp" 6 | 7 | using namespace test_tools; 8 | 9 | namespace test_react_order { 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | using Config = hfsm2::Config 14 | ::BottomUpReactions; 15 | 16 | using M = hfsm2::MachineT; 17 | 18 | using Logger = LoggerT; 19 | 20 | struct Empty {}; 21 | 22 | //------------------------------------------------------------------------------ 23 | 24 | #define S(s) struct s 25 | 26 | using FSM = M::OrthogonalRoot, 31 | M::Composite 35 | >; 36 | 37 | #undef S 38 | 39 | //------------------------------------------------------------------------------ 40 | 41 | static_assert(FSM::stateId() == 0, ""); 42 | static_assert(FSM::stateId() == 1, ""); 43 | static_assert(FSM::stateId() == 2, ""); 44 | static_assert(FSM::stateId() == 3, ""); 45 | static_assert(FSM::stateId() == 4, ""); 46 | static_assert(FSM::stateId() == 5, ""); 47 | static_assert(FSM::stateId() == 6, ""); 48 | 49 | //////////////////////////////////////////////////////////////////////////////// 50 | 51 | struct R : FSM::State {}; 52 | struct C1 : FSM::State {}; 53 | struct I1 : FSM::State {}; 54 | 55 | struct D1 56 | : FSM::State 57 | { 58 | void preReact(const Empty&, EventControl& control) { 59 | control.consumeEvent(); 60 | } 61 | 62 | void react(const Empty&, EventControl& control) { 63 | control.consumeEvent(); 64 | } 65 | 66 | void postReact(const Empty&, EventControl& control) { 67 | control.consumeEvent(); 68 | } 69 | }; 70 | 71 | struct C2 : FSM::State {}; 72 | struct I2 : FSM::State {}; 73 | struct D2 : FSM::State {}; 74 | 75 | //////////////////////////////////////////////////////////////////////////////// 76 | 77 | const Types all = { 78 | FSM::stateId(), 79 | FSM::stateId(), 80 | FSM::stateId(), 81 | FSM::stateId(), 82 | FSM::stateId(), 83 | FSM::stateId(), 84 | }; 85 | 86 | //------------------------------------------------------------------------------ 87 | 88 | TEST_CASE("FSM.Prepend Plans") { 89 | Logger logger; 90 | 91 | WHEN("Created") { 92 | FSM::Instance machine{&logger}; 93 | 94 | logger.assertSequence({}); 95 | 96 | assertActive(machine, all, { 97 | FSM::stateId(), 98 | FSM::stateId(), 99 | FSM::stateId(), 100 | FSM::stateId(), 101 | }); 102 | 103 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 104 | 105 | THEN("Initial reactions") { 106 | machine.react(Empty{}); 107 | 108 | logger.assertSequence({ 109 | { FSM::stateId(), Event::Type::PRE_REACT }, 110 | { FSM::stateId(), Event::Type::PRE_REACT }, 111 | { FSM::stateId(), Event::Type::PRE_REACT }, 112 | { FSM::stateId(), Event::Type::PRE_REACT }, 113 | { FSM::stateId(), Event::Type::PRE_REACT }, 114 | 115 | { FSM::stateId(), Event::Type::REACT }, 116 | { FSM::stateId(), Event::Type::REACT }, 117 | { FSM::stateId(), Event::Type::REACT }, 118 | { FSM::stateId(), Event::Type::REACT }, 119 | { FSM::stateId(), Event::Type::REACT }, 120 | 121 | { FSM::stateId(), Event::Type::POST_REACT }, 122 | { FSM::stateId(), Event::Type::POST_REACT }, 123 | { FSM::stateId(), Event::Type::POST_REACT }, 124 | { FSM::stateId(), Event::Type::POST_REACT }, 125 | { FSM::stateId(), Event::Type::POST_REACT }, 126 | }); 127 | } 128 | 129 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 130 | 131 | AND_THEN("Secondary reactions") { 132 | machine. changeTo(); 133 | machine.immediateChangeTo(); 134 | 135 | assertActive(machine, all, { 136 | FSM::stateId(), 137 | FSM::stateId(), 138 | FSM::stateId(), 139 | FSM::stateId(), 140 | }); 141 | 142 | machine.react(Empty{}); 143 | 144 | logger.assertSequence({ 145 | { Event::Type::CHANGE, FSM::stateId() }, 146 | { Event::Type::CHANGE, FSM::stateId() }, 147 | 148 | { FSM::stateId(), Event::Type::PRE_REACT }, 149 | 150 | { FSM::stateId(), Event::Type::REACT }, 151 | 152 | { FSM::stateId(), Event::Type::POST_REACT }, 153 | { FSM::stateId(), Event::Type::POST_REACT }, 154 | { FSM::stateId(), Event::Type::POST_REACT }, 155 | }); 156 | } 157 | 158 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 159 | } 160 | } 161 | 162 | //////////////////////////////////////////////////////////////////////////////// 163 | 164 | } 165 | -------------------------------------------------------------------------------- /test/wiki_class_member.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #include "wiki_class_member.hpp" 5 | 6 | #include 7 | 8 | #include 9 | 10 | //////////////////////////////////////////////////////////////////////////////// 11 | namespace actor_fsm { 12 | 13 | //------------------------------------------------------------------------------ 14 | 15 | using Config = hfsm2::Config 16 | ::ContextT; 17 | 18 | using M = hfsm2::MachineT; 19 | 20 | #define S(s) struct s 21 | using FSM = M::PeerRoot< 22 | S(Off), 23 | S(On) 24 | >; 25 | #undef S 26 | 27 | struct Off : FSM::State {}; 28 | struct On : FSM::State {}; 29 | 30 | FSM::Instance& 31 | fsm( Actor::FsmHost& fsmHost) { return *reinterpret_cast< FSM::Instance*>(&fsmHost); } 32 | 33 | const FSM::Instance& 34 | fsm(const Actor::FsmHost& fsmHost) { return *reinterpret_cast(&fsmHost); } 35 | 36 | //------------------------------------------------------------------------------ 37 | 38 | } 39 | 40 | Actor::Actor() { 41 | //hfsm2::StaticPrintConstT alignment; 42 | static_assert(alignof(actor_fsm::FSM::Instance) <= alignof(FsmHost), 43 | "Uncomment the line above to find out the alignment of the `FsmHost` needed"); 44 | 45 | //hfsm2::StaticPrintConstT size; 46 | static_assert(sizeof(actor_fsm::FSM::Instance) <= sizeof(FsmHost), 47 | "Uncomment the line above to find out the size of the `FsmHost` needed"); 48 | 49 | new (&_fsmHost) actor_fsm::FSM::Instance{*this}; 50 | } 51 | 52 | Actor::~Actor() { 53 | hfsm2::destroy(actor_fsm::fsm(_fsmHost)); 54 | } 55 | 56 | void Actor::turnOn() { 57 | actor_fsm::fsm(_fsmHost).immediateChangeTo(); 58 | } 59 | 60 | bool Actor::isOn() const { 61 | return actor_fsm::fsm(_fsmHost).isActive(); 62 | } 63 | 64 | //////////////////////////////////////////////////////////////////////////////// 65 | 66 | TEST_CASE("Wiki.Class Member") { 67 | Actor actor; 68 | REQUIRE(actor.isOn() == false); 69 | 70 | actor.turnOn(); 71 | REQUIRE(actor.isOn() == true); 72 | } 73 | 74 | //////////////////////////////////////////////////////////////////////////////// 75 | -------------------------------------------------------------------------------- /test/wiki_class_member.hpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #pragma once 5 | 6 | #include // max_align_t 7 | 8 | //////////////////////////////////////////////////////////////////////////////// 9 | 10 | class Actor { 11 | public: 12 | struct alignas(std::max_align_t) FsmHost { 13 | char buffer[104]; // the size is hand-adjusted 14 | }; 15 | 16 | public: 17 | Actor(); 18 | ~Actor(); 19 | 20 | void turnOn(); 21 | 22 | bool isOn() const; 23 | 24 | private: 25 | FsmHost _fsmHost; 26 | }; 27 | 28 | //////////////////////////////////////////////////////////////////////////////// 29 | -------------------------------------------------------------------------------- /test/wiki_serialization.cpp: -------------------------------------------------------------------------------- 1 | // HFSM2 (hierarchical state machine for games and interactive applications) 2 | // Created by Andrew Gresyk 3 | 4 | #define HFSM2_ENABLE_SERIALIZATION 5 | #include 6 | 7 | #include 8 | 9 | using M = hfsm2::Machine; 10 | 11 | using FSM = M::PeerRoot< 12 | struct State1, 13 | struct State2 14 | >; 15 | 16 | struct State1 : FSM::State { /* .. */ }; 17 | struct State2 : FSM::State { /* .. */ }; 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | TEST_CASE("Docs.Serialization") { 22 | // Buffer for serialization 23 | // Members: 24 | // bitSize - Number of payload bits used 25 | // payload - Serialized data 26 | FSM::Instance::SerialBuffer buffer; 27 | 28 | { 29 | FSM::Instance fsm; // Create a new FSM instance 30 | fsm.immediateChangeTo(); // Transition to 'State2' 31 | REQUIRE(fsm.isActive()); // Check if transition completed 32 | 33 | fsm.save(buffer); // Serialize FSM configuration into 'buffer' 34 | } 35 | 36 | { 37 | FSM::Instance fsm; // Create a fresh FSM instance 38 | REQUIRE(fsm.isActive()); // Initial 'State1' is activated by default 39 | 40 | fsm.load(buffer); // De-serialize FSM from 'buffer' 41 | REQUIRE(fsm.isActive()); // Check its configuration is restored 42 | } 43 | } 44 | 45 | //////////////////////////////////////////////////////////////////////////////// 46 | -------------------------------------------------------------------------------- /tools/join.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | #=============================================================================== 4 | 5 | def merge(path, folder, lastLineEmpty, included, output, commentRE): 6 | pathTokens = path.split("/") 7 | 8 | current = folder + "/" + pathTokens[-1] 9 | with open(current, 'r', encoding='utf-8') as input: 10 | if not lastLineEmpty: 11 | output.write("\n") 12 | lastLineEmpty = True 13 | 14 | for line in input: 15 | hashIndex = line.find('#include "') 16 | 17 | if hashIndex != -1: 18 | next = line[hashIndex + 10 : -2] 19 | 20 | if next not in included: 21 | nextTokens = next.split("/") 22 | included.append(nextTokens[-1]) 23 | 24 | #output.write("// inlined '" + pathTokens[-1] + "' -> '" + nextTokens[-1] + "'\n") 25 | 26 | if len(nextTokens) == 1: 27 | lastLineEmpty = merge(next, folder, lastLineEmpty, included, output, commentRE) 28 | else: 29 | name = nextTokens.pop() 30 | subFolder = folder + "/" + "/".join(nextTokens) 31 | lastLineEmpty = merge(name, subFolder, lastLineEmpty, included, output, commentRE) 32 | 33 | else: 34 | if line.startswith('\ufeff'): 35 | line = line[1:] 36 | 37 | if commentRE.match(line): 38 | continue 39 | 40 | if line == "\n": 41 | if lastLineEmpty: 42 | continue 43 | 44 | lastLineEmpty = True 45 | else: 46 | lastLineEmpty = False 47 | 48 | output.write(line) 49 | 50 | return lastLineEmpty 51 | 52 | #------------------------------------------------------------------------------- 53 | 54 | commentRE = re.compile("(?:\s*\/\/ COMMON)|(?:\s*\/\/ SPECIFIC)|(?:\s*\/\/\/\/)|(?:\s*\/\/--)|(?:\s*\/\/ -)") 55 | 56 | output = open("../include/hfsm2/machine.hpp" , 'w', encoding='utf-8-sig') 57 | merge("machine_dev.hpp" , "../development/hfsm2", True, [], output, commentRE) 58 | output.close() 59 | 60 | #=============================================================================== 61 | --------------------------------------------------------------------------------