#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* FINITE-STATE MACHINE IMPLEMENTATION */ #include #include #include #include #include "mcc_fsm_utils.h" namespace mcc::fsm { class MccFsmAbstractState; namespace traits { template concept fsm_event_c = std::is_default_constructible_v && std::is_move_constructible_v && std::movable && requires { { T::ID } -> std::same_as; // static constant member of event identificator }; template concept fsm_event_state_pair_c = requires { [] StT>(std::type_identity>) { }(std::type_identity()); }; template concept fsm_event_state_pair_tuple_c = requires { [](std::type_identity>) {}(std::type_identity()); }; } // namespace traits /* A base FSM state class with implementation of "event -- new state" transition table */ class MccFsmAbstractState { static constexpr std::string_view ID = "MCC-FSM-STATE"; protected: MccFsmAbstractState() = default; // helpers template struct in_tuple; template struct in_tuple> : std::disjunction...> { }; template static constexpr bool in_tpl_v = in_tuple::value; // template // struct in_pair : std::disjunction...> { // }; template static constexpr bool in_pair_v = std::disjunction...>::value; // static constexpr bool in_pair_v = in_pair::value; /* transition table definition */ public: template struct trans_table_t; template struct trans_table_t { using events_t = std::tuple; using states_t = std::tuple; using unique_states_t = states_t; using evst_pairs_t = std::tuple; static constexpr bool unique = true; template using find_state_by_event_t = std::conditional_t, typename PT::first_second, std::nullptr_t>; }; template struct trans_table_t { private: using ev_t = typename PT::first_type; using st_t = typename PT::second_type; // static constexpr bool non_unique = in_pair_v; static constexpr bool non_unique = (std::same_as || ...); public: using events_t = std::conditional_t::events_t, decltype(std::tuple_cat(std::declval>(), std::declval::events_t>()))>; using states_t = std::conditional_t::states_t, decltype(std::tuple_cat(std::declval>(), std::declval::states_t>()))>; using unique_states_t = std::conditional_t< non_unique, typename trans_table_t::unique_states_t, std::conditional_t<(std::same_as || ...), typename trans_table_t::unique_states_t, decltype(std::tuple_cat( std::declval>(), std::declval::unique_states_t>()))>>; using evst_pairs_t = std::conditional_t::evst_pairs_t, decltype(std::tuple_cat(std::declval>(), std::declval::evst_pairs_t>()))>; private: template struct find_state_by_event { template struct helper { static constexpr size_t idx = std::same_as> ? I : helper::idx; }; // to stop unwind the recursive 'helper' template // in std::conditional_t trait template struct helper - 1, T> { static constexpr size_t idx = std::tuple_size_v - 1; }; using res_t = std:: conditional_t, std::tuple_element_t::idx, states_t>, std::nullptr_t>; }; public: template using find_state_by_event_t = find_state_by_event::res_t; }; // end of 'trans_table_t' }; // end of 'MccFsmAbstractState' namespace traits { template concept fsm_trans_table_c = requires { [](std::type_identity>) { }(std::type_identity()); }; template concept fsm_state_c = std::is_default_constructible_v && std::is_move_constructible_v && std::movable && std::derived_from && requires { // state class must define a type 'transition_t' which must be a full specialization of // MccFsmAbstractState::trans_table_t class [](std::type_identity) {}(std::type_identity()); }; } // namespace traits class MccFiniteStateMachine { public: template MccFiniteStateMachine(ST initial_state) : _currentStateID(ST::ID), _currentStateIDX(typeid(ST)) { // setStateFunc(); initFromInitial(typeid(ST)); } template void dispatchEvent(EvT event) { enter_state_func_umap_t[this][_currentStateIDX](std::move(event)); // state_func_umap_t[this][_currentStateIDX](std::move(event)); } protected: template using state_func_t = std::unordered_map>; template inline static std::unordered_map> state_func_umap_t{}; template inline static std::unordered_map> enter_state_func_umap_t{}; template inline static std::unordered_map> exit_state_func_umap_t{}; std::string_view _currentStateID; std::type_index _currentStateIDX; std::function _exitCurrentStateFunc; template consteval static void initFromInitial(std::type_index state_idx) { initFromInitial(state_idx); if constexpr (sizeof...(PTs)) { initFromInitial(state_idx); } } template consteval static void initFromInitial(std::type_index state_idx) { using ev_t = typename PT::first_type; using st_t = typename PT::second_type; enter_state_func_umap_t[][state_idx] = [](ev_t event) { st_t state; initFromInitial(st_t::ID); if constexpr (requires(st_t inst) { { inst.enter(std::declval()) }; }) { state.enter(std::move(event)); } else { state.enter(); } }; } // template // void setStateFunc() // { // setStateFunc(); // if constexpr (sizeof...(PTs)) { // setStateFunc(); // } // } // template // void setStateFunc() // { // using ev_t = typename PT::first_type; // using st_t = typename PT::second_type; // state_func_umap_t[this][_currentStateIDX] = [](ev_t event) { // st_t state; // if constexpr (requires(st_t inst) { // { inst.enter(std::declval()) }; // }) { // state.enter(std::move(event)); // } else { // state.enter(); // } // }; // } template struct merge_tuples_t; }; } // namespace mcc::fsm