add mcc_finite_state_machine.h (rewrite MccFiniteStateMachine class)
This commit is contained in:
parent
10dd92baab
commit
74b4cf06b1
@ -125,7 +125,8 @@ add_library(${CNTR_PROTO_LIB} STATIC ${CNTR_PROTO_LIB_SRC})
|
||||
set(MOUNT_SERVER_APP_SRC mount.h mount_state.h mount_server.cpp comm_server.h comm_server_endpoint.h comm_server_configfile.h mount_astrom.h
|
||||
mount_astrom_default.h mcc_coord.h mount_pz.h mcc_fsm.h mcc_fsm_utils.h)
|
||||
set(MOUNT_SERVER_APP mount_server)
|
||||
add_executable(${MOUNT_SERVER_APP} ${MOUNT_SERVER_APP_SRC})
|
||||
add_executable(${MOUNT_SERVER_APP} ${MOUNT_SERVER_APP_SRC}
|
||||
mcc_finite_state_machine.h)
|
||||
# target_include_directories(${MOUNT_SERVER_APP} PUBLIC ${ERFA_INCLUDE_DIR})
|
||||
target_link_libraries(${MOUNT_SERVER_APP} ${CNTR_PROTO_LIB} spdlog::spdlog_header_only ERFA_LIB)
|
||||
|
||||
|
||||
196
cxx/mcc_finite_state_machine.h
Normal file
196
cxx/mcc_finite_state_machine.h
Normal file
@ -0,0 +1,196 @@
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
namespace mcc::fsm
|
||||
{
|
||||
|
||||
namespace traits
|
||||
{
|
||||
|
||||
/*
|
||||
The only requirement to Event-class is public-accepted static constant 'ID'
|
||||
*/
|
||||
template <typename T>
|
||||
concept fsm_event_c = std::is_default_constructible_v<T> && std::is_move_constructible_v<T> && std::movable<T> &&
|
||||
requires { requires std::same_as<const std::string_view, decltype(T::ID)>; };
|
||||
|
||||
|
||||
/*
|
||||
The only requirement to State-class is public-accepted static constant 'ID'
|
||||
*/
|
||||
template <typename T>
|
||||
concept fsm_state_c = std::is_default_constructible_v<T> && std::is_move_constructible_v<T> && std::movable<T> &&
|
||||
requires { requires std::same_as<const std::string_view, decltype(T::ID)>; };
|
||||
|
||||
|
||||
// concept for std::pair
|
||||
template <typename T>
|
||||
concept fsm_pair_of_types_c =
|
||||
requires { []<typename T1, typename T2>(std::type_identity<std::pair<T1, T2>>) {}(std::type_identity<T>()); };
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept fsm_tuple_of_pairs_c =
|
||||
requires { []<fsm_pair_of_types_c... PTs>(std::type_identity<std::tuple<PTs...>>) {}(std::type_identity<T>()); };
|
||||
|
||||
|
||||
} // namespace traits
|
||||
|
||||
|
||||
/* Event-to-State transition table definition */
|
||||
|
||||
template <traits::fsm_pair_of_types_c... PTs>
|
||||
struct fsm_transition_table_t;
|
||||
|
||||
template <traits::fsm_pair_of_types_c PT>
|
||||
struct fsm_transition_table_t<PT> {
|
||||
using events_t = std::tuple<typename PT::first_type>;
|
||||
|
||||
using event_state_pair_t = PT;
|
||||
|
||||
using unique_states = std::tuple<typename PT::second_type>;
|
||||
|
||||
template <traits::fsm_event_c EvT>
|
||||
using find_state_by_event_t =
|
||||
std::conditional_t<std::same_as<EvT, typename PT::first_type>, typename PT::second_type, void>;
|
||||
};
|
||||
|
||||
|
||||
template <traits::fsm_pair_of_types_c PT, traits::fsm_pair_of_types_c... PTs>
|
||||
struct fsm_transition_table_t<PT, PTs...> {
|
||||
private:
|
||||
static constexpr bool non_unique_event = (std::same_as<typename PTs::first_type, typename PTs::first_type> || ...);
|
||||
|
||||
public:
|
||||
using events_t =
|
||||
std::conditional_t<non_unique_event,
|
||||
typename fsm_transition_table_t<PTs...>::events_t,
|
||||
decltype(std::tuple_cat(std::declval<std::tuple<typename PT::first_type>>(),
|
||||
std::declval<typename fsm_transition_table_t<PTs...>::events_t>()))>;
|
||||
|
||||
using event_state_pair_t =
|
||||
std::conditional_t<non_unique_event,
|
||||
typename fsm_transition_table_t<PTs...>::event_state_pair_t,
|
||||
decltype(std::tuple_cat(
|
||||
std::declval<std::tuple<PT>>(),
|
||||
std::declval<typename fsm_transition_table_t<PTs...>::event_state_pair_t>()))>;
|
||||
|
||||
using unique_states = std::conditional_t<
|
||||
non_unique_event,
|
||||
typename fsm_transition_table_t<PTs...>::unique_states_t,
|
||||
std::conditional_t<(std::same_as<typename PT::second_type, typename PTs::second_type> || ...),
|
||||
typename fsm_transition_table_t<PTs...>::unique_states_t,
|
||||
decltype(std::tuple_cat(
|
||||
std::declval<std::tuple<typename PT::second_type>>(),
|
||||
std::declval<typename fsm_transition_table_t<PTs...>::unique_states_t>()))>>;
|
||||
|
||||
private:
|
||||
template <typename EvT, traits::fsm_tuple_of_pairs_c TplT>
|
||||
struct find_state_by_event;
|
||||
|
||||
template <typename LookEvT, typename EvT, typename StT>
|
||||
struct find_state_by_event<LookEvT, std::tuple<std::pair<EvT, StT>>> {
|
||||
using state_t = std::conditional_t<std::same_as<LookEvT, EvT>, StT, void>;
|
||||
};
|
||||
|
||||
template <typename LookEvT, typename EvT, typename StT, traits::fsm_pair_of_types_c... PairTs>
|
||||
struct find_state_by_event<LookEvT, std::tuple<std::pair<EvT, StT>, PairTs...>> {
|
||||
using state_t = std::conditional_t<std::same_as<LookEvT, EvT>,
|
||||
StT,
|
||||
typename find_state_by_event<LookEvT, std::tuple<PairTs...>>::state_t>;
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename EvT, traits::fsm_tuple_of_pairs_c TplT>
|
||||
using find_state_by_event_t = typename find_state_by_event<EvT, TplT>::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 <typename... TplTs>
|
||||
struct merge_tuples;
|
||||
|
||||
template <typename TplT>
|
||||
struct merge_tuples<TplT> {
|
||||
using result_t = TplT;
|
||||
};
|
||||
|
||||
template <typename TplT1, typename TplT2>
|
||||
struct merge_tuples<TplT1, TplT2> {
|
||||
using result_t = TplT1;
|
||||
};
|
||||
|
||||
template <typename... T1, typename T2, typename... T2s>
|
||||
struct merge_tuples<std::tuple<T1...>, std::tuple<T2, T2s...>>
|
||||
: std::conditional_t<(std::same_as<T1, T2> || ...),
|
||||
merge_tuples<std::tuple<T1...>, std::tuple<T2s...>>,
|
||||
merge_tuples<std::tuple<T1..., T2>, std::tuple<T2s...>>> {
|
||||
};
|
||||
|
||||
template <typename TplT1, typename TplT2, typename TplT3, typename... TplTs>
|
||||
struct merge_tuples<TplT1, TplT2, TplT3, TplTs...>
|
||||
: merge_tuples<typename merge_tuples<TplT1, TplT2>::result_t, TplT3, TplTs...> {
|
||||
};
|
||||
|
||||
template <typename... TplTs>
|
||||
using merge_tuples_t = typename merge_tuples<TplTs...>::res_t;
|
||||
|
||||
|
||||
// deduce all unique states from the initial one
|
||||
template <bool stop, typename ResTplT, typename... InTplTs>
|
||||
struct deduce_states;
|
||||
|
||||
template <typename ResTplT, typename... InTplTs>
|
||||
struct deduce_states<true, ResTplT, InTplTs...> {
|
||||
using states_t = ResTplT;
|
||||
};
|
||||
|
||||
template <typename ResTplT, traits::fsm_state_c... StTs, typename... InTplTs>
|
||||
struct deduce_states<false, ResTplT, std::tuple<StTs...>, InTplTs...> {
|
||||
using curr_collection_t =
|
||||
merge_tuples_t<ResTplT, std::tuple<StTs...>, typename StTs::transition_t::unique_states_t...>;
|
||||
|
||||
using states_t = typename deduce_states<std::tuple_size_v<ResTplT> == std::tuple_size_v<curr_collection_t>,
|
||||
curr_collection_t,
|
||||
typename StTs::transition_t::unique_states_t...>::states_t;
|
||||
};
|
||||
|
||||
template <traits::fsm_state_c InitStateT>
|
||||
using deduce_states_t = typename deduce_states<false, std::tuple<>, std::tuple<InitStateT>>::states_t;
|
||||
|
||||
template <typename TplT>
|
||||
struct variant_from_tuple;
|
||||
|
||||
template <typename... Ts>
|
||||
struct variant_from_tuple<std::tuple<Ts...>> {
|
||||
using variant_t = std::variant<Ts*...>;
|
||||
};
|
||||
|
||||
template <typename TplT>
|
||||
using variant_from_tuple_t = typename variant_from_tuple<TplT>::variant_t;
|
||||
|
||||
|
||||
template <traits::fsm_event_c EvT>
|
||||
inline static std::unordered_map<const MccFiniteStateMachine*, std::function<void(EvT)>> _dispatchEventFunc{};
|
||||
|
||||
public:
|
||||
template <traits::fsm_state_c InitStateT>
|
||||
MccFiniteStateMachine(InitStateT)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace mcc::fsm
|
||||
@ -102,7 +102,7 @@ public:
|
||||
using st_t = typename PT::second_type;
|
||||
|
||||
// static constexpr bool non_unique = in_pair_v<ev_t, PTs...>;
|
||||
static constexpr bool non_unique = (std::same_as<ev_t, typename PTs::second_type> || ...);
|
||||
static constexpr bool non_unique = (std::same_as<ev_t, typename PTs::first_type> || ...);
|
||||
|
||||
public:
|
||||
using events_t =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user