├── .editorconfig
├── .gitignore
├── appveyor.yml
├── examples
├── basic_streetlight
│ ├── CMakeLists.txt
│ └── main.cpp
├── advanced_event_handling
│ ├── CMakeLists.txt
│ └── main.cpp
└── debug_logger_interface
│ ├── CMakeLists.txt
│ └── main.cpp
├── projects
└── visual-studio
│ ├── basic_streetlight.vcxproj.filters
│ ├── basic_event.vcxproj.filters
│ ├── basic_logger_interface.filters
│ ├── shared.props
│ ├── HFSM-tools.pyproj
│ ├── HFSM.vcxproj.filters
│ ├── HFSM.sln
│ ├── basic_streetlight.vcxproj
│ ├── basic_event.vcxproj
│ ├── basic_logger_interface.vcxproj
│ └── HFSM.vcxproj
├── test
├── CMakeLists.txt
└── main.cpp
├── include
└── hfsm
│ └── detail
│ ├── type_info.hpp
│ ├── array.inl
│ ├── iterator.inl
│ ├── wrap.hpp
│ ├── array_view.hpp
│ ├── array_view.inl
│ ├── iterator.hpp
│ ├── array.hpp
│ ├── hash_table.hpp
│ ├── machine_state.hpp
│ ├── utility.hpp
│ ├── hash_table.inl
│ ├── machine_state_methods.inl
│ ├── machine_orthogonal_sub_2.inl
│ ├── machine_orthogonal.hpp
│ ├── machine_composite_sub_2.inl
│ ├── machine_composite.hpp
│ ├── machine_orthogonal_methods.inl
│ ├── machine_composite_sub_1.inl
│ ├── machine_orthogonal_sub_1.inl
│ ├── machine_composite_methods.inl
│ └── machine.inl
├── LICENSE
├── tools
└── join.py
├── CMakeLists.txt
├── CODE_OF_CONDUCT.md
├── README.md
├── .travis.yml
└── hfsm.natvis
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | indent_style = tab
3 | indent_size = 4
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /binaries-*
2 | /build
3 | /hfsm_test.dir/Debug
4 | .idea
5 | .vs
6 | cmake-*
7 | *.user
8 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: "{build}"
2 |
3 | image:
4 | - Visual Studio 2015
5 | - Visual Studio 2017
6 |
7 | configuration:
8 | - Debug
9 | - Release
10 |
11 | platform:
12 | - 32
13 | - 64
14 |
15 | build:
16 | parallel: true
17 | verbosity: normal
18 |
--------------------------------------------------------------------------------
/examples/basic_streetlight/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | set(CMAKE_CXX_STANDARD 14)
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas -Werror")
5 |
6 | project(basic_streetlight)
7 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../../include")
8 | add_executable(${PROJECT_NAME} main.cpp)
9 |
--------------------------------------------------------------------------------
/examples/advanced_event_handling/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | set(CMAKE_CXX_STANDARD 14)
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas -Werror")
5 |
6 | project(advanced_event_handling)
7 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../../include")
8 | add_executable(${PROJECT_NAME} main.cpp)
9 |
--------------------------------------------------------------------------------
/examples/debug_logger_interface/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | set(CMAKE_CXX_STANDARD 14)
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas -Werror")
5 |
6 | project(debug_logger_interface)
7 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../../include")
8 | add_executable(${PROJECT_NAME} main.cpp)
9 |
--------------------------------------------------------------------------------
/projects/visual-studio/basic_streetlight.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/projects/visual-studio/basic_event.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------------------------------------
2 | # hfsm_test target
3 | #-------------------------------------------------------------------------------
4 | add_executable(hfsm_test main.cpp)
5 | target_link_libraries(hfsm_test hfsm)
6 | add_dependencies(hfsm_test hfsm)
7 |
8 | #-------------------------------------------------------------------------------
9 | # Add tests
10 | #-------------------------------------------------------------------------------
11 | add_test(NAME hfsm_test COMMAND hfsm_test)
12 |
--------------------------------------------------------------------------------
/projects/visual-studio/basic_logger_interface.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {f36e39b3-d6a6-4d9f-be7c-7081167a0b62}
6 |
7 |
8 |
9 |
10 | _
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/include/hfsm/detail/type_info.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "wrap.hpp"
4 |
5 | namespace hfsm {
6 | namespace detail {
7 |
8 | ////////////////////////////////////////////////////////////////////////////////
9 |
10 | class TypeInfo
11 | : public Wrap
12 | {
13 | using Base = Wrap;
14 |
15 | public:
16 | typedef std::type_index Native;
17 |
18 | public:
19 | inline TypeInfo() = default;
20 |
21 | inline TypeInfo(const std::type_index type)
22 | : Base(type)
23 | {}
24 |
25 | template
26 | static inline TypeInfo get() { return TypeInfo(typeid(T)); }
27 | };
28 |
29 | ////////////////////////////////////////////////////////////////////////////////
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/include/hfsm/detail/array.inl:
--------------------------------------------------------------------------------
1 | namespace hfsm {
2 | namespace detail {
3 |
4 | ////////////////////////////////////////////////////////////////////////////////
5 |
6 | template
7 | T&
8 | StaticArray::operator[] (const unsigned i) {
9 | assert(0 <= i && i < CAPACITY);
10 |
11 | return _items[i];
12 | }
13 |
14 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
15 |
16 | template
17 | const T&
18 | StaticArray::operator[] (const unsigned i) const {
19 | assert(0 <= i && i < CAPACITY);
20 |
21 | return _items[i];
22 | }
23 |
24 | ////////////////////////////////////////////////////////////////////////////////
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017
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 |
--------------------------------------------------------------------------------
/projects/visual-studio/shared.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(SolutionDir)..\..\binaries-$(PlatformArchitecture)\
7 | $(BUILD_ROOT)\$(SolutionName)-$(PlatformArchitecture)\$(ProjectName)-$(Configuration)\
8 | $(ProjectName)-$(Configuration)-$(PlatformArchitecture)
9 |
10 |
11 |
12 | $(SolutionDir)../../include;%(AdditionalIncludeDirectories)
13 | Level4
14 | true
15 | _UNICODE;UNICODE;_CONSOLE;%(PreprocessorDefinitions)
16 | /std:c++latest
17 |
18 |
19 | Console
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/include/hfsm/detail/iterator.inl:
--------------------------------------------------------------------------------
1 | namespace hfsm {
2 | namespace detail {
3 |
4 | ////////////////////////////////////////////////////////////////////////////////
5 |
6 | template
7 | bool
8 | Iterator::operator != (const Iterator& HSFM_IF_ASSERT(dummy)) const {
9 | assert(&_container == &dummy._container);
10 |
11 | return _cursor != _container.limit();
12 | }
13 |
14 | //------------------------------------------------------------------------------
15 |
16 | template
17 | Iterator&
18 | Iterator::operator ++() {
19 | _cursor = _container.next(_cursor);
20 |
21 | return *this;
22 | }
23 |
24 | ////////////////////////////////////////////////////////////////////////////////
25 |
26 | template
27 | bool
28 | Iterator::operator != (const Iterator& HSFM_IF_ASSERT(dummy)) const {
29 | assert(&_container == &dummy._container);
30 |
31 | return _cursor != _container.limit();
32 | }
33 |
34 | //------------------------------------------------------------------------------
35 |
36 | template
37 | Iterator&
38 | Iterator::operator ++() {
39 | _cursor = _container.next(_cursor);
40 |
41 | return *this;
42 | }
43 |
44 | ////////////////////////////////////////////////////////////////////////////////
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tools/join.py:
--------------------------------------------------------------------------------
1 | ################################################################################
2 |
3 | def mergeTo(folder, path, included, pragmaOnceCounter, output):
4 | pathTokens = path.split("/")
5 |
6 | if len(pathTokens) > 1:
7 | folder += "/" + pathTokens[0]
8 |
9 | current = folder + "/" + pathTokens[-1]
10 | with open(current, 'r', encoding='utf-8') as input:
11 | for line in input:
12 |
13 | if line.startswith('#include "'):
14 | next = line[10 : -2]
15 |
16 | if next not in included:
17 | nextTokens = next.split("/")
18 | included.append(nextTokens[-1])
19 |
20 | #output.write("// inlined '" + pathTokens[-1] + "' -> '" + nextTokens[-1] + "'\n")
21 |
22 | if len(nextTokens) == 1:
23 | mergeTo(folder, next, included, pragmaOnceCounter, output)
24 | else:
25 | mergeTo(folder + "/" + nextTokens[0], nextTokens[-1], included, pragmaOnceCounter, output)
26 | else:
27 | if line.startswith('\ufeff'):
28 | line = line[1:]
29 |
30 | if line.startswith('#pragma'):
31 | pragma = line[8:]
32 |
33 | if pragma.startswith('once'):
34 | pragmaOnceCounter += 1
35 | if pragmaOnceCounter > 1:
36 | continue
37 |
38 | elif pragma.startswith('region') or pragma.startswith('endregion'):
39 | continue
40 |
41 | output.write(line)
42 |
43 | ################################################################################
44 |
45 | output = open("../include/hfsm/machine_single.hpp", 'w', encoding='utf-8-sig')
46 | included = []
47 | pragmaOnceCounter = 0
48 | mergeTo("../include", "hfsm/machine.hpp", included, pragmaOnceCounter, output)
49 |
50 | output.close()
51 |
52 | ################################################################################
53 |
--------------------------------------------------------------------------------
/include/hfsm/detail/wrap.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace hfsm {
4 | namespace detail {
5 |
6 | //------------------------------------------------------------------------------
7 |
8 | template
9 | class Wrap;
10 |
11 | ////////////////////////////////////////////////////////////////////////////////
12 |
13 | template
14 | class Wrap {
15 | using Item = T;
16 | using Storage = typename std::aligned_storage::type;
17 |
18 | public:
19 | inline Wrap() = default;
20 |
21 | template
22 | inline void create(Ts&&... ts) { new (&get()) Item(std::forward(ts)...); }
23 |
24 | inline Wrap(const Item& item) { get() = item; }
25 | inline Wrap(Item&& item) { get() = std::move(item); }
26 |
27 | inline Wrap& operator = (const Item& item) { get() = item; return *this; }
28 | inline Wrap& operator = (Item&& item) { get() = std::move(item); return *this; }
29 |
30 | inline void clear() { fill(_storage, 0); }
31 |
32 | inline T& operator *() { return get(); }
33 | inline const T& operator *() const { return get(); }
34 |
35 | inline T* operator->() { return &get(); }
36 | inline const T* operator->() const { return &get(); }
37 |
38 | inline explicit operator bool() const { return _storage != 0; }
39 |
40 | inline bool operator == (const Wrap other) const { return get() == other.get(); }
41 |
42 | private:
43 | inline T& get() { return *reinterpret_cast< T* const>(&_storage); }
44 | inline const T& get() const { return *reinterpret_cast(&_storage); }
45 |
46 | private:
47 | Storage _storage;
48 | };
49 |
50 | ////////////////////////////////////////////////////////////////////////////////
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/include/hfsm/detail/array_view.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace hfsm {
4 | namespace detail {
5 |
6 | ////////////////////////////////////////////////////////////////////////////////
7 |
8 | #pragma pack(push, 4)
9 |
10 | template
11 | class ArrayView {
12 | public:
13 | using Item = T;
14 |
15 | template
16 | friend class Iterator;
17 |
18 | protected:
19 | ArrayView(const unsigned capacity);
20 | ~ArrayView();
21 |
22 | public:
23 | inline void clear() { _count = 0; }
24 |
25 | inline unsigned resize(const unsigned count);
26 |
27 | template
28 | inline unsigned operator << (TValue&& value);
29 |
30 | inline Item& operator[] (const unsigned i) { return get(i); }
31 | inline const Item& operator[] (const unsigned i) const { return get(i); }
32 |
33 | inline unsigned capacity() const { return _capacity; }
34 | inline unsigned count() const { return _count; }
35 |
36 | protected:
37 | inline unsigned first() const { return 0; }
38 | inline unsigned limit() const { return _count; }
39 |
40 | inline unsigned prev(const unsigned i) const { return i - 1; }
41 | inline unsigned next(const unsigned i) const { return i + 1; }
42 |
43 | inline Item& get(const unsigned i);
44 | inline const Item& get(const unsigned i) const;
45 |
46 | private:
47 | // hacks
48 | inline Item* data() { return reinterpret_cast< Item*>(&_count + 1); }
49 | inline const Item* data() const { return reinterpret_cast(&_count + 1); }
50 |
51 | protected:
52 | const unsigned _capacity;
53 | unsigned _count = 0;
54 | };
55 |
56 | #pragma pack(pop)
57 |
58 | ////////////////////////////////////////////////////////////////////////////////
59 |
60 | }
61 | }
62 |
63 | #include "array_view.inl"
64 |
--------------------------------------------------------------------------------
/projects/visual-studio/HFSM-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.6
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 |
--------------------------------------------------------------------------------
/include/hfsm/detail/array_view.inl:
--------------------------------------------------------------------------------
1 | namespace hfsm {
2 | namespace detail {
3 |
4 | ////////////////////////////////////////////////////////////////////////////////
5 |
6 | template
7 | ArrayView::ArrayView(const unsigned capacity)
8 | : _capacity(capacity)
9 | {}
10 |
11 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
12 |
13 | template
14 | ArrayView::~ArrayView() {
15 | if (_count > 0)
16 | for (int i = _count - 1; i >= 0; --i)
17 | get(i).~Item();
18 | }
19 |
20 | //------------------------------------------------------------------------------
21 |
22 | template
23 | unsigned
24 | ArrayView::resize(const unsigned count) {
25 | const unsigned clampedCount = count < _capacity ?
26 | count : _capacity;
27 |
28 | if (clampedCount > _count) {
29 | for (unsigned i = _count; i < clampedCount; ++i)
30 | get(i) = Item();
31 | }
32 | else if (clampedCount < _count) {
33 | for (unsigned i = _count - 1; i >= clampedCount; --i)
34 | get(i).~Item();
35 | }
36 |
37 | return _count = clampedCount;
38 | }
39 |
40 | //------------------------------------------------------------------------------
41 |
42 | template
43 | template
44 | unsigned
45 | ArrayView::operator << (TValue&& value) {
46 | assert(_count < _capacity);
47 |
48 | new (&get(_count)) Item(std::move(value));
49 |
50 | return _count++;
51 | }
52 |
53 | //------------------------------------------------------------------------------
54 |
55 | template
56 | T&
57 | ArrayView::get(const unsigned i) {
58 | assert(0 <= i && i < _capacity);
59 |
60 | return data()[i];
61 | }
62 |
63 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
64 |
65 | template
66 | const T&
67 | ArrayView::get(const unsigned i) const {
68 | assert(0 <= i && i < _capacity);
69 |
70 | return data()[i];
71 | }
72 |
73 | ////////////////////////////////////////////////////////////////////////////////
74 |
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/include/hfsm/detail/iterator.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "utility.hpp"
4 |
5 | namespace hfsm {
6 | namespace detail {
7 |
8 | ////////////////////////////////////////////////////////////////////////////////
9 |
10 | template
11 | class Iterator {
12 | public:
13 | using Container = TContainer;
14 | using Item = typename Container::Item;
15 |
16 | template
17 | friend class Array;
18 |
19 | private:
20 | inline Iterator(Container& container, const unsigned cursor)
21 | : _container(container)
22 | , _cursor(cursor)
23 | {}
24 |
25 | public:
26 | inline bool operator != (const Iterator& dummy) const;
27 |
28 | inline Iterator& operator ++();
29 |
30 | inline Item& operator *() { return _container[_cursor]; }
31 | inline const Item& operator *() const { return _container[_cursor]; }
32 |
33 | inline Item* operator->() { return &operator *(); }
34 | inline const Item* operator->() const { return &operator *(); }
35 |
36 | private:
37 | Container& _container;
38 |
39 | unsigned _cursor;
40 | };
41 |
42 | //------------------------------------------------------------------------------
43 |
44 | template
45 | class Iterator {
46 | public:
47 | using Container = TContainer;
48 | using Item = typename Container::Item;
49 |
50 | template
51 | friend class Array;
52 |
53 | private:
54 | inline Iterator(const Container& container, const unsigned cursor)
55 | : _container(container)
56 | , _cursor(cursor)
57 | {}
58 |
59 | public:
60 | inline bool operator != (const Iterator& dummy) const;
61 |
62 | inline Iterator& operator ++();
63 |
64 | inline const Item& operator *() const { return _container[_cursor]; }
65 |
66 | inline const Item* operator->() const { return &operator *(); }
67 |
68 | private:
69 | const Container& _container;
70 |
71 | unsigned _cursor;
72 | };
73 |
74 | ////////////////////////////////////////////////////////////////////////////////
75 |
76 | }
77 | }
78 |
79 | #include "iterator.inl"
80 |
--------------------------------------------------------------------------------
/include/hfsm/detail/array.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "array_view.hpp"
4 | #include "iterator.hpp"
5 |
6 | namespace hfsm {
7 | namespace detail {
8 |
9 | ////////////////////////////////////////////////////////////////////////////////
10 |
11 | #pragma pack(push, 4)
12 |
13 | template
14 | class StaticArray {
15 | public:
16 | enum {
17 | CAPACITY = TCapacity,
18 | };
19 |
20 | using Item = T;
21 | using Index = unsigned char; // TODO: adjust to CAPACITY
22 | static_assert(CAPACITY <= std::numeric_limits::max(), "");
23 |
24 | public:
25 | inline StaticArray() = default;
26 |
27 | inline Item& operator[] (const unsigned i);
28 | inline const Item& operator[] (const unsigned i) const;
29 |
30 | inline const unsigned count() const { return CAPACITY; }
31 |
32 | private:
33 | Item _items[CAPACITY];
34 | };
35 |
36 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
37 |
38 | template
39 | struct StaticArray {};
40 |
41 | //------------------------------------------------------------------------------
42 |
43 | template
44 | class Array
45 | : public ArrayView
46 | {
47 | public:
48 | enum : unsigned {
49 | CAPACITY = TCapacity,
50 | INVALID = (unsigned)-1,
51 | DUMMY = INVALID,
52 | };
53 |
54 | using View = ArrayView;
55 | using Item = typename View::Item;
56 |
57 | public:
58 | Array()
59 | : View(CAPACITY)
60 | {
61 | assert(&View::get(0) == _storage);
62 | }
63 |
64 | inline Iterator< Array> begin() { return Iterator< Array>(*this, View::first()); }
65 | inline Iterator begin() const { return Iterator(*this, View::first()); }
66 | inline Iterator cbegin() const { return Iterator(*this, View::first()); }
67 |
68 | inline Iterator< Array> end() { return Iterator< Array>(*this, DUMMY); }
69 | inline Iterator end() const { return Iterator(*this, DUMMY); }
70 | inline Iterator cend() const { return Iterator(*this, DUMMY); }
71 |
72 | private:
73 | Item _storage[CAPACITY];
74 | };
75 |
76 | #pragma pack(pop)
77 |
78 | ////////////////////////////////////////////////////////////////////////////////
79 |
80 | }
81 | }
82 |
83 | #include "array.inl"
84 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
2 | project(hfsm VERSION 0.1.0 LANGUAGES CXX)
3 |
4 | include(GNUInstallDirs)
5 |
6 | option(HFSM_BUILD_TESTS "Enable/disable building test executable" ON)
7 |
8 | set(CMAKE_CXX_STANDARD 14)
9 | set(CMAKE_CXX_EXTENSIONS OFF)
10 |
11 | set(extra_cxx_flags "-Wall -Wno-unknown-pragmas -Werror")
12 | set(CMAKE_CXX_FLAGS "${extra_cxx_flags} ${CMAKE_CXX_FLAGS}")
13 | set(CMAKE_C_FLAGS "${extra_cxx_flags} ${CMAKE_C_FLAGS}")
14 |
15 | #-------------------------------------------------------------------------------
16 | # hfsm target
17 | #-------------------------------------------------------------------------------
18 | add_library(hfsm INTERFACE)
19 | target_include_directories(
20 | hfsm INTERFACE
21 | "$"
22 | "$"
23 | )
24 |
25 | #-------------------------------------------------------------------------------
26 | # Install & export targets
27 | #-------------------------------------------------------------------------------
28 | set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
29 | set(include_install_dir "${CMAKE_INSTALL_INCLUDEDIR}")
30 | set(version_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
31 | set(project_config "${PROJECT_NAME}Config.cmake")
32 | set(targets_export_name "${PROJECT_NAME}Targets")
33 | set(namespace "${PROJECT_NAME}::")
34 |
35 | # Generate package version file.
36 | include(CMakePackageConfigHelpers)
37 | write_basic_package_version_file(
38 | "${version_config}" COMPATIBILITY SameMajorVersion
39 | )
40 |
41 | # Export hfsm target.
42 | install(
43 | TARGETS hfsm
44 | EXPORT "${targets_export_name}"
45 | INCLUDES DESTINATION "${include_install_dir}"
46 | )
47 |
48 | # Install hfsm headers.
49 | install(
50 | DIRECTORY "include/${PROJECT_NAME}"
51 | DESTINATION "${include_install_dir}"
52 | )
53 |
54 | # Install project version file.
55 | install(
56 | FILES "${version_config}"
57 | DESTINATION "${config_install_dir}"
58 | )
59 |
60 | # Install project config file.
61 | install(
62 | EXPORT "${targets_export_name}"
63 | NAMESPACE "${namespace}"
64 | DESTINATION "${config_install_dir}"
65 | FILE ${project_config}
66 | )
67 |
68 | # Export build directory config file.
69 | export(
70 | EXPORT ${targets_export_name}
71 | NAMESPACE "${namespace}"
72 | FILE ${project_config}
73 | )
74 |
75 | # Register project in CMake user registry.
76 | export(PACKAGE ${PROJECT_NAME})
77 |
78 | if(HFSM_BUILD_TESTS)
79 | enable_testing()
80 | add_subdirectory(test)
81 | endif(HFSM_BUILD_TESTS)
82 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at andrew.gresyk@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/include/hfsm/detail/hash_table.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "utility.hpp"
4 | #include "wrap.hpp"
5 |
6 | namespace hfsm {
7 | namespace detail {
8 |
9 | ////////////////////////////////////////////////////////////////////////////////
10 | // Open-addressing, Robin Hood hashing associative container
11 |
12 | template >
16 | class HashTable {
17 | public:
18 | enum : unsigned {
19 | REQUESTED_CAPACITY = TCapacity,
20 | CAPACITY = NextPowerOf2::Value,
21 | INDEX_MASK = CAPACITY - 1,
22 | USED_SHIFT = 31u,
23 | USED_MASK = 1u << USED_SHIFT,
24 | HASH_MASK = ~USED_MASK,
25 | INVALID = (unsigned)-1,
26 | DUMMY = INVALID,
27 | };
28 | static_assert(CAPACITY <= HASH_MASK, "Capacity needs to be less than HASH_MASK 0x7fffffff");
29 |
30 | using Hash = unsigned;
31 | using Key = TKey;
32 | using Value = TValue;
33 | using Hasher = THasher;
34 |
35 | //----------------------------------------------------------------------
36 |
37 | class Item {
38 | public:
39 | inline Item() = default;
40 |
41 | inline Item(const Hash hash, const Key key);
42 | inline Item(const Hash hash, const Key key, const Value value);
43 |
44 | inline void swap(Item& other);
45 | inline bool operator == (const Item& other) const;
46 |
47 | inline unsigned hash() const { return _hash & HASH_MASK; }
48 |
49 | inline bool vacant() const { return _hash >> USED_SHIFT == 0; }
50 | inline bool occupied() const { return _hash >> USED_SHIFT != 0; }
51 | inline void vacate() { _hash &= !USED_MASK; }
52 |
53 | inline const Key& key() const { return *_keyWrap; }
54 |
55 | inline Value* value() { return &_value; }
56 | inline const Value* value() const { return &_value; }
57 |
58 | private:
59 | Hash _hash = 0;
60 | Wrap _keyWrap;
61 | Value _value;
62 | };
63 | typedef Item Items[CAPACITY];
64 |
65 | //----------------------------------------------------------------------
66 |
67 | struct Stats {
68 | inline Stats(const float loadFactor_, const float averageProbeCount_)
69 | : loadFactor(loadFactor_)
70 | , averageProbeCount(averageProbeCount_)
71 | {}
72 |
73 | float loadFactor = 0.0f;
74 | float averageProbeCount = 0.0f;
75 | };
76 |
77 | //----------------------------------------------------------------------
78 |
79 | public:
80 | HashTable() = default;
81 |
82 | bool insert(const Key key, const Value value);
83 |
84 | Value* find(const Key key);
85 | const Value* find(const Key key) const;
86 |
87 | inline unsigned count() const { return _count; }
88 |
89 | private:
90 | unsigned locate(const Key key) const;
91 |
92 | inline unsigned probeCount(const unsigned i) const;
93 |
94 | inline unsigned index(const unsigned hash) const { return hash & INDEX_MASK; }
95 | inline unsigned hash(const Key key) const { return Hasher()(key) & HASH_MASK; }
96 |
97 | inline unsigned skipVacantForward(const unsigned i) const;
98 |
99 | private:
100 | Items _items;
101 | unsigned _count = 0;
102 | };
103 |
104 | ////////////////////////////////////////////////////////////////////////////////
105 |
106 | }
107 | }
108 |
109 | #include "hash_table.inl"
110 |
--------------------------------------------------------------------------------
/include/hfsm/detail/machine_state.hpp:
--------------------------------------------------------------------------------
1 | namespace hfsm {
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 |
5 | template
6 | template
7 | struct M::_S {
8 | using Head = TH;
9 |
10 | enum : unsigned {
11 | ReverseDepth = 1,
12 | DeepWidth = 0,
13 | StateCount = 1,
14 | ForkCount = 0,
15 | ProngCount = 0,
16 | Width = 1,
17 | };
18 |
19 | _S(StateRegistry& stateRegistry,
20 | const Parent parent,
21 | Parents& stateParents,
22 | Parents& forkParents,
23 | ForkPointers& forkPointers);
24 |
25 | inline void deepForwardSubstitute (Control&, Context&, LoggerInterface* const) {}
26 | inline bool deepSubstitute (Control& control, Context& context, LoggerInterface* const logger);
27 |
28 | inline void deepEnterInitial ( Context& context, LoggerInterface* const logger);
29 | inline void deepEnter ( Context& context, LoggerInterface* const logger);
30 |
31 | inline bool deepUpdateAndTransition (Control& control, Context& context, LoggerInterface* const logger);
32 | inline void deepUpdate ( Context& context, LoggerInterface* const logger);
33 |
34 | template
35 | inline void deepReact (const TEvent& event,
36 | Control& control, Context& context, LoggerInterface* const logger);
37 |
38 | inline void deepLeave ( Context& context, LoggerInterface* const logger);
39 |
40 | inline void deepForwardRequest(const enum Transition::Type) {}
41 | inline void deepRequestRemain() {}
42 | inline void deepRequestRestart() {}
43 | inline void deepRequestResume() {}
44 | inline void deepChangeToRequested ( Context&, LoggerInterface* const) {}
45 |
46 | #if defined HFSM_ENABLE_STRUCTURE_REPORT || defined HFSM_ENABLE_LOG_INTERFACE
47 | static constexpr bool isBare() { return std::is_same::value; }
48 |
49 | enum : unsigned {
50 | NameCount = isBare() ? 0 : 1,
51 | };
52 | #endif
53 |
54 | #ifdef HFSM_ENABLE_STRUCTURE_REPORT
55 | static const char* name();
56 |
57 | void deepGetNames(const unsigned parent,
58 | const enum StateInfo::RegionType region,
59 | const unsigned depth,
60 | StateInfos& stateInfos) const;
61 |
62 | void deepIsActive(const bool isActive,
63 | unsigned& index,
64 | MachineStructure& structure) const;
65 | #endif
66 |
67 | #ifdef HFSM_ENABLE_LOG_INTERFACE
68 | static const char* fullName();
69 |
70 | template
71 | struct MemberTraits;
72 |
73 | template
74 | struct MemberTraits {
75 | using State = TState;
76 | };
77 |
78 | template
79 | typename std::enable_if< std::is_same::State, Base>::value>::type
80 | log(LoggerInterface&) const {}
81 |
82 | template
83 | typename std::enable_if::State, Base>::value>::type
84 | log(LoggerInterface& logger) const {
85 | logger.record(typeid(Head), fullName(), TMethodId, methodName(TMethodId));
86 | }
87 | #endif
88 |
89 | Head _head;
90 |
91 | HSFM_IF_DEBUG(const TypeInfo _type = TypeInfo::get());
92 | };
93 |
94 | ////////////////////////////////////////////////////////////////////////////////
95 |
96 | }
97 |
98 | #include "machine_state_methods.inl"
99 |
--------------------------------------------------------------------------------
/projects/visual-studio/HFSM.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {25afde4c-8636-489f-9a74-e87f38b09cb9}
6 |
7 |
8 | {25fa5477-2735-467a-a226-594457ffc81b}
9 |
10 |
11 | {bcadbaf6-c69d-493f-b835-a441b888682d}
12 |
13 |
14 |
15 |
16 | test
17 |
18 |
19 |
20 |
21 | hfsm
22 |
23 |
24 | hfsm\detail
25 |
26 |
27 | hfsm\detail
28 |
29 |
30 | hfsm\detail
31 |
32 |
33 | hfsm\detail
34 |
35 |
36 | hfsm\detail
37 |
38 |
39 | hfsm\detail
40 |
41 |
42 | hfsm\detail
43 |
44 |
45 | hfsm
46 |
47 |
48 |
49 |
50 | hfsm\detail
51 |
52 |
53 | hfsm\detail
54 |
55 |
56 | hfsm\detail
57 |
58 |
59 | hfsm\detail
60 |
61 |
62 | hfsm\detail
63 |
64 |
65 | hfsm\detail
66 |
67 |
68 | hfsm\detail
69 |
70 |
71 | hfsm\detail
72 |
73 |
74 | hfsm\detail
75 |
76 |
77 | hfsm\detail
78 |
79 |
80 | hfsm\detail
81 |
82 |
83 | hfsm\detail
84 |
85 |
86 | hfsm\detail
87 |
88 |
89 | hfsm\detail
90 |
91 |
92 | hfsm\detail
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/include/hfsm/detail/utility.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #if defined _DEBUG && _MSC_VER
4 | #include // __debugbreak()
5 | #endif
6 |
7 | //------------------------------------------------------------------------------
8 |
9 | #if defined _DEBUG && _MSC_VER
10 | #define HSFM_BREAK() __debugbreak()
11 | #define HSFM_CHECKED(x) (!!(x) || (HSFM_BREAK(), 0))
12 | #else
13 | #define HSFM_BREAK() ((void) 0)
14 | #define HSFM_CHECKED(x) x
15 | #endif
16 |
17 | #ifdef _DEBUG
18 | #define HSFM_IF_DEBUG(...) __VA_ARGS__
19 | #else
20 | #define HSFM_IF_DEBUG(...)
21 | #endif
22 |
23 | #ifndef NDEBUG
24 | #define HSFM_IF_ASSERT(...) __VA_ARGS__
25 | #else
26 | #define HSFM_IF_ASSERT(...)
27 | #endif
28 |
29 | //------------------------------------------------------------------------------
30 |
31 | namespace hfsm {
32 | namespace detail {
33 |
34 | ////////////////////////////////////////////////////////////////////////////////
35 |
36 | template
37 | inline
38 | void
39 | fill(T& a, const char value) {
40 | memset(&a, (int) value, sizeof(a));
41 | }
42 |
43 | ////////////////////////////////////////////////////////////////////////////////
44 |
45 | template
46 | inline
47 | unsigned
48 | count(const T(&)[TCount]) {
49 | return TCount;
50 | }
51 |
52 | //------------------------------------------------------------------------------
53 |
54 | template
55 | inline
56 | const T*
57 | end(const T(& a)[TCapacity]) {
58 | return &a[TCapacity];
59 | }
60 |
61 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62 |
63 | template
64 | inline
65 | const TReturn*
66 | end(const T(& a)[TCapacity]) {
67 | return reinterpret_cast(&a[TCapacity]);
68 | }
69 |
70 | ////////////////////////////////////////////////////////////////////////////////
71 |
72 | template
73 | struct Min {
74 | enum {
75 | Value = t1 < t2 ? t1 : t2
76 | };
77 | };
78 |
79 | //------------------------------------------------------------------------------
80 |
81 | template
82 | struct Max {
83 | enum {
84 | Value = t1 > t2 ? t1 : t2
85 | };
86 | };
87 |
88 | ////////////////////////////////////////////////////////////////////////////////
89 |
90 | template
91 | struct PowerOf2 {
92 | enum {
93 | Value = !(t & (t - 1))
94 | };
95 | };
96 |
97 | //------------------------------------------------------------------------------
98 |
99 | template
100 | struct BitCount {
101 | enum {
102 | Value =
103 | t == 0 ? 0 :
104 | t >> 1 == 0 ? 1 :
105 | t >> 2 == 0 ? 2 :
106 | t >> 3 == 0 ? 3 :
107 | t >> 4 == 0 ? 4 :
108 | t >> 5 == 0 ? 5 :
109 | t >> 6 == 0 ? 6 :
110 | t >> 7 == 0 ? 7 :
111 |
112 | t >> 8 == 0 ? 8 :
113 | t >> 9 == 0 ? 9 :
114 | t >> 10 == 0 ? 10 :
115 | t >> 11 == 0 ? 11 :
116 | t >> 12 == 0 ? 12 :
117 | t >> 13 == 0 ? 13 :
118 | t >> 14 == 0 ? 14 :
119 | t >> 15 == 0 ? 15 :
120 |
121 | t >> 16 == 0 ? 16 :
122 | t >> 17 == 0 ? 17 :
123 | t >> 18 == 0 ? 18 :
124 | t >> 19 == 0 ? 19 :
125 | t >> 20 == 0 ? 20 :
126 | t >> 21 == 0 ? 21 :
127 | t >> 22 == 0 ? 22 :
128 | t >> 23 == 0 ? 23 :
129 |
130 | t >> 24 == 0 ? 24 :
131 | t >> 25 == 0 ? 25 :
132 | t >> 26 == 0 ? 26 :
133 | t >> 27 == 0 ? 27 :
134 | t >> 28 == 0 ? 28 :
135 | t >> 29 == 0 ? 29 :
136 | t >> 30 == 0 ? 30 :
137 | t >> 31 == 0 ? 31 :
138 | 32
139 | };
140 | };
141 |
142 | //------------------------------------------------------------------------------
143 |
144 | template
145 | struct NextPowerOf2 {
146 | enum {
147 | Value = PowerOf2::Value ?
148 | t : 1 << BitCount::Value
149 | };
150 | };
151 |
152 | ////////////////////////////////////////////////////////////////////////////////
153 |
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://en.wikipedia.org/wiki/C%2B%2B#Standardization)
2 | [](https://opensource.org/licenses/MIT)
3 | [](https://ci.appveyor.com/project/andrew-gresyk/hfsm)
4 | [](https://travis-ci.org/andrew-gresyk/HFSM)
5 |
6 | # HFSM (Hierarchical Finite State Machine) Framework
7 |
8 | Header-only heriarchical FSM framework in C++14, completely static (no dynamic allocations), built with variadic templates.
9 |
10 | ## Compiler Support
11 |
12 | DEPRECATED, FURTHER DEVELOPMENT CONTINUES IN [HFSM2](https://github.com/andrew-gresyk/HFSM2)
13 |
14 | ## Compiler Support
15 |
16 | - Visual Studio 14.u3, 15.7
17 | - GCC 4.9, 5.4, 6.3, 7.3, 8.0
18 | - Clang 3.6, 3.7, 3.8, 3.9, 4.0, 5.0, 6.0
19 |
20 | ---
21 |
22 | ## Basic Usage
23 |
24 | ```cpp
25 | // 1. Include HFSM header:
26 | #include
27 |
28 | // 2. Define interface class between the FSM and its owner
29 | // (also ok to use the owner object itself):
30 | struct Context { /* ... */ };
31 |
32 | // 3. (Optional) Typedef hfsm::Machine for convenience:
33 | using M = hfsm::Machine;
34 |
35 | // 4. Define states:
36 | struct MyState1 : M::Bare {
37 | // 5. Override some of the following state functions:
38 | void enter(Context& _);
39 | void update(Context& _);
40 | void transition(Control& c, Context& _);
41 | void leave(Context& _);
42 | };
43 |
44 | struct MyState2 : M::Bare { /* .. */ };
45 | struct MySubState1 : M::Bare { /* .. */ };
46 | struct MySubState2 : M::Bare { /* .. */ };
47 |
48 | struct MyState3 : M::Bare { /* .. */ };
49 | struct MyOrthogonalState1 : M::Bare { /* .. */ };
50 | struct MyOrthogonalState2 : M::Bare { /* .. */ };
51 |
52 | // 6. Declare state machine structure:
53 | using MyFSM = M::PeerRoot<
54 | MyState1,
55 | M::Composite,
59 | M::Orthogonal
63 | >;
64 |
65 | int main() {
66 | // 7. Create context and state machine instances:
67 | Context context;
68 | MyFSM fsm(context);
69 |
70 | // 8. Kick off periodic updates:
71 | bool running = true;
72 | while (running)
73 | fsm.update();
74 |
75 | return 0;
76 | }
77 | ```
78 |
79 | ---
80 |
81 | ## Feature Highlights
82 |
83 | - Permissive [MIT License](LICENSE.md)
84 | - Written in widely-supported modern(ish) C++ 14
85 | - 100% NoUML-compliant
86 | - Not hamstrung by restrictive event reaction-based approach, but supports powerful event handling
87 | - Hierarchical, with composite (sub-machine) and orthogonal regions
88 | - Header-only
89 | - Fully static, no dynamic allocations
90 | - Uses inline-friendly compile-time pylymorphism, no virtual methods were harmed
91 | - Type-safe transitions: `FSM.changeTo()`
92 | - Gamedev-friendly, supports explicit `State::update()`
93 | - Scaleable, supports state re-use via state injections
94 | - Debug-assisted, includes automatic structure and activity visualization API with `#define HFSM_ENABLE_STRUCTURE_REPORT`
95 | - Convenient, minimal boilerplate
96 |
97 | ---
98 |
99 | ## Documentation
100 |
101 | See [Wiki](../../wiki) for [Tutorial](../../wiki/Tutorial) and docs.
102 |
103 | ---
104 |
105 | ## Get Updates
106 |
107 | - [Blog](https://andrew-gresyk.github.io/)
108 | - [Twitter](https://www.twitter.com/andrew_gresyk)
109 |
110 | ---
111 |
112 | ## Special Thanks
113 |
114 | - [Phil Nash](https://github.com/philsquared)
115 | - [Romain Cheminade](https://github.com/romaincheminade)
116 | - [Tristan Brindle](https://github.com/tcbrindle)
117 | - [Kevin Greene](https://github.com/kgreenek)
118 | - everybody at [C++::London](https://www.meetup.com/CppLondon/) meetup
119 | - programming community at [Splash Damage](http://www.splashdamage.com/)
--------------------------------------------------------------------------------
/examples/basic_streetlight/main.cpp:
--------------------------------------------------------------------------------
1 | // HFSM (hierarchical state machine for games and interactive applications)
2 | // Created by Andrew Gresyk
3 | //
4 | // Streetlight FSM 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 HFSM_ENABLE_STRUCTURE_REPORT
37 |
38 | #include
39 |
40 | #include
41 |
42 | //------------------------------------------------------------------------------
43 |
44 | // data shared between FSM states and outside code
45 | struct Context {
46 | unsigned cycleCount;
47 | };
48 |
49 | // convenience typedef
50 | using M = hfsm::Machine;
51 |
52 | ////////////////////////////////////////////////////////////////////////////////
53 |
54 | // forward declared for Red::transition()
55 | struct Off;
56 |
57 | // top-level region in the hierarchy
58 | struct On
59 | : M::Base // necessary boilerplate!
60 | {
61 | // called on state entry
62 | void enter(Context& context) {
63 | context.cycleCount = 0;
64 | std::cout << "On" << std::endl;
65 | }
66 |
67 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68 |
69 | // forward declared for Red::transition()
70 | struct YellowDownwards;
71 |
72 | // sub-states
73 | struct Red
74 | : M::Base
75 | {
76 | void enter(Context& context) {
77 | ++context.cycleCount;
78 | std::cout << " Red" << std::endl;
79 | }
80 |
81 | // state can initiate transitions to _any_ other state
82 | void transition(Control& control, Context& context) {
83 | // multiple transitions can be initiated, can be useful in a hierarchy
84 | if (context.cycleCount > 3)
85 | control.changeTo();
86 | else
87 | control.changeTo();
88 | }
89 | };
90 |
91 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
92 |
93 | // forward declared for transition()
94 | struct Green;
95 |
96 | struct YellowDownwards
97 | : M::Base
98 | {
99 | void enter(Context&) {
100 | std::cout << " Yellow v" << std::endl;
101 | }
102 |
103 | void transition(Control& control, Context&) {
104 | control.changeTo();
105 | }
106 | };
107 |
108 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
109 |
110 | struct YellowUpwards
111 | : M::Base
112 | {
113 | void enter(Context&) {
114 | std::cout << " Yellow ^" << std::endl;
115 | }
116 |
117 | void transition(Control& control, Context&) {
118 | control.changeTo();
119 | }
120 | };
121 |
122 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123 |
124 | struct Green
125 | : M::Base
126 | {
127 | void enter(Context&) {
128 | std::cout << " Green" << std::endl;
129 | }
130 |
131 | void transition(Control& control, Context&) {
132 | control.changeTo();
133 | }
134 | };
135 |
136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137 | };
138 |
139 | //------------------------------------------------------------------------------
140 |
141 | // another top-level state
142 | struct Off
143 | : M::Base
144 | {
145 | void enter(Context&) {
146 | std::cout << "Off" << std::endl;
147 | }
148 | };
149 |
150 | ////////////////////////////////////////////////////////////////////////////////
151 |
152 | int
153 | main() {
154 | // shared data storage instance
155 | Context context;
156 |
157 | // state machine structure
158 | M::PeerRoot<
159 | // sub-machine ..
160 | M::Composite,
167 | Off
168 | > machine(context);
169 |
170 | while (machine.isActive() == false)
171 | machine.update();
172 |
173 | return 0;
174 | }
175 |
176 | ////////////////////////////////////////////////////////////////////////////////
177 |
--------------------------------------------------------------------------------
/include/hfsm/detail/hash_table.inl:
--------------------------------------------------------------------------------
1 | namespace hfsm {
2 | namespace detail {
3 |
4 | ////////////////////////////////////////////////////////////////////////////////
5 |
6 | template
7 | HashTable::Item::Item(const Hash hash, const Key key)
8 | : _hash(hash | USED_MASK)
9 | , _keyWrap(key)
10 | {}
11 |
12 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13 |
14 | template
15 | HashTable::Item::Item(const Hash hash, const Key key, const Value value)
16 | : _hash(hash | USED_MASK)
17 | , _keyWrap(key)
18 | , _value(value)
19 | {}
20 |
21 | //------------------------------------------------------------------------------
22 |
23 | template
24 | void
25 | HashTable::Item::swap(Item& other) {
26 | std::swap(_hash, other._hash);
27 | std::swap(_keyWrap, other._keyWrap);
28 | std::swap(_value, other._value);
29 | }
30 |
31 | //------------------------------------------------------------------------------
32 |
33 | template
34 | bool
35 | HashTable::Item::operator == (const Item& other) const {
36 | return _hash == other._hash && *_keyWrap == *other._keyWrap;
37 | }
38 |
39 | ////////////////////////////////////////////////////////////////////////////////
40 |
41 | template
42 | bool
43 | HashTable::insert(const Key key, const Value value) {
44 | assert(_count < CAPACITY);
45 |
46 | if (_count < CAPACITY) {
47 | Item newcomer(hash(key), key, value);
48 |
49 | for (unsigned i = index(newcomer.hash()), newcomerDistance = 0;
50 | ;
51 | i = index(i + 1), ++newcomerDistance)
52 | {
53 | Item& resident = _items[i];
54 |
55 | if (resident.occupied()) {
56 | const unsigned residentDistance = probeCount(i);
57 |
58 | if (newcomerDistance > residentDistance) {
59 | newcomerDistance = residentDistance;
60 |
61 | std::swap(newcomer, resident);
62 | }
63 | }
64 | else {
65 | resident = newcomer;
66 | ++_count;
67 |
68 | return true;
69 | }
70 |
71 | assert(newcomerDistance < CAPACITY);
72 | }
73 | }
74 | else
75 | return false;
76 | }
77 |
78 | //------------------------------------------------------------------------------
79 |
80 | template
81 | typename HashTable::Value*
82 | HashTable::find(const Key key) {
83 | const unsigned index = locate(key);
84 |
85 | return index != INVALID ?
86 | _items[index].value() : nullptr;
87 | }
88 |
89 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
90 |
91 | template
92 | const typename HashTable::Value*
93 | HashTable::find(const Key key) const {
94 | const unsigned index = locate(key);
95 |
96 | return index != INVALID ?
97 | _items[index].value() : nullptr;
98 | }
99 |
100 | //------------------------------------------------------------------------------
101 |
102 | template
103 | unsigned
104 | HashTable::locate(const Key key) const {
105 | const Item item(hash(key), key);
106 |
107 | for (unsigned i = index(item.hash()), distance = 0;
108 | ;
109 | i = index(i + 1), ++distance)
110 | {
111 | const Item& resident = _items[i];
112 |
113 | if (item == resident)
114 | return i;
115 | else if (distance > probeCount(i))
116 | return INVALID;
117 |
118 | assert(distance < CAPACITY);
119 | }
120 | }
121 |
122 | //------------------------------------------------------------------------------
123 |
124 | template
125 | unsigned
126 | HashTable::probeCount(const unsigned i) const {
127 | assert(i < CAPACITY);
128 |
129 | return index(CAPACITY + i - index(_items[i].hash()));
130 | }
131 |
132 | //------------------------------------------------------------------------------
133 |
134 | template
135 | unsigned
136 | HashTable::skipVacantForward(const unsigned i) const {
137 | assert(0 <= i && i <= CAPACITY);
138 |
139 | if (i < CAPACITY) {
140 | unsigned n = i;
141 | for (; _items[n].vacant(); ++n)
142 | if (n < CAPACITY)
143 | continue;
144 | else
145 | return CAPACITY;
146 |
147 | return n;
148 | }
149 | else
150 | return i;
151 | }
152 |
153 | ////////////////////////////////////////////////////////////////////////////////
154 |
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/projects/visual-studio/HFSM.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2036
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_", "_", "{498EF6B0-5565-411A-839A-B41294202103}"
7 | ProjectSection(SolutionItems) = preProject
8 | ..\..\.gitignore = ..\..\.gitignore
9 | ..\..\.travis.yml = ..\..\.travis.yml
10 | ..\..\appveyor.yml = ..\..\appveyor.yml
11 | ..\..\CMakeLists.txt = ..\..\CMakeLists.txt
12 | ..\..\README.md = ..\..\README.md
13 | EndProjectSection
14 | EndProject
15 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HFSM", "HFSM.vcxproj", "{0895F78B-D3D4-4BEF-8E12-DAABE32686E5}"
16 | EndProject
17 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "HFSM-tools", "HFSM-tools.pyproj", "{2347027E-E5DE-43C4-8EF9-5F1411ADE33B}"
18 | EndProject
19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{EDEB0687-3B3E-429D-9213-0A3EED99821D}"
20 | EndProject
21 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic_streetlight", "basic_streetlight.vcxproj", "{C543B4D9-A8AC-47B7-8376-AB4B110C144E}"
22 | EndProject
23 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic_event", "basic_event.vcxproj", "{AA58BDD0-0F56-43E9-816C-37BA6C30F97C}"
24 | EndProject
25 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic_logger_interface", "basic_logger_interface.vcxproj", "{E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}"
26 | EndProject
27 | Global
28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
29 | Debug|32 = Debug|32
30 | Debug|64 = Debug|64
31 | Release|32 = Release|32
32 | Release|64 = Release|64
33 | EndGlobalSection
34 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
35 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Debug|32.ActiveCfg = Debug|Win32
36 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Debug|32.Build.0 = Debug|Win32
37 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Debug|64.ActiveCfg = Debug|x64
38 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Debug|64.Build.0 = Debug|x64
39 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Release|32.ActiveCfg = Release|Win32
40 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Release|32.Build.0 = Release|Win32
41 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Release|64.ActiveCfg = Release|x64
42 | {0895F78B-D3D4-4BEF-8E12-DAABE32686E5}.Release|64.Build.0 = Release|x64
43 | {2347027E-E5DE-43C4-8EF9-5F1411ADE33B}.Debug|32.ActiveCfg = Debug|Any CPU
44 | {2347027E-E5DE-43C4-8EF9-5F1411ADE33B}.Debug|64.ActiveCfg = Debug|Any CPU
45 | {2347027E-E5DE-43C4-8EF9-5F1411ADE33B}.Release|32.ActiveCfg = Release|Any CPU
46 | {2347027E-E5DE-43C4-8EF9-5F1411ADE33B}.Release|64.ActiveCfg = Release|Any CPU
47 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Debug|32.ActiveCfg = Debug|Win32
48 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Debug|32.Build.0 = Debug|Win32
49 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Debug|64.ActiveCfg = Debug|x64
50 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Debug|64.Build.0 = Debug|x64
51 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Release|32.ActiveCfg = Release|Win32
52 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Release|32.Build.0 = Release|Win32
53 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Release|64.ActiveCfg = Release|x64
54 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}.Release|64.Build.0 = Release|x64
55 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Debug|32.ActiveCfg = Debug|Win32
56 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Debug|32.Build.0 = Debug|Win32
57 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Debug|64.ActiveCfg = Debug|x64
58 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Debug|64.Build.0 = Debug|x64
59 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Release|32.ActiveCfg = Release|Win32
60 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Release|32.Build.0 = Release|Win32
61 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Release|64.ActiveCfg = Release|x64
62 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}.Release|64.Build.0 = Release|x64
63 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Debug|32.ActiveCfg = Debug|Win32
64 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Debug|32.Build.0 = Debug|Win32
65 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Debug|64.ActiveCfg = Debug|x64
66 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Debug|64.Build.0 = Debug|x64
67 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Release|32.ActiveCfg = Release|Win32
68 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Release|32.Build.0 = Release|Win32
69 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Release|64.ActiveCfg = Release|x64
70 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}.Release|64.Build.0 = Release|x64
71 | EndGlobalSection
72 | GlobalSection(SolutionProperties) = preSolution
73 | HideSolutionNode = FALSE
74 | EndGlobalSection
75 | GlobalSection(NestedProjects) = preSolution
76 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E} = {EDEB0687-3B3E-429D-9213-0A3EED99821D}
77 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C} = {EDEB0687-3B3E-429D-9213-0A3EED99821D}
78 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E} = {EDEB0687-3B3E-429D-9213-0A3EED99821D}
79 | EndGlobalSection
80 | GlobalSection(ExtensibilityGlobals) = postSolution
81 | SolutionGuid = {3BE666E0-1098-42CF-B1FD-F0F0CA579F4C}
82 | EndGlobalSection
83 | EndGlobal
84 |
--------------------------------------------------------------------------------
/examples/debug_logger_interface/main.cpp:
--------------------------------------------------------------------------------
1 | // HFSM (hierarchical state machine for games and interactive applications)
2 | // Created by Andrew Gresyk
3 | //
4 | // Attachable logger example
5 |
6 | // Full output:
7 | //
8 | // --- ctor: ---
9 | //
10 | // Top::enter()
11 | // Top::From::enter()
12 | //
13 | // -- update: --
14 | //
15 | // Top::update()
16 | // Top::transition()
17 | // Top::From::update()
18 | // Top::From::transition()
19 | //
20 | // -- react: ---
21 | //
22 | // Top::react()
23 | // Top::From::react()
24 | // Top::To::substitute()
25 | // Top::From::leave()
26 | // Top::To::enter()
27 | //
28 | // -- detach: --
29 | //
30 | //
31 | // --- dtor: ---
32 | //
33 | // Top::To::leave()
34 | // Top::leave()
35 | //
36 | // --- done! ---
37 |
38 | // enable logger functionality
39 | #define HFSM_ENABLE_LOG_INTERFACE
40 | #include
41 |
42 | #include
43 |
44 | //------------------------------------------------------------------------------
45 |
46 | // data shared between FSM states and outside code
47 | struct Context {};
48 |
49 | // convenience typedef
50 | using M = hfsm::Machine;
51 |
52 | ////////////////////////////////////////////////////////////////////////////////
53 |
54 | struct Logger
55 | : hfsm::LoggerInterface
56 | {
57 | // hfsm::LoggerInterface
58 | void record(const std::type_index& /*state*/,
59 | const char* const stateName,
60 | const Method /*method*/,
61 | const char* const methodName) override
62 | {
63 | std::cout << stateName << "::" << methodName << "()\n";
64 | }
65 | };
66 |
67 | ////////////////////////////////////////////////////////////////////////////////
68 |
69 | // top-level state in the hierarchy
70 | struct Top
71 | : M::Base
72 | {
73 | // all state methods:
74 | void substitute(Control&, Context&) {} // not going to be called in this example
75 | void enter(Context&) {}
76 | void update(Context&) {}
77 | void transition(Control&, Context&) {}
78 | template
79 | void react(const TEvent&, Control&, Context&) {}
80 | void leave(Context&) {}
81 |
82 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
83 |
84 | // forward declared for Red::transition()
85 | struct To;
86 |
87 | // initial state
88 | struct From
89 | : M::Base // necessary boilerplate!
90 | {
91 | // all state methods:
92 | void substitute(Control&, Context&) {} // not going to be called in this example
93 | void enter(Context&) {}
94 | void update(Context&) {}
95 | void transition(Control&, Context&) {}
96 | template
97 | void react(const TEvent&, Control& control, Context&) { control.changeTo(); }
98 | void leave(Context&) {}
99 | };
100 |
101 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
102 |
103 | // transition target state
104 | struct To
105 | : M::Base
106 | {
107 | // all state methods:
108 | void substitute(Control&, Context&) {}
109 | void enter(Context&) {}
110 | void update(Context&) {}
111 | void transition(Control&, Context&) {}
112 | template
113 | void react(const TEvent&, Control&, Context&) {} // not going to be called in this example
114 | void leave(Context&) {}
115 | };
116 |
117 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
118 | };
119 |
120 | ////////////////////////////////////////////////////////////////////////////////
121 |
122 | int main() {
123 | using FSM = M::Root;
127 |
128 | {
129 | // shared data storage instance
130 | Context context;
131 |
132 | // logger
133 | Logger logger;
134 |
135 | std::cout << "--- ctor: ---\n\n";
136 |
137 | // state machine instance - all initial states are activated
138 | FSM machine(context, &logger);
139 |
140 | // output:
141 | // Top::enter()
142 | // Top::From::enter()
143 |
144 | std::cout << "\n-- update: --\n\n";
145 |
146 | // first update
147 | machine.update();
148 |
149 | // output:
150 | // Top::update()
151 | // Top::transition()
152 | // Top::From::update()
153 | // Top::From::transition()
154 |
155 | std::cout << "\n-- react: ---\n\n";
156 |
157 | machine.react(1);
158 |
159 | // output:
160 | // Top::react()
161 | // Top::From::react()
162 | // Top::To::substitute()
163 | // Top::From::leave()
164 | // Top::To::enter()
165 |
166 | std::cout << "\n-- detach: --\n\n";
167 |
168 | // detach logger and update again
169 | machine.attachLogger(nullptr);
170 | machine.update();
171 |
172 | // no output, since logger is detached
173 |
174 | std::cout << "\n--- dtor: ---\n\n";
175 |
176 | // re-attach logger for destruction log
177 | machine.attachLogger(&logger);
178 |
179 | // state machine instance gets destroyed
180 | }
181 |
182 | // output:
183 | // Top::To::leave()
184 | // Top::leave()
185 |
186 | std::cout << "\n--- done! ---\n\n";
187 |
188 | return 0;
189 | }
190 |
191 | ////////////////////////////////////////////////////////////////////////////////
192 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | #sudo: false
2 |
3 | language: cpp
4 |
5 | notifications:
6 | email: true
7 |
8 | os: linux
9 | dist: trusty
10 |
11 | env:
12 | global:
13 | - TMPDIR=/tmp
14 |
15 | matrix:
16 | include:
17 |
18 | # GCC 4.9
19 | - env: COMPILER=g++-4.9 BUILD_TYPE=Debug
20 | addons: &gcc49
21 | apt:
22 | packages: g++-4.9
23 | sources: ubuntu-toolchain-r-test
24 |
25 | - env: COMPILER=g++-4.9 BUILD_TYPE=Release
26 | addons: *gcc49
27 |
28 | # GCC 5
29 | - env: COMPILER=g++-5 BUILD_TYPE=Debug
30 | addons: &gcc5
31 | apt:
32 | packages: g++-5
33 | sources: ubuntu-toolchain-r-test
34 |
35 | - env: COMPILER=g++-5 BUILD_TYPE=Release
36 | addons: *gcc5
37 |
38 | # GCC 6
39 | - env: COMPILER=g++-6 BUILD_TYPE=Debug
40 | addons: &gcc6
41 | apt:
42 | packages: g++-6
43 | sources: ubuntu-toolchain-r-test
44 |
45 | - env: COMPILER=g++-6 BUILD_TYPE=Release
46 | addons: *gcc6
47 |
48 | # GCC 7
49 | - env: COMPILER=g++-7 BUILD_TYPE=Debug
50 | addons: &gcc7
51 | apt:
52 | packages: g++-7
53 | sources: ubuntu-toolchain-r-test
54 |
55 | - env: COMPILER=g++-7 BUILD_TYPE=Release
56 | addons: *gcc7
57 |
58 | # GCC 8
59 | - env: COMPILER=g++-8 BUILD_TYPE=Debug
60 | addons: &gcc8
61 | apt:
62 | packages: g++-8
63 | sources: ubuntu-toolchain-r-test
64 |
65 | - env: COMPILER=g++-8 BUILD_TYPE=Release
66 | addons: *gcc8
67 |
68 | # Clang 3.6
69 | - env: COMPILER=clang++-3.6 BUILD_TYPE=Debug
70 | addons: &clang36
71 | apt:
72 | packages:
73 | - clang-3.6
74 | - g++-5
75 | sources:
76 | - ubuntu-toolchain-r-test
77 | - llvm-toolchain-precise-3.6
78 |
79 | - env: COMPILER=clang++-3.6 BUILD_TYPE=Release
80 | addons: *clang36
81 |
82 | # Clang 3.7
83 | - env: COMPILER=clang++-3.7 BUILD_TYPE=Debug
84 | addons: &clang37
85 | apt:
86 | packages:
87 | - clang-3.7
88 | - g++-5
89 | sources:
90 | - ubuntu-toolchain-r-test
91 | - llvm-toolchain-precise-3.7
92 |
93 | - env: COMPILER=clang++-3.7 BUILD_TYPE=Release
94 | addons: *clang37
95 |
96 | # Clang 3.8
97 | - env: COMPILER=clang++-3.8 BUILD_TYPE=Debug
98 | addons: &clang38
99 | apt:
100 | packages:
101 | - clang-3.8
102 | - g++-5
103 | sources:
104 | - ubuntu-toolchain-r-test
105 | - llvm-toolchain-precise-3.8
106 |
107 | - env: COMPILER=clang++-3.8 BUILD_TYPE=Release
108 | addons: *clang38
109 |
110 | # Clang 3.9
111 | - env: COMPILER=clang++-3.9 BUILD_TYPE=Debug
112 | addons: &clang39
113 | apt:
114 | packages:
115 | - clang-3.9
116 | - g++-5
117 | sources:
118 | - ubuntu-toolchain-r-test
119 | - llvm-toolchain-precise-3.9
120 |
121 | - env: COMPILER=clang++-3.9 BUILD_TYPE=Release
122 | addons: *clang39
123 |
124 | # Clang 4.0
125 | - env: COMPILER=clang++-4.0 BUILD_TYPE=Debug
126 | addons: &clang4
127 | apt:
128 | packages:
129 | - clang-4.0
130 | - g++-5
131 | sources:
132 | - ubuntu-toolchain-r-test
133 | - llvm-toolchain-trusty-4.0
134 |
135 | - env: COMPILER=clang++-4.0 BUILD_TYPE=Release
136 | addons: *clang4
137 |
138 | # Clang 5.0
139 | - env: COMPILER=clang++-5.0 BUILD_TYPE=Debug
140 | addons: &clang5
141 | apt:
142 | packages:
143 | - clang-5.0
144 | - g++-5
145 | sources:
146 | - ubuntu-toolchain-r-test
147 | - llvm-toolchain-trusty-5.0
148 |
149 | - env: COMPILER=clang++-5.0 BUILD_TYPE=Release
150 | addons: *clang5
151 |
152 | # Clang 6.0
153 | - env: COMPILER=clang++-6.0 BUILD_TYPE=Debug
154 | addons: &clang6
155 | apt:
156 | packages:
157 | - clang-6.0
158 | - g++-6
159 | sources:
160 | - ubuntu-toolchain-r-test
161 | - llvm-toolchain-trusty-6.0
162 |
163 | - env: COMPILER=clang++-6.0 BUILD_TYPE=Release
164 | addons: *clang6
165 |
166 | script:
167 | - cd "${TRAVIS_BUILD_DIR}"
168 | - mkdir build && cd build
169 | - cmake .. -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=$TMPDIR/hfsm
170 | - make install
171 |
172 | - cd "${TRAVIS_BUILD_DIR}/examples/advanced_event_handling"
173 | - mkdir build && cd build
174 | - cmake .. -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=$BUILD_TYPE
175 | - make
176 |
177 | - cd "${TRAVIS_BUILD_DIR}/examples/basic_streetlight"
178 | - mkdir build && cd build
179 | - cmake .. -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=$BUILD_TYPE
180 | - make
181 |
182 | - cd "${TRAVIS_BUILD_DIR}/examples/debug_logger_interface"
183 | - mkdir build && cd build
184 | - cmake .. -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=$BUILD_TYPE
185 | - make
186 |
--------------------------------------------------------------------------------
/examples/advanced_event_handling/main.cpp:
--------------------------------------------------------------------------------
1 | // HFSM (hierarchical state machine for games and interactive applications)
2 | // Created by Andrew Gresyk
3 | //
4 | // Event handling example
5 |
6 | // Output:
7 | //
8 | // sending PrimaryEvent:
9 | // ConcreteHandler: reacting to PrimaryEvent
10 | // TemplateHandler: reacting to TEvent
11 | // EnableIfHandler: reacting to a
12 | //
13 | // sending SecondaryEvent:
14 | // ConcreteHandler: reacting to SecondaryEvent
15 | // TemplateHandler: reacting to TEvent
16 | // EnableIfHandler: reacting to a
17 | //
18 | // sending TransitionEvent:
19 | // Reactive: reacting to TransitionEvent (aka 'char')
20 | // TemplateHandler: reacting to TEvent
21 | // EnableIfHandler: reacting to a
22 | // changed to Target
23 |
24 | // optional: enable FSM structure report in debugger
25 | #define HFSM_ENABLE_STRUCTURE_REPORT
26 |
27 | #include
28 |
29 | #include
30 |
31 | //------------------------------------------------------------------------------
32 |
33 | struct Context {};
34 |
35 | using M = hfsm::Machine;
36 |
37 | struct PrimaryEvent {};
38 | struct SecondaryEvent { int payload; };
39 |
40 | using TransitionEvent = char;
41 |
42 | ////////////////////////////////////////////////////////////////////////////////
43 |
44 | // forward declared for Reactive::transition()
45 | struct Target;
46 |
47 | struct Reactive
48 | : M::Base
49 | {
50 | // handle a single event type - TransitionEvent
51 | void react(const TransitionEvent&, Control& control, Context&) {
52 | std::cout << " Reactive: reacting to TransitionEvent\n";
53 |
54 | control.changeTo();
55 | }
56 |
57 | // and ignore the other event types
58 | using M::Base::react;
59 |
60 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
61 |
62 | struct NonHandler
63 | : M::Base
64 | {
65 | // events are totally opt-in
66 | };
67 |
68 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
69 |
70 | struct ConcreteHandler
71 | : M::Base
72 | {
73 | // handle two event types - PrimaryEvent
74 | void react(const PrimaryEvent&, Control&, Context&) {
75 | std::cout << " ConcreteHandler: reacting to PrimaryEvent\n";
76 | }
77 |
78 | // and SecondaryEvent
79 | void react(const SecondaryEvent&, Control&, Context&) {
80 | std::cout << " ConcreteHandler: reacting to SecondaryEvent\n";
81 | }
82 |
83 | // and ignore the other event types
84 | using M::Base::react;
85 | };
86 |
87 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
88 |
89 | struct TemplateHandler
90 | : M::Base
91 | {
92 | // handle all possible event types
93 | template
94 | void react(const TEvent&, Control&, Context&) {
95 | std::cout << " TemplateHandler: reacting to TEvent\n";
96 | }
97 | };
98 |
99 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100 |
101 | struct EnableIfHandler
102 | : M::Base
103 | {
104 | // use std::enable_if to build more complex conditional event handling
105 | template
106 | typename std::enable_if::value>::type
107 | react(const TEvent&, Control&, Context&) {
108 | std::cout << " EnableIfHandler: reacting to a \n";
109 | }
110 |
111 | // but remember to cover all the remaining cases
112 | template
113 | typename std::enable_if::value>::type
114 | react(const TEvent&, Control&, Context&) {
115 | std::cout << " EnableIfHandler: reacting to a \n";
116 | }
117 | };
118 |
119 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
120 | };
121 |
122 | //------------------------------------------------------------------------------
123 |
124 | struct Target
125 | : M::Base
126 | {
127 | void enter(Context&) {
128 | std::cout << " changed to Target\n";
129 | }
130 | };
131 |
132 | ////////////////////////////////////////////////////////////////////////////////
133 |
134 | int
135 | main() {
136 | Context context;
137 |
138 | M::PeerRoot<
139 | M::Orthogonal,
145 | Target
146 | > machine(context);
147 |
148 | std::cout << "sending PrimaryEvent:\n";
149 | machine.react(PrimaryEvent{});
150 |
151 | // output:
152 | // ConcreteHandler: reacting to PrimaryEvent
153 | // TemplateHandler: reacting to TEvent
154 | // EnableIfHandler: reacting to a
155 |
156 | std::cout << "\nsending SecondaryEvent:\n";
157 | machine.react(SecondaryEvent{});
158 |
159 | // output:
160 | // ConcreteHandler: reacting to SecondaryEvent
161 | // TemplateHandler: reacting to TEvent
162 | // EnableIfHandler: reacting to a
163 |
164 | std::cout << "\nsending TransitionEvent (aka 'char'):\n";
165 | machine.react(TransitionEvent{});
166 |
167 | // output:
168 | // Reactive: reacting to TransitionEvent (aka 'char')
169 | // TemplateHandler: reacting to TEvent
170 | // EnableIfHandler: reacting to a
171 | // changed to Target
172 |
173 | std::cout<< std::endl;
174 | return 0;
175 | };
176 |
177 | ////////////////////////////////////////////////////////////////////////////////
178 |
--------------------------------------------------------------------------------
/hfsm.natvis:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {_Tptr->_Data._UndecoratedName,sb}
9 |
10 | {&_Tptr->_Data._DecoratedName[6],[strchr(_Tptr->_Data._DecoratedName,'@') - _Tptr->_Data._DecoratedName - 6]sb}
11 | <
12 | {strstr(_Tptr->_Data._DecoratedName,"@V") + 2,[strstr(_Tptr->_Data._DecoratedName,"@?") - strstr(_Tptr->_Data._DecoratedName,"@V") - 2]sb}
13 | >
14 |
15 | {&_Tptr->_Data._DecoratedName[4],[strchr(_Tptr->_Data._DecoratedName,'@') - _Tptr->_Data._DecoratedName - 4]sb}
16 |
17 |
18 |
19 |
20 |
21 |
22 | {_count} / {_capacity}
23 |
24 |
25 | _count
26 | *(($T1*) &((Item*) (&_count + 1))[$i])
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | {_count} / {_capacity}
35 |
36 |
37 | _count
38 | *(($T1*) &_storage[$i])
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | {_count}
47 |
48 |
49 | $T3
50 | _items[$i],na
51 |
52 |
53 |
54 |
55 |
56 | {_keyWrap} : {_value}
57 |
58 | - _keyWrap
59 | - _value
60 |
61 |
62 |
63 |
64 |
65 |
66 | {*($T1*) &_storage._Val}
67 |
68 | *($T1*) &_storage._Val
69 |
70 |
71 |
72 |
73 |
74 |
75 | █ {prefix,sub}{name,sb}
76 | ░ {prefix,sub}{name,sb}
77 |
78 |
79 |
80 |
81 |
82 |
83 | {forkType} ► {prongType}
84 |
85 |
86 |
87 |
88 |
89 |
90 | {_typeToIndex,na}
91 |
92 | _typeToIndex,na
93 |
94 |
95 |
96 |
97 |
98 |
99 | {type}: {*(std::type_index*)&stateType._storage}
100 |
101 |
102 |
103 |
104 |
105 |
106 | [{type}] <{resumableType,na}> ◄ <{activeType,na}> ► <{requestedType,na}>
107 |
108 | - type
109 | - activeType
110 | - resumableType
111 | - requestedType
112 |
113 |
114 |
115 |
116 |
117 |
118 | {_type}
119 |
120 | - _client
121 |
122 |
123 |
124 |
125 |
126 |
127 | {_fork}
128 |
129 | - _state
130 | - _subStates
131 |
132 |
133 |
134 |
135 | {initial} {remaining}
136 |
137 |
138 |
139 | {initial}
140 |
141 |
142 |
143 |
144 |
145 | {_type}
146 |
147 | - _state
148 | - _subStates
149 |
150 |
151 |
152 |
153 | {initial} {remaining}
154 |
155 |
156 |
157 |
158 |
159 | {_structure}
160 |
161 | {_structure}
162 |
163 |
164 |
165 |
166 |
167 |
168 | [{_cursor}] = {_t[_cursor]}
169 |
170 | _container
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/include/hfsm/detail/machine_state_methods.inl:
--------------------------------------------------------------------------------
1 | namespace hfsm {
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 |
5 | template
6 | template
7 | M::_S::_S(StateRegistry& stateRegistry,
8 | const Parent parent,
9 | Parents& stateParents,
10 | Parents& /*forkParents*/,
11 | ForkPointers& /*forkPointers*/)
12 | {
13 | const auto id = stateRegistry.add(TypeInfo::get());
14 | stateParents[id] = parent;
15 | }
16 |
17 | //------------------------------------------------------------------------------
18 |
19 | template
20 | template
21 | bool
22 | M::_S::deepSubstitute(Control& control,
23 | Context& context,
24 | LoggerInterface* const HFSM_IF_LOGGER(logger))
25 | {
26 | HFSM_IF_LOGGER(if (logger) log(*logger));
27 |
28 | const unsigned requestCountBefore = control.requestCount();
29 |
30 | _head.widePreSubstitute(context);
31 | _head.substitute(control, context);
32 |
33 | return requestCountBefore < control.requestCount();
34 | }
35 |
36 | //------------------------------------------------------------------------------
37 |
38 | template
39 | template
40 | void
41 | M::_S::deepEnterInitial(Context& context,
42 | LoggerInterface* const logger)
43 | {
44 | deepEnter(context, logger);
45 | }
46 |
47 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
48 |
49 | template
50 | template
51 | void
52 | M::_S::deepEnter(Context& context,
53 | LoggerInterface* const HFSM_IF_LOGGER(logger))
54 | {
55 | HFSM_IF_LOGGER(if (logger) log(*logger));
56 |
57 | _head.widePreEnter(context);
58 | _head.enter(context);
59 | }
60 |
61 | //------------------------------------------------------------------------------
62 |
63 | template
64 | template
65 | bool
66 | M::_S::deepUpdateAndTransition(Control& control,
67 | Context& context,
68 | LoggerInterface* const HFSM_IF_LOGGER(logger))
69 | {
70 | HFSM_IF_LOGGER(if (logger) log(*logger));
71 |
72 | _head.widePreUpdate(context);
73 | _head.update(context);
74 |
75 | HFSM_IF_LOGGER(if (logger) log(*logger));
76 |
77 | const unsigned requestCountBefore = control.requestCount();
78 |
79 | _head.widePreTransition(context);
80 | _head.transition(control, context);
81 |
82 | return requestCountBefore < control.requestCount();
83 | }
84 |
85 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
86 |
87 | template
88 | template
89 | void
90 | M::_S::deepUpdate(Context& context,
91 | LoggerInterface* const HFSM_IF_LOGGER(logger))
92 | {
93 | HFSM_IF_LOGGER(if (logger) log(*logger));
94 |
95 | _head.widePreUpdate(context);
96 | _head.update(context);
97 | }
98 |
99 | //------------------------------------------------------------------------------
100 |
101 | template
102 | template
103 | template
104 | void
105 | M::_S::deepReact(const TEvent& event,
106 | Control& control,
107 | Context& context,
108 | LoggerInterface* const HFSM_IF_LOGGER(logger))
109 | {
110 | HFSM_IF_LOGGER(if (logger) log), LoggerInterface::Method::React>(*logger));
111 |
112 | _head.widePreReact(event, context);
113 | _head.react(event, control, context);
114 | }
115 |
116 | //------------------------------------------------------------------------------
117 |
118 | template
119 | template
120 | void
121 | M::_S::deepLeave(Context& context,
122 | LoggerInterface* const HFSM_IF_LOGGER(logger))
123 | {
124 | HFSM_IF_LOGGER(if (logger) log(*logger));
125 |
126 | _head.leave(context);
127 | _head.widePostLeave(context);
128 | }
129 |
130 | //------------------------------------------------------------------------------
131 |
132 | #ifdef HFSM_ENABLE_STRUCTURE_REPORT
133 |
134 | template
135 | template
136 | const char*
137 | M::_S::name() {
138 | if (isBare())
139 | return "";
140 | else {
141 | const char* const raw = TypeInfo::get()->name();
142 |
143 | #if defined(_MSC_VER)
144 |
145 | unsigned first =
146 | raw[0] == 's' ? 7 : // Struct
147 | raw[0] == 'c' ? 6 : // Class
148 | 0;
149 |
150 | for (auto c = first; raw[c]; ++c)
151 | if (raw[c] == ':')
152 | first = c + 1;
153 |
154 | return raw + first;
155 |
156 | #elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
157 |
158 | return raw;
159 |
160 | #else
161 |
162 | return raw;
163 |
164 | #endif
165 | }
166 | }
167 |
168 | //------------------------------------------------------------------------------
169 |
170 | template
171 | template
172 | void
173 | M::_S::deepGetNames(const unsigned parent,
174 | const enum StateInfo::RegionType region,
175 | const unsigned depth,
176 | StateInfos& _stateInfos) const
177 | {
178 | _stateInfos << StateInfo { parent, region, depth, name() };
179 | }
180 |
181 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
182 |
183 | template
184 | template
185 | void
186 | M::_S::deepIsActive(const bool isActive,
187 | unsigned& index,
188 | MachineStructure& structure) const
189 | {
190 | if (!isBare())
191 | structure[index++].isActive = isActive;
192 | }
193 |
194 | #endif
195 |
196 | //------------------------------------------------------------------------------
197 |
198 | #ifdef HFSM_ENABLE_LOG_INTERFACE
199 |
200 | template
201 | template
202 | const char*
203 | M::_S| ::fullName() {
204 | if (isBare())
205 | return "";
206 | else {
207 | const char* const raw = TypeInfo::get()->name();
208 |
209 | #if defined(_MSC_VER)
210 |
211 | unsigned first =
212 | raw[0] == 's' ? 7 : // Struct
213 | raw[0] == 'c' ? 6 : // Class
214 | 0;
215 | return raw + first;
216 |
217 | #elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
218 |
219 | return raw;
220 |
221 | #else
222 |
223 | return raw;
224 |
225 | #endif
226 | }
227 | }
228 |
229 | #endif
230 |
231 | ////////////////////////////////////////////////////////////////////////////////
232 |
233 | }
234 |
--------------------------------------------------------------------------------
/projects/visual-studio/basic_streetlight.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 15.0
29 | {C543B4D9-A8AC-47B7-8376-AB4B110C144E}
30 | Win32Proj
31 | 8.1
32 |
33 |
34 |
35 | Application
36 | true
37 | v140
38 | Unicode
39 |
40 |
41 | Application
42 | false
43 | v140
44 | true
45 | Unicode
46 |
47 |
48 | Application
49 | true
50 | v140
51 | Unicode
52 |
53 |
54 | Application
55 | false
56 | v140
57 | true
58 | Unicode
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | true
84 |
85 |
86 | false
87 |
88 |
89 | true
90 |
91 |
92 | false
93 |
94 |
95 |
96 |
97 |
98 | Disabled
99 | WIN32;_DEBUG;%(PreprocessorDefinitions)
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | MaxSpeed
108 | true
109 | true
110 | WIN32;NDEBUG;%(PreprocessorDefinitions)
111 |
112 |
113 | true
114 | true
115 |
116 |
117 |
118 |
119 |
120 |
121 | Disabled
122 | _DEBUG;%(PreprocessorDefinitions)
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | MaxSpeed
131 | true
132 | true
133 | NDEBUG;%(PreprocessorDefinitions)
134 |
135 |
136 | true
137 | true
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/projects/visual-studio/basic_event.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 15.0
29 | {AA58BDD0-0F56-43E9-816C-37BA6C30F97C}
30 | Win32Proj
31 | 8.1
32 | advanced_event_handling
33 |
34 |
35 |
36 | Application
37 | true
38 | v140
39 | Unicode
40 |
41 |
42 | Application
43 | false
44 | v140
45 | true
46 | Unicode
47 |
48 |
49 | Application
50 | true
51 | v140
52 | Unicode
53 |
54 |
55 | Application
56 | false
57 | v140
58 | true
59 | Unicode
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | true
85 |
86 |
87 | false
88 |
89 |
90 | true
91 |
92 |
93 | false
94 |
95 |
96 |
97 |
98 |
99 | Disabled
100 | WIN32;_DEBUG;%(PreprocessorDefinitions)
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | MaxSpeed
109 | true
110 | true
111 | WIN32;NDEBUG;%(PreprocessorDefinitions)
112 |
113 |
114 | true
115 | true
116 |
117 |
118 |
119 |
120 |
121 |
122 | Disabled
123 | _DEBUG;%(PreprocessorDefinitions)
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | MaxSpeed
132 | true
133 | true
134 | NDEBUG;%(PreprocessorDefinitions)
135 |
136 |
137 | true
138 | true
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/projects/visual-studio/basic_logger_interface.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 15.0
29 | {E1C0E44B-EEF3-40D4-AEB7-54C4E570237E}
30 | Win32Proj
31 | 8.1
32 | debug_logger_interface
33 |
34 |
35 |
36 | Application
37 | true
38 | v140
39 | Unicode
40 |
41 |
42 | Application
43 | false
44 | v140
45 | true
46 | Unicode
47 |
48 |
49 | Application
50 | true
51 | v140
52 | Unicode
53 |
54 |
55 | Application
56 | false
57 | v140
58 | true
59 | Unicode
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | true
85 |
86 |
87 | false
88 |
89 |
90 | true
91 |
92 |
93 | false
94 |
95 |
96 |
97 |
98 |
99 | Disabled
100 | WIN32;_DEBUG;%(PreprocessorDefinitions)
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | MaxSpeed
109 | true
110 | true
111 | WIN32;NDEBUG;%(PreprocessorDefinitions)
112 |
113 |
114 | true
115 | true
116 |
117 |
118 |
119 |
120 |
121 |
122 | Disabled
123 | _DEBUG;%(PreprocessorDefinitions)
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | MaxSpeed
132 | true
133 | true
134 | NDEBUG;%(PreprocessorDefinitions)
135 |
136 |
137 | true
138 | true
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/include/hfsm/detail/machine_orthogonal_sub_2.inl:
--------------------------------------------------------------------------------
1 | namespace hfsm {
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 |
5 | template
6 | template
7 | template
8 | M::_O::Sub::Sub(StateRegistry& stateRegistry,
9 | const Index fork,
10 | Parents& stateParents,
11 | Parents& forkParents,
12 | ForkPointers& forkPointers)
13 | : initial(stateRegistry,
14 | Parent(fork,
15 | ProngIndex
16 | HSFM_IF_DEBUG(, TypeInfo::get())
17 | HSFM_IF_DEBUG(, TypeInfo::get())),
18 | stateParents,
19 | forkParents,
20 | forkPointers)
21 | {}
22 |
23 | //------------------------------------------------------------------------------
24 |
25 | template
26 | template
27 | template
28 | void
29 | M::_O::Sub::wideForwardSubstitute(const unsigned HSFM_IF_ASSERT(prong),
30 | Control& control,
31 | Context& context,
32 | LoggerInterface* const logger)
33 | {
34 | assert(prong == ProngIndex);
35 |
36 | initial.deepForwardSubstitute(control, context, logger);
37 | }
38 |
39 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
40 |
41 | template
42 | template
43 | template
44 | void
45 | M::_O::Sub::wideForwardSubstitute(Control& control,
46 | Context& context,
47 | LoggerInterface* const logger)
48 | {
49 | initial.deepForwardSubstitute(control, context, logger);
50 | }
51 |
52 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53 |
54 | template
55 | template
56 | template
57 | void
58 | M::_O::Sub::wideSubstitute(Control& control,
59 | Context& context,
60 | LoggerInterface* const logger)
61 | {
62 | initial.deepSubstitute(control, context, logger);
63 | }
64 |
65 | //------------------------------------------------------------------------------
66 |
67 | template
68 | template
69 | template
70 | void
71 | M::_O::Sub::wideEnterInitial(Context& context,
72 | LoggerInterface* const logger)
73 | {
74 | initial.deepEnterInitial(context, logger);
75 | }
76 |
77 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
78 |
79 | template
80 | template
81 | template
82 | void
83 | M::_O::Sub::wideEnter(Context& context,
84 | LoggerInterface* const logger)
85 | {
86 | initial.deepEnter(context, logger);
87 | }
88 |
89 | //------------------------------------------------------------------------------
90 |
91 | template
92 | template
93 | template
94 | bool
95 | M::_O::Sub::wideUpdateAndTransition(Control& control,
96 | Context& context,
97 | LoggerInterface* const logger)
98 | {
99 | return initial.deepUpdateAndTransition(control, context, logger);
100 | }
101 |
102 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
103 |
104 | template | | | | | | | | | | | |