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