MccFiniteStateMachine: compiled and works (again ... :) )
This commit is contained in:
parent
9bee1ca0ea
commit
52a29e0f91
@ -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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user