#pragma once #include #include #include #include #include #include #include #include #include namespace mcc::fsm { namespace traits { /* The only requirement to Event-class is public-accepted static constant 'ID' */ template concept fsm_event_c = std::is_default_constructible_v && std::is_move_constructible_v && std::movable && requires { requires std::same_as; }; /* The only requirements to State-class is public-accepted static constant 'ID' and definition of type transition_table_t */ template concept fsm_state_c = std::is_default_constructible_v && std::is_move_constructible_v && std::movable && requires { requires std::same_as; typename T::transition_t; }; // concept for std::pair template concept fsm_pair_of_types_c = requires { [](std::type_identity>) {}(std::type_identity()); }; template concept fsm_tuple_of_pairs_c = requires { [](std::type_identity>) {}(std::type_identity()); }; template concept fsm_tuple_of_events_c = requires { [](std::type_identity>) {}(std::type_identity()); }; } // namespace traits /* Event-to-State transition table definition */ template struct fsm_transition_table_t; template struct fsm_transition_table_t { using events_t = std::tuple; using event_state_pair_t = PT; using unique_states_t = std::tuple; template using find_state_by_event_t = std::conditional_t, typename PT::second_type, void>; }; template struct fsm_transition_table_t { private: static constexpr bool non_unique_event = (std::same_as || ...); public: using events_t = std::conditional_t::events_t, decltype(std::tuple_cat(std::declval>(), std::declval::events_t>()))>; using event_state_pair_t = std::conditional_t::event_state_pair_t, decltype(std::tuple_cat( std::declval>(), std::declval::event_state_pair_t>()))>; using unique_states_t = std::conditional_t< non_unique_event, typename fsm_transition_table_t::unique_states_t, std::conditional_t<(std::same_as || ...), typename fsm_transition_table_t::unique_states_t, decltype(std::tuple_cat( std::declval>(), std::declval::unique_states_t>()))>>; private: template struct find_state_by_event; template struct find_state_by_event>> { using state_t = std::conditional_t, StT, void>; }; template struct find_state_by_event, PairTs...>> { using state_t = std::conditional_t, StT, typename find_state_by_event>::state_t>; }; public: // template template using find_state_by_event_t = typename find_state_by_event::state_t; }; class MccFiniteStateMachine { protected: /* helper types definition */ // merge N std::tuple types with filtering dublicates // (NOTE: the first std::tuple must contain unique types!!!) template struct merge_tuples; template struct merge_tuples { using result_t = TplT; }; template struct merge_tuples { using result_t = TplT1; }; template struct merge_tuples, std::tuple> : std::conditional_t<(std::same_as || ...), merge_tuples, std::tuple>, merge_tuples, std::tuple>> { }; template struct merge_tuples : merge_tuples::result_t, TplT3, TplTs...> { }; template using merge_tuples_t = typename merge_tuples::result_t; // deduce all unique states from the initial one template struct deduce_states; template struct deduce_states { using states_t = ResTplT; }; template struct deduce_states, InTplTs...> { using curr_collection_t = merge_tuples_t, typename StTs::transition_t::unique_states_t...>; using states_t = typename deduce_states == std::tuple_size_v, curr_collection_t, typename StTs::transition_t::unique_states_t..., InTplTs...>::states_t; }; template using deduce_states_t = typename deduce_states, std::tuple>::states_t; // deduce all unique events from the initial state transition table template struct deduce_events; template struct deduce_events { using events_t = ResTplT; }; template struct deduce_events> { using curr_collection_t = typename StT::transition_t::events_t; using events_t = typename deduce_states::events_t; }; template struct deduce_events, InTplTs...> { using curr_collection_t = merge_tuples_t; using events_t = typename deduce_states == std::tuple_size_v, curr_collection_t, typename StTs::transition_t::events_t..., typename StTs::transition_t::unique_states_t...>::events_t; }; template using deduce_events_t = typename deduce_events::events_t; // using deduce_events_t = typename deduce_events, std::tuple<>, // std::tuple>::events_t; template struct variant_from_tuple; template struct variant_from_tuple> { using variant_t = std::variant; }; template using variant_from_tuple_t = typename variant_from_tuple::variant_t; // template static void for_each_event(FT&& func, std::index_sequence) { (func(std::get(EvTplT{})), ...); }; template static void for_each_event(FT&& func) { for_each_event(std::forward(func), std::make_index_sequence>()); }; template inline static std::unordered_map> _dispatchEventFunc{}; public: template MccFiniteStateMachine(InitStateT) { using states_t = deduce_states_t; auto states = std::make_shared(); auto currentState = std::make_shared>(); *currentState = &std::get(*states); int status; char* aa = abi::__cxa_demangle(typeid(states_t).name(), NULL, NULL, &status); std::cout << "states_t = " << aa << '\n'; free(aa); /* aa = abi::__cxa_demangle(typeid(deduce_events_t).name(), NULL, NULL, &status); std::cout << "events_t = " << aa << '\n'; free(aa); // setup dispatch event functions for_each_event>([states, currentState, this](EvT) { _dispatchEventFunc[this] = [states, currentState, this](EvT& event) { std::visit( [&event, states](curr_state_t*) { using to_state_t = curr_state_t::trasition_table_t::template find_state_by_event_t; if constexpr (std::is_void_v) { /// throw?!! return; } // exit from current if constexpr (requires(curr_state_t inst) { { inst.exit(std::declval()) }; }) { std::get(states).exit(event); } else if constexpr (requires(curr_state_t inst) { { inst.exit() }; }) { std::get(states).exit(); } // transit ... if constexpr (requires(EvT inst) { { inst.on_transit() }; }) { event.on_transit(); } // enter to new if constexpr (requires(to_state_t inst) { { inst.enter(std::declval()) }; }) { std::get(states).enter(event); } else if constexpr (requires(to_state_t inst) { { inst.enter() }; }) { std::get(states).enter(); } }, currentState); }; }); */ } template auto dispatchEvent(EvT& event) { _dispatchEventFunc[this](event); } }; } // namespace mcc::fsm