MccFiniteStateMachine: compiled and works (again ... :) )

This commit is contained in:
Timur A. Fatkhullin 2025-06-02 17:48:08 +03:00
parent 9bee1ca0ea
commit 52a29e0f91
2 changed files with 186 additions and 24 deletions

View File

@ -6,6 +6,7 @@
#include <concepts> #include <concepts>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex>
#include <string_view> #include <string_view>
#include <tuple> #include <tuple>
#include <unordered_map> #include <unordered_map>
@ -14,6 +15,64 @@
namespace mcc::fsm namespace mcc::fsm
{ {
enum class MccFiniteStateMachineErrorCode : int { ERROR_OK, ERROR_UNREGISTERED_EVENT_TYPE, ERROR_UNHANDLED_TRANSITION };
} // namespace mcc::fsm
namespace std
{
template <>
class is_error_code_enum<mcc::fsm::MccFiniteStateMachineErrorCode> : public true_type
{
};
} // namespace std
namespace mcc::fsm
{
// error category
struct MccFiniteStateMachineCategory : public std::error_category {
MccFiniteStateMachineCategory() : std::error_category() {}
const char* name() const noexcept
{
return "ADC_GENERIC_DEVICE";
}
std::string message(int ec) const
{
MccFiniteStateMachineErrorCode err = static_cast<MccFiniteStateMachineErrorCode>(ec);
switch (err) {
case MccFiniteStateMachineErrorCode::ERROR_OK:
return "OK";
case MccFiniteStateMachineErrorCode::ERROR_UNREGISTERED_EVENT_TYPE:
return "unregistered event type";
case MccFiniteStateMachineErrorCode::ERROR_UNHANDLED_TRANSITION:
return "unhandled transition";
default:
return "UNKNOWN";
}
}
static const MccFiniteStateMachineCategory& get()
{
static const MccFiniteStateMachineCategory constInst;
return constInst;
}
};
inline std::error_code make_error_code(MccFiniteStateMachineErrorCode ec)
{
return std::error_code(static_cast<int>(ec), MccFiniteStateMachineCategory::get());
}
namespace traits namespace traits
{ {
@ -221,26 +280,64 @@ protected:
using variant_from_tuple_t = typename variant_from_tuple<TplT>::variant_t; using variant_from_tuple_t = typename variant_from_tuple<TplT>::variant_t;
// // call given function for all event-types in the given std::tuple
template <typename EvTplT, typename FT, size_t... Is> template <traits::fsm_tuple_of_events_c EvTplT, typename FT, size_t... Is>
static void for_each_event(FT&& func, std::index_sequence<Is...>) static void for_each_event(FT&& func, std::index_sequence<Is...>)
{ {
(func(std::get<Is>(EvTplT{})), ...); (func(std::get<Is>(EvTplT{})), ...);
}; };
template <typename EvTplT, typename FT> template <traits::fsm_tuple_of_events_c EvTplT, typename FT>
static void for_each_event(FT&& func) static void for_each_event(FT&& func)
{ {
for_each_event<EvTplT>(std::forward<FT>(func), std::make_index_sequence<std::tuple_size_v<EvTplT>>()); for_each_event<EvTplT>(std::forward<FT>(func), std::make_index_sequence<std::tuple_size_v<EvTplT>>());
}; };
template <traits::fsm_state_c StT, typename FT>
static void for_each_event_in_each_state(FT&& func)
{
for_each_event<typename StT::transition_t::events_t>(std::forward<FT>(func));
}
template <typename StTplT, typename FT, size_t... Is>
static void for_each_event_in_each_state(FT&& func, std::index_sequence<Is...>)
{
(for_each_event_in_each_state<std::tuple_element_t<Is, StTplT>>(std::forward<FT>(func)), ...);
}
template <typename StTplT, typename FT>
static void for_each_event_in_each_state(FT&& func)
{
for_each_event_in_each_state<StTplT>(std::forward<FT>(func),
std::make_index_sequence<std::tuple_size_v<StTplT>>());
}
// check if given event-type is in std::tuple of event-types
template <traits::fsm_event_c EvT, typename EvTplT>
struct in_tuple;
template <traits::fsm_event_c EvT, traits::fsm_event_c... EvTplTs>
struct in_tuple<EvT, std::tuple<EvTplTs...>> : std::disjunction<std::is_same<EvT, EvTplTs>...> {
};
template <traits::fsm_event_c EvT, typename EvTplT>
static constexpr bool in_tuple_v = in_tuple<EvT, EvTplT>::value;
template <traits::fsm_event_c EvT> template <traits::fsm_event_c EvT>
inline static std::unordered_map<const MccFiniteStateMachine*, std::function<void(EvT&)>> _dispatchEventFunc{}; inline static std::unordered_map<const MccFiniteStateMachine*, std::function<void(EvT&)>> _dispatchEventFunc{};
std::vector<std::function<void(MccFiniteStateMachine*, MccFiniteStateMachine*)>> _moveFunc{}; std::vector<std::function<void(MccFiniteStateMachine*, MccFiniteStateMachine*)>> _moveFunc{};
std::vector<std::function<void(const MccFiniteStateMachine*, MccFiniteStateMachine*)>> _copyFunc{}; std::vector<std::function<void(const MccFiniteStateMachine*, MccFiniteStateMachine*)>> _copyFunc{};
std::vector<std::function<void()>> _destroyFunc{}; std::vector<std::function<void(const MccFiniteStateMachine*)>> _destroyFunc{};
std::string_view _currentStateID;
std::mutex _transitionMutex;
static MccFiniteStateMachine& copyInstance(const MccFiniteStateMachine* from, MccFiniteStateMachine* to) static MccFiniteStateMachine& copyInstance(const MccFiniteStateMachine* from, MccFiniteStateMachine* to)
{ {
@ -249,6 +346,7 @@ protected:
func(from, to); func(from, to);
} }
to->_currentStateID = from->_currentStateID;
to->_moveFunc = from->_moveFunc; to->_moveFunc = from->_moveFunc;
to->_copyFunc = from->_copyFunc; to->_copyFunc = from->_copyFunc;
to->_destroyFunc = from->_destroyFunc; to->_destroyFunc = from->_destroyFunc;
@ -264,6 +362,7 @@ protected:
func(from, to); func(from, to);
} }
to->_currentStateID = std::move(from->_currentStateID);
to->_moveFunc = std::move(from->_moveFunc); to->_moveFunc = std::move(from->_moveFunc);
to->_copyFunc = std::move(from->_copyFunc); to->_copyFunc = std::move(from->_copyFunc);
to->_destroyFunc = std::move(from->_destroyFunc); to->_destroyFunc = std::move(from->_destroyFunc);
@ -274,7 +373,7 @@ protected:
public: public:
template <traits::fsm_state_c InitStateT> template <traits::fsm_state_c InitStateT>
MccFiniteStateMachine(InitStateT) MccFiniteStateMachine(InitStateT) : _currentStateID(InitStateT::ID)
{ {
using states_t = deduce_states_t<InitStateT>; using states_t = deduce_states_t<InitStateT>;
auto states = std::make_shared<states_t>(); auto states = std::make_shared<states_t>();
@ -308,15 +407,23 @@ public:
// setup dispatch event functions // setup dispatch event functions
for_each_event<deduce_events_t<InitStateT>>([states, currentState, this]<traits::fsm_event_c EvT>(EvT) mutable {
using all_events_t = deduce_events_t<InitStateT>;
for_each_event<all_events_t>([states, currentState, this]<traits::fsm_event_c EvT>(EvT) mutable {
if constexpr (!in_tuple_v<EvT, all_events_t>) {
throw std::system_error(MccFiniteStateMachineErrorCode::ERROR_UNREGISTERED_EVENT_TYPE);
}
_dispatchEventFunc<EvT>[this] = [states, currentState, this](EvT& event) mutable { _dispatchEventFunc<EvT>[this] = [states, currentState, this](EvT& event) mutable {
std::lock_guard lock(_transitionMutex);
std::visit( std::visit(
[&event, states, currentState]<traits::fsm_state_c curr_state_t>(curr_state_t*) { [&event, states, currentState, this]<traits::fsm_state_c curr_state_t>(curr_state_t*) {
using to_state_t = curr_state_t::transition_t::template find_state_by_event_t<EvT>; using to_state_t = curr_state_t::transition_t::template find_state_by_event_t<EvT>;
if constexpr (!std::is_void_v<to_state_t>) { if constexpr (!std::is_void_v<to_state_t>) {
// exit from current // exit from current
if constexpr (requires(curr_state_t inst) { if constexpr (requires(curr_state_t inst) {
{ inst.exit(std::declval<EvT>()) }; { inst.exit(std::declval<EvT&>()) };
}) { }) {
std::get<curr_state_t>(*states).exit(event); std::get<curr_state_t>(*states).exit(event);
} else if constexpr (requires(curr_state_t inst) { } else if constexpr (requires(curr_state_t inst) {
@ -327,23 +434,26 @@ public:
// transit ... // transit ...
if constexpr (requires(EvT inst) { if constexpr (requires(EvT inst) {
{ inst.on_transit() }; { inst.onTransit() };
}) { }) {
event.on_transit(); event.onTransit();
} }
*currentState = std::get<to_state_t*>(*states); *currentState = &std::get<to_state_t>(*states);
_currentStateID = to_state_t::ID;
// enter to new // enter to new
if constexpr (requires(to_state_t inst) { if constexpr (requires(to_state_t inst) {
{ inst.enter(std::declval<EvT>()) }; { inst.enter(std::declval<EvT&>()) };
}) { }) {
std::get<curr_state_t>(*states).enter(event); std::get<to_state_t>(*states).enter(event);
} else if constexpr (requires(to_state_t inst) { } else if constexpr (requires(to_state_t inst) {
{ inst.enter() }; { inst.enter() };
}) { }) {
std::get<curr_state_t>(*states).enter(); std::get<to_state_t>(*states).enter();
} }
} else {
throw std::system_error(MccFiniteStateMachineErrorCode::ERROR_UNHANDLED_TRANSITION);
} }
}, },
*currentState); *currentState);
@ -355,25 +465,39 @@ public:
_copyFunc.emplace_back([](const MccFiniteStateMachine* from, MccFiniteStateMachine* to) { _copyFunc.emplace_back([](const MccFiniteStateMachine* from, MccFiniteStateMachine* to) {
_dispatchEventFunc<EvT>[to] = _dispatchEventFunc<EvT>[from]; _dispatchEventFunc<EvT>[to] = _dispatchEventFunc<EvT>[from];
}); });
_destroyFunc.emplace_back([](MccFiniteStateMachine* inst) { _destroyFunc.emplace_back([](const MccFiniteStateMachine* inst) {
// //
_dispatchEventFunc<EvT>.erase(inst); _dispatchEventFunc<EvT>.erase(inst);
}); });
}); });
std::cout << "MOVE VEC: " << _moveFunc.size() << "\n";
} }
MccFiniteStateMachine(const MccFiniteStateMachine& other) { copyInstance(&other, this); } MccFiniteStateMachine(const MccFiniteStateMachine& other)
{
copyInstance(&other, this);
}
MccFiniteStateMachine(MccFiniteStateMachine&& other) { moveInstance(&other, this); } MccFiniteStateMachine(MccFiniteStateMachine&& other)
{
moveInstance(&other, this);
}
MccFiniteStateMachine& operator=(const MccFiniteStateMachine& other) { return copyInstance(&other, this); } MccFiniteStateMachine& operator=(const MccFiniteStateMachine& other)
{
return copyInstance(&other, this);
}
MccFiniteStateMachine& operator=(MccFiniteStateMachine&& other) { return moveInstance(&other, this); } MccFiniteStateMachine& operator=(MccFiniteStateMachine&& other)
{
return moveInstance(&other, this);
}
virtual ~MccFiniteStateMachine() virtual ~MccFiniteStateMachine()
{ {
for (auto& func : _destroyFunc) { for (auto& func : _destroyFunc) {
func(); func(this);
} }
} }
@ -382,6 +506,18 @@ public:
{ {
_dispatchEventFunc<EvT>[this](event); _dispatchEventFunc<EvT>[this](event);
} }
template <traits::fsm_event_c EvT>
auto dispatchEvent()
{
static EvT event;
return dispatchEvent(event);
}
std::string_view currentStateID() const
{
return _currentStateID;
}
}; };

View File

@ -15,9 +15,11 @@ struct S {
struct EV1 { struct EV1 {
static constexpr std::string_view ID = "EV1"; static constexpr std::string_view ID = "EV1";
// EV1() = default; void onTransit()
// EV1(EV1&&) = default; {
// EV1& operator=(EV1&&) = default; //
std::cout << "EV1::onTransit()\n";
}
}; };
struct EV2 { struct EV2 {
@ -44,12 +46,22 @@ struct ST3 {
struct ST2 { struct ST2 {
static constexpr std::string_view ID = "ST2"; static constexpr std::string_view ID = "ST2";
using transition_t = fsm::fsm_transition_table_t<std::pair<EV2, STN>, std::pair<EV3, ST3>>; using transition_t = fsm::fsm_transition_table_t<std::pair<EV2, STN>, std::pair<EV3, ST3>>;
void enter(EV1& ev)
{
std::cout << "transit to " << ID << "-state\n";
}
}; };
struct ST1 { struct ST1 {
static constexpr std::string_view ID = "ST1"; static constexpr std::string_view ID = "ST1";
using transition_t = using transition_t =
fsm::fsm_transition_table_t<std::pair<EV1, ST2>, std::pair<EV2, STN>, std::pair<EV3, STN>, std::pair<EV3, STN>>; fsm::fsm_transition_table_t<std::pair<EV1, ST2>, std::pair<EV2, STN>, std::pair<EV3, STN>, std::pair<EV3, STN>>;
void exit()
{
std::cout << "transit from " << ID << "-state\n";
}
}; };
// struct STN : fsm::MccFsmAbstractState { // struct STN : fsm::MccFsmAbstractState {
@ -124,7 +136,21 @@ int main()
*/ */
fsm::MccFiniteStateMachine(ST1{}); fsm::MccFiniteStateMachine fsmach(ST1{});
fsmach.dispatchEvent<EV1>();
// fsmach.dispatchEvent<EV1>();
// using tab_t = fsm::fsm_transition_table_t<std::pair<EV1, ST2>, std::pair<EV3, ST1>>;
// using st_t = tab_t::find_state_by_event_t<EV2>;
// int status;
// char* aa = abi::__cxa_demangle(typeid(st_t).name(), NULL, NULL, &status);
// std::cout << "aa = " << aa << "\n";
// free(aa);
return 0; return 0;
} }