From d502796d6b11081d82b884a146ae0ebd1b4bcbb9 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Tue, 3 Jun 2025 23:42:05 +0300 Subject: [PATCH] ... --- cxx/mcc_finite_state_machine.h | 135 +++++++++++++++++++++++++++++++-- cxx/mcc_traits.h | 5 ++ cxx/tests/fsm_test.cpp | 12 +++ 3 files changed, 147 insertions(+), 5 deletions(-) diff --git a/cxx/mcc_finite_state_machine.h b/cxx/mcc_finite_state_machine.h index f1bf457..c82ac96 100644 --- a/cxx/mcc_finite_state_machine.h +++ b/cxx/mcc_finite_state_machine.h @@ -12,6 +12,8 @@ #include #include +#include "mcc_traits.h" + namespace mcc::fsm { @@ -230,14 +232,14 @@ protected: template struct deduce_states, InTplTs...> { - // using curr_collection_t = merge_tuples_t>; - using curr_collection_t = - merge_tuples_t, typename StTs::transition_t::unique_states_t...>; + using curr_collection_t = merge_tuples_t>; + // 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, - // merge_tuples_t, - typename StTs::transition_t::unique_states_t..., + merge_tuples_t, + // typename StTs::transition_t::unique_states_t..., InTplTs...>::states_t; }; @@ -336,9 +338,44 @@ protected: std::vector> _destroyFunc{}; std::string_view _currentStateID; + std::vector _stateID; + std::vector _eventID; std::mutex _transitionMutex; + + template + void setupInstanceFuncs(FT&& func, std::index_sequence) + { + ((_dispatchEventFunc>[this] = std::forward(func)), ...); + + (_moveFunc.emplace_back([](MccFiniteStateMachine* from, MccFiniteStateMachine* to) { + _dispatchEventFunc>[to] = + std::move(_dispatchEventFunc>[from]); + }), + ...); + + (_copyFunc.emplace_back([](const MccFiniteStateMachine* from, MccFiniteStateMachine* to) { + _dispatchEventFunc>[to] = + _dispatchEventFunc>[from]; + }), + ...); + + (_destroyFunc.emplace_back([](const MccFiniteStateMachine* inst) { + // + _dispatchEventFunc>.erase(inst); + }), + ...); + + (_eventID.emplace_back(std::tuple_element_t::ID), ...); + }; + + template + void setupInstanceFuncs(FT&& func) + { + setupInstanceFuncs(std::forward(func), std::make_index_sequence>()); + }; + static MccFiniteStateMachine& copyInstance(const MccFiniteStateMachine* from, MccFiniteStateMachine* to) { if (from != to) { @@ -381,6 +418,10 @@ public: auto currentState = std::make_shared>(); *currentState = &std::get(*states); + _stateID = [](std::tuple&) { + return std::vector({STs::ID...}); + }(*states); + int status; char* aa = abi::__cxa_demangle(typeid(states_t).name(), NULL, NULL, &status); std::cout << "deduced states_t = " << aa << '\n'; @@ -409,6 +450,10 @@ public: // setup dispatch event functions using all_events_t = deduce_events_t; + + // for_each_event([this](EvT) { _eventID.emplace_back(EvT::ID); }); + + /* for_each_event([states, currentState, this](EvT) mutable { if constexpr (!in_tuple_v) { throw std::system_error(MccFiniteStateMachineErrorCode::ERROR_UNREGISTERED_EVENT_TYPE); @@ -470,6 +515,52 @@ public: _dispatchEventFunc.erase(inst); }); }); + */ + + setupInstanceFuncs([states, currentState, this](EvT& event) mutable { + std::lock_guard lock(_transitionMutex); + + std::visit( + [&event, states, currentState, this](curr_state_t*) { + using to_state_t = curr_state_t::transition_t::template find_state_by_event_t; + if constexpr (!std::is_void_v) { + // 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.onTransit() }; + }) { + event.onTransit(); + } + + *currentState = &std::get(*states); + _currentStateID = to_state_t::ID; + + // 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(); + } + } else { + throw std::system_error(MccFiniteStateMachineErrorCode::ERROR_UNHANDLED_TRANSITION); + } + }, + *currentState); + }); std::cout << "MOVE VEC: " << _moveFunc.size() << "\n"; } @@ -518,6 +609,40 @@ public: { return _currentStateID; } + + + template + R stateIDs() const + { + R r; + for (auto& el : _stateID) { + std::back_inserter(r) = {el.begin(), el.end()}; + } + + return r; + } + + std::vector stateIDs() const + { + return stateIDs>(); + } + + + template + R eventIDs() const + { + R r; + for (auto& el : _eventID) { + std::back_inserter(r) = {el.begin(), el.end()}; + } + + return r; + } + + std::vector eventIDs() const + { + return eventIDs>(); + } }; diff --git a/cxx/mcc_traits.h b/cxx/mcc_traits.h index 5369df9..a23ec79 100644 --- a/cxx/mcc_traits.h +++ b/cxx/mcc_traits.h @@ -32,6 +32,11 @@ concept mcc_range_of_input_char_range = std::ranges::range && traits::mcc_input_char_range>; +template +concept mcc_range_of_output_char_range = + std::ranges::range && traits::mcc_output_char_range>; + + // https://stackoverflow.com/questions/72430369/how-to-check-that-a-type-is-formattable-using-type-traits-concepts) template diff --git a/cxx/tests/fsm_test.cpp b/cxx/tests/fsm_test.cpp index 5d9f312..e54c8fa 100644 --- a/cxx/tests/fsm_test.cpp +++ b/cxx/tests/fsm_test.cpp @@ -138,6 +138,18 @@ int main() fsm::MccFiniteStateMachine fsmach(ST1{}); + std::cout << "STATES: "; + for (auto& el : fsmach.stateIDs()) { + std::cout << std::quoted(el) << " "; + } + std::cout << "\n"; + + std::cout << "EVENTS: "; + for (auto& el : fsmach.eventIDs()) { + std::cout << std::quoted(el) << " "; + } + std::cout << "\n"; + fsmach.dispatchEvent(); // fsmach.dispatchEvent();