#pragma once /* MOUNT CONTROL COMPONENTS LIBRARY */ /* FINITE-STATE MACHINE IMPLEMENTATION */ #include #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 requires std::same_as; }; template concept fsm_event_state_pair_c = requires { [](std::type_identity>) { // [] 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::second_type, 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' using transition_t = trans_table_t<>; }; // end of 'MccFsmAbstractState' namespace traits { template concept fsm_trans_table_c = requires { [](std::type_identity>) { }(std::type_identity()); // requires true; }; 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 template class MccFiniteStateMachine { public: // template // MccFiniteStateMachine(ST initial_state) : _currentStateID(ST::ID), _currentStateIDX(typeid(ST)) // { // // setStateFunc(); // initFromInitial(typeid(ST)); // } MccFiniteStateMachine() : _currentStateID(InitStateT::ID), _currentStateVariant(&std::get(_states)) {} 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{InitStateT::ID}; std::type_index _currentStateIDX{typeid(InitStateT)}; 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(); // } // }; // } // merge N std::tuple types with filtering dublicates // (NOTE: the first std::tuple type must contain unique types!!!) template struct merge_tuples_t; // template <> // struct merge_tuples_t> { // using res_t = std::tuple<>; // }; template struct merge_tuples_t { using res_t = TplT; }; template struct merge_tuples_t { using res_t = TplT1; }; template struct merge_tuples_t, std::tuple> : std::conditional_t<(std::same_as || ...), merge_tuples_t, std::tuple>, merge_tuples_t, std::tuple>> { }; template struct merge_tuples_t : merge_tuples_t::res_t, TplT3, TplTs...> { }; template using merge_tuples_res_t = typename merge_tuples_t::res_t; template struct variant_maker_t; template struct variant_maker_t> { using variant_t = std::variant; }; // template > // struct deduce_states_t; // template // struct deduce_states_t, OutTplT> { // using curr_collection_t = // merge_tuples_res_t, typename StTs::transition_t::unique_states_t...>; // using states_t = std::conditional_t< // std::tuple_size_v == std::tuple_size_v, // curr_collection_t, // merge_tuples_res_t>::curr_collection_t>>; // }; template struct deduce_states_t; template struct deduce_states_t { using states_t = ResTplT; }; template struct deduce_states_t, InTplTs...> { using curr_collection_t = merge_tuples_res_t, typename StTs::transition_t::unique_states_t...>; using states_t = typename deduce_states_t == std::tuple_size_v, curr_collection_t, typename StTs::transition_t::unique_states_t...>::states_t; }; public: // using states_t = typename deduce_states_t>::states_t; using states_t = typename deduce_states_t, std::tuple>::states_t; protected: states_t _states; typename variant_maker_t::variant_t _currentStateVariant; }; } // namespace mcc::fsm