reintroduced optional enter/exit methods for each state

This commit is contained in:
Francisco Paisana 2020-03-31 12:33:03 +01:00 committed by Francisco Paisana
parent 7c76a64238
commit 7dc1489ea7
4 changed files with 66 additions and 18 deletions

View File

@ -310,11 +310,16 @@ template <typename... Args>
class choice_t : private choice_details::tagged_union_t<Args...> class choice_t : private choice_details::tagged_union_t<Args...>
{ {
using base_t = choice_details::tagged_union_t<Args...>; using base_t = choice_details::tagged_union_t<Args...>;
public:
//! Useful metafunction
template <typename T> template <typename T>
using enable_if_can_hold = using enable_if_can_hold =
typename std::enable_if<base_t::template can_hold_type<typename std::decay<T>::type>()>::type; typename std::enable_if<base_t::template can_hold_type<typename std::decay<T>::type>()>::type;
template <typename T>
using disable_if_can_hold =
typename std::enable_if<not base_t::template can_hold_type<typename std::decay<T>::type>()>::type;
public:
using base_t::can_hold_type; using base_t::can_hold_type;
using base_t::get; using base_t::get;
using base_t::get_if; using base_t::get_if;
@ -408,6 +413,12 @@ const T* get_if(const choice_t<Args...>& c)
return c.template get_if<T>(); return c.template get_if<T>();
} }
template <typename T, typename... Args>
T& get(choice_t<Args...>& c)
{
return c.template get<T>();
}
template <std::size_t I, typename... Args> template <std::size_t I, typename... Args>
auto get(const choice_t<Args...>& c) -> decltype(c.template get<I>()) auto get(const choice_t<Args...>& c) -> decltype(c.template get<I>())
{ {

View File

@ -57,13 +57,25 @@ struct variant_convert {
{ {
static_assert(not std::is_same<typename std::decay<State>::type, typename std::decay<PrevState>::type>::value, static_assert(not std::is_same<typename std::decay<State>::type, typename std::decay<PrevState>::type>::value,
"State cannot transition to itself.\n"); "State cannot transition to itself.\n");
if (p != nullptr) {
srslte::get<PrevState>(*v).exit();
}
*v = std::move(s); *v = std::move(s);
srslte::get<State>(*v).enter();
} }
TargetVariant* v; TargetVariant* v;
PrevState* p; PrevState* p;
}; };
struct fsm_helper { struct fsm_helper {
//! Metafunction to determine if FSM can hold given State type
template <typename FSM>
using get_fsm_state_list = decltype(std::declval<typename FSM::derived_view>().states);
template <typename FSM, typename State>
using enable_if_fsm_state = typename get_fsm_state_list<FSM>::template enable_if_can_hold<State>;
template <typename FSM, typename State>
using disable_if_fsm_state = typename get_fsm_state_list<FSM>::template disable_if_can_hold<State>;
//! Stayed in same state //! Stayed in same state
template <typename FSM, typename PrevState> template <typename FSM, typename PrevState>
static void handle_state_change(FSM* f, same_state* s, PrevState* p) static void handle_state_change(FSM* f, same_state* s, PrevState* p)
@ -79,17 +91,25 @@ struct fsm_helper {
} }
//! Simple state transition in FSM //! Simple state transition in FSM
template <typename FSM, typename State, typename PrevState> template <typename FSM, typename State, typename PrevState>
static auto handle_state_change(FSM* f, State* s, PrevState* p) -> decltype(f->states = std::move(*s), void()) static enable_if_fsm_state<FSM, State> handle_state_change(FSM* f, State* s, PrevState* p)
{ {
static_assert(not std::is_same<State, PrevState>::value, "State cannot transition to itself.\n"); static_assert(not std::is_same<State, PrevState>::value, "State cannot transition to itself.\n");
if (p != nullptr) {
srslte::get<PrevState>(f->states).exit();
}
f->states = std::move(*s); f->states = std::move(*s);
srslte::get<State>(f->states).enter();
} }
//! State not present in current FSM. Attempt state transition in parent FSM in the case of NestedFSM //! State not present in current FSM. Attempt state transition in parent FSM in the case of NestedFSM
template <typename FSM, typename... Args> template <typename FSM, typename State, typename PrevState>
static void handle_state_change(FSM* f, Args&&... args) static disable_if_fsm_state<FSM, State> handle_state_change(FSM* f, State* s, PrevState* p)
{ {
static_assert(FSM::is_nested, "State is not present in the FSM list of valid states"); static_assert(FSM::is_nested, "State is not present in the FSM list of valid states");
handle_state_change(f->parent_fsm()->derived(), args...); if (p != nullptr) {
srslte::get<PrevState>(f->states).exit();
p = nullptr;
}
handle_state_change(f->parent_fsm()->derived(), s, p);
} }
//! Trigger Event, that will result in a state transition //! Trigger Event, that will result in a state transition
@ -140,10 +160,12 @@ class state_t
public: public:
state_t() = default; state_t() = default;
virtual const char* name() const = 0; virtual const char* name() const = 0;
virtual void enter() {}
virtual void exit() {}
}; };
template <typename Derived> template <typename Derived>
class fsm_t class fsm_t : public state_t
{ {
public: public:
// get access to derived protected members from the base // get access to derived protected members from the base
@ -155,8 +177,6 @@ public:
}; };
static const bool is_nested = false; static const bool is_nested = false;
virtual const char* name() const = 0;
// Push Events to FSM // Push Events to FSM
template <typename Ev> template <typename Ev>
void trigger(Ev&& e) void trigger(Ev&& e)

