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 <functional>
#include <memory>
#include <mutex>
#include <string_view>
#include <tuple>
#include <unordered_map>
@ -14,6 +15,64 @@
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
{
@ -221,26 +280,64 @@ protected:
using variant_from_tuple_t = typename variant_from_tuple<TplT>::variant_t;
//
template <typename EvTplT, typename FT, size_t... Is>
// call given function for all event-types in the given std::tuple
template <traits::fsm_tuple_of_events_c EvTplT, typename FT, size_t... Is>
static void for_each_event(FT&& func, std::index_sequence<Is...>)
{
(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)
{
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>
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(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)
{
@ -249,6 +346,7 @@ protected:
func(from, to);
}
to->_currentStateID = from->_currentStateID;
to->_moveFunc = from->_moveFunc;
to->_copyFunc = from->_copyFunc;
to->_destroyFunc = from->_destroyFunc;
@ -264,6 +362,7 @@ protected:
func(from, to);
}
to->_currentStateID = std::move(from->_currentStateID);
to->_moveFunc = std::move(from->_moveFunc);
to->_copyFunc = std::move(from->_copyFunc);
to->_destroyFunc = std::move(from->_destroyFunc);
@ -274,7 +373,7 @@ protected:
public:
template <traits::fsm_state_c InitStateT>
MccFiniteStateMachine(InitStateT)
MccFiniteStateMachine(InitStateT) : _currentStateID(InitStateT::ID)
{
using states_t = deduce_states_t<InitStateT>;
auto states = std::make_shared<states_t>();
@ -308,15 +407,23 @@ public:
// 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 {
std::lock_guard lock(_transitionMutex);
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>;
if constexpr (!std::is_void_v<to_state_t>) {
// exit from current
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);
} else if constexpr (requires(curr_state_t inst) {
@ -327,23 +434,26 @@ public:
// transit ...
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
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) {
{ 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);
@ -355,25 +465,39 @@ public:
_copyFunc.emplace_back([](const MccFiniteStateMachine* from, MccFiniteStateMachine* to) {
_dispatchEventFunc<EvT>[to] = _dispatchEventFunc<EvT>[from];
});
_destroyFunc.emplace_back([](MccFiniteStateMachine* inst) {
_destroyFunc.emplace_back([](const MccFiniteStateMachine* 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()
{
for (auto& func : _destroyFunc) {
func();
func(this);
}
}
@ -382,6 +506,18 @@ public:
{
_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 {
static constexpr std::string_view ID = "EV1";
// EV1() = default;
// EV1(EV1&&) = default;
// EV1& operator=(EV1&&) = default;
void onTransit()
{
//
std::cout << "EV1::onTransit()\n";
}
};
struct EV2 {
@ -44,12 +46,22 @@ struct ST3 {
struct ST2 {
static constexpr std::string_view ID = "ST2";
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 {
static constexpr std::string_view ID = "ST1";
using transition_t =
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 {
@ -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;
}