View File

@ -77,6 +77,10 @@ static_assert(std::is_same<tagged_union_t<char, int, double>::default_type, char
static_assert(tagged_union_t<char, int, double>::can_hold_type<int>(), "Can hold type implementation is incorrect\n"); static_assert(tagged_union_t<char, int, double>::can_hold_type<int>(), "Can hold type implementation is incorrect\n");
static_assert(not tagged_union_t<char, int, double>::can_hold_type<uint8_t>(), static_assert(not tagged_union_t<char, int, double>::can_hold_type<uint8_t>(),
"Can hold type implementation is incorrect\n"); "Can hold type implementation is incorrect\n");
static_assert(std::is_same<choice_t<char, int, double>::enable_if_can_hold<char>, void>::value,
"Metafunction enable if not working\n");
static_assert(std::is_same<choice_t<char, int, double>::disable_if_can_hold<float>, void>::value,
"Metafunction enable if not working\n");
} // namespace choice_details } // namespace choice_details
} // namespace srslte } // namespace srslte

View File

@ -38,18 +38,13 @@ public:
uint32_t idle_enter_counter = 0, state1_enter_counter = 0; uint32_t idle_enter_counter = 0, state1_enter_counter = 0;
uint32_t foo_counter = 0; uint32_t foo_counter = 0;
fsm1() : states(idle_st{this}) {}
const char* name() const override { return "fsm1"; } const char* name() const override { return "fsm1"; }
// idle state // idle state
struct idle_st : srslte::state_t { struct idle_st : public srslte::state_t {
idle_st(fsm1* f) idle_st(fsm1* f) { f->idle_enter_counter++; }
{ void enter() final { test_log->info("fsm1::%s::enter called\n", name()); }
test_log->info("fsm1::%s::enter called\n", name()); void exit() final { test_log->info("fsm1::%s::exit called\n", name()); }
f->idle_enter_counter++;
}
~idle_st() { test_log->info("fsm1::%s::exit called\n", name()); }
const char* name() const final { return "idle"; } const char* name() const final { return "idle"; }
}; };
@ -72,7 +67,7 @@ public:
struct state_inner : public srslte::state_t { struct state_inner : public srslte::state_t {
const char* name() const final { return "state_inner"; } const char* name() const final { return "state_inner"; }
state_inner() { test_log->info("fsm2::%s::enter called\n", name()); } state_inner() { test_log->info("fsm2::%s::enter called\n", name()); }
~state_inner() { test_log->info("fsm2::%s::exit called\n", name()); } void exit() final { test_log->info("fsm2::%s::exit called\n", name()); }
}; };
fsm2(fsm1* f_) : nested_fsm_t(f_) { test_log->info("%s::enter called\n", name()); } fsm2(fsm1* f_) : nested_fsm_t(f_) { test_log->info("%s::enter called\n", name()); }
@ -130,6 +125,24 @@ auto fsm1::react(state1& s, ev2 e) -> srslte::state_list<idle_st, fsm2>
return idle_st{this}; return idle_st{this};
} }
// Static Checks
namespace srslte {
namespace fsm_details {
static_assert(std::is_same<fsm_helper::get_fsm_state_list<fsm1>,
srslte::state_list<fsm1::idle_st, fsm1::state1, fsm1::fsm2> >::value,
"get state list failed\n");
static_assert(std::is_same<fsm_helper::enable_if_fsm_state<fsm1, fsm1::idle_st>, void>::value,
"get state list failed\n");
static_assert(std::is_same<fsm_helper::disable_if_fsm_state<fsm1, fsm1::fsm2::state_inner>, void>::value,
"get state list failed\n");
} // namespace fsm_details
} // namespace srslte
// Runtime checks
int test_hsm() int test_hsm()
{ {
test_log->set_level(srslte::LOG_LEVEL_INFO); test_log->set_level(srslte::LOG_LEVEL_INFO);