From 6e34dadce261747cfecacf01c487f68b953d68f2 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sun, 5 Apr 2020 18:29:24 +0100 Subject: [PATCH] reverted back to tuples to store fsm state_list --- lib/include/srslte/common/choice_type.h | 247 +++------------------- lib/include/srslte/common/fsm.h | 217 ++++++++++++------- lib/include/srslte/common/type_utils.h | 263 ++++++++++++++++++++++++ lib/test/common/choice_type_test.cc | 54 +++-- lib/test/common/fsm_test.cc | 67 +++--- 5 files changed, 491 insertions(+), 357 deletions(-) create mode 100644 lib/include/srslte/common/type_utils.h diff --git a/lib/include/srslte/common/choice_type.h b/lib/include/srslte/common/choice_type.h index 5d951c623..d9e97900d 100644 --- a/lib/include/srslte/common/choice_type.h +++ b/lib/include/srslte/common/choice_type.h @@ -19,57 +19,13 @@ * */ -#include -#include -#include +#include "type_utils.h" #ifndef SRSLTE_CHOICE_TYPE_H #define SRSLTE_CHOICE_TYPE_H namespace srslte { -namespace choice_details { - -using size_idx_t = std::size_t; - -static constexpr size_idx_t invalid_idx = std::numeric_limits::max(); - -class bad_choice_access : public std::runtime_error -{ -public: - explicit bad_choice_access(const std::string& what_arg) : runtime_error(what_arg) {} - explicit bad_choice_access(const char* what_arg) : runtime_error(what_arg) {} -}; - -//! Get Index of a type in a list of types (reversed) -template -struct type_indexer; - -template -struct type_indexer { - static constexpr size_idx_t index = - std::is_same::value ? sizeof...(Types) : type_indexer::index; -}; - -template -struct type_indexer { - static constexpr size_idx_t index = invalid_idx; -}; - -//! Get a type of an index in a list of types -template -struct type_get; - -template -struct type_get { - using type = typename std::conditional::type>::type; -}; - -template -struct type_get { - using type = void; -}; - //! Compute maximum at compile time template struct static_max; @@ -83,6 +39,8 @@ struct static_max { arg1 >= arg2 ? static_max::value : static_max::value; }; +namespace choice_details { + //! Holds one of the Args types template struct choice_storage_t { @@ -94,13 +52,13 @@ struct choice_storage_t { void* get_buffer() { return &buffer; } template - T& get_unsafe() + T& get_unchecked() { return *reinterpret_cast(&buffer); } template - const T& get_unsafe() const + const T& get_unchecked() const { return *reinterpret_cast(&buffer); } @@ -108,7 +66,7 @@ struct choice_storage_t { template void destroy_unsafe() { - get_unsafe().~U(); + get_unchecked().~U(); }; }; @@ -149,75 +107,29 @@ struct DtorUnsafeVisitor { C* c; }; -/** - * @brief visit pattern implementation - * @tparam F functor - * @tparam V tagged union type - * @tparam Types remaining types to iterate - */ -template -struct visit_impl; - -template -struct visit_impl { - static void apply(V& c, F&& f) - { - if (c.template is()) { - f(c.template get_unsafe()); - } else { - visit_impl::apply(c, std::forward(f)); - } - } - static void apply(const V& c, F&& f) - { - if (c.template is()) { - f(c.template get_unsafe()); - } else { - visit_impl::apply(c, std::forward(f)); - } - } -}; -template -struct visit_impl { - static void apply(V& c, F&& f) { f(c.template get_unsafe()); } - static void apply(const V& c, F&& f) { f(c.template get_unsafe()); } -}; - template struct tagged_union_t; -template -void visit(tagged_union_t& u, Functor&& f) -{ - visit_impl, First, Args...>::apply(u, std::forward(f)); -} -template -void visit(const tagged_union_t& u, Functor&& f) -{ - visit_impl, First, Args...>::apply(u, std::forward(f)); -} - template struct tagged_union_t : private choice_storage_t::value, static_max::value> { - using base_t = choice_storage_t::value, static_max::value>; - using buffer_t = typename base_t::buffer_t; - using this_type = tagged_union_t; - using default_type = typename type_get::type; + using base_t = choice_storage_t::value, static_max::value>; + using buffer_t = typename base_t::buffer_t; + using this_type = tagged_union_t; std::size_t type_id; using base_t::destroy_unsafe; using base_t::get_buffer; - using base_t::get_unsafe; + using base_t::get_unchecked; template void construct_emplace_unsafe(Args2&&... args) { using U2 = typename std::decay::type; - static_assert(type_indexer::index != invalid_idx, + static_assert(type_list_contains(), "The provided type to ctor is not part of the list of possible types"); - type_id = type_indexer::index; + type_id = get_type_index(); new (get_buffer()) U2(std::forward(args)...); } @@ -225,82 +137,30 @@ struct tagged_union_t void construct_unsafe(U&& u) { using U2 = typename std::decay::type; - static_assert(type_indexer::index != invalid_idx, + static_assert(type_list_contains(), "The provided type to ctor is not part of the list of possible types"); - type_id = type_indexer::index; + type_id = get_type_index(); new (get_buffer()) U2(std::forward(u)); } - void copy_unsafe(const this_type& other) { visit(other, CopyCtorVisitor{this}); } + void copy_unsafe(const this_type& other) { visit(CopyCtorVisitor{this}, other); } - void move_unsafe(this_type&& other) { visit(other, MoveCtorVisitor{this}); } + void move_unsafe(this_type&& other) { visit(MoveCtorVisitor{this}, other); } - void dtor_unsafe() { visit(*this, choice_details::DtorUnsafeVisitor{this}); } + void dtor_unsafe() { visit(choice_details::DtorUnsafeVisitor{this}, *this); } - template ::type> - T& get_unsafe() - { - return get_unsafe(); - } + size_t get_type_idx() const { return type_id; } template bool is() const { - return type_indexer::index == type_id; - } - - template - T& get() - { - if (is()) { - return get_unsafe(); - } - throw choice_details::bad_choice_access{"in get"}; - } - - template - const T& get() const - { - if (is()) { - return get_unsafe(); - } - throw choice_details::bad_choice_access{"in get"}; - } - - template ::type> - T& get() - { - if (is()) { - return get_unsafe(); - } - throw choice_details::bad_choice_access{"in get"}; - } - - template ::type> - const T& get() const - { - if (is()) { - return get_unsafe(); - } - throw choice_details::bad_choice_access{"in get"}; - } - - template - T* get_if() - { - return (is()) ? &get_unsafe() : nullptr; - } - - template - const T* get_if() const - { - return (is()) ? &get_unsafe() : nullptr; + return get_type_index() == type_id; } template constexpr static bool can_hold_type() { - return type_indexer::index != invalid_idx; + return type_list_contains(); } }; @@ -312,6 +172,7 @@ class choice_t : private choice_details::tagged_union_t using base_t = choice_details::tagged_union_t; public: + using default_type = typename get_index_type<0, Args...>::type; //! Useful metafunction template using enable_if_can_hold = @@ -321,16 +182,14 @@ public: typename std::enable_if::type>()>::type; using base_t::can_hold_type; - using base_t::get; - using base_t::get_if; + using base_t::get_unchecked; using base_t::is; - template < - typename... Args2, - typename = typename std::enable_if::value>::type> + template ::value>::type> explicit choice_t(Args2&&... args) noexcept { - base_t::template construct_emplace_unsafe(std::forward(args)...); + base_t::template construct_emplace_unsafe(std::forward(args)...); } choice_t(const choice_t& other) noexcept { base_t::copy_unsafe(other); } @@ -379,64 +238,8 @@ public: } bool holds_same_type(const choice_t& other) noexcept { return base_t::type_id == other.type_id; } - - template - void visit(Functor&& f) - { - choice_details::visit(*static_cast(this), f); - } - - template - void visit(Functor&& f) const - { - choice_details::visit(*static_cast(this), f); - } - -private: }; -template -bool holds_alternative(const Choice& u) -{ - return u.template is(); -} - -template -T* get_if(choice_t& c) -{ - return c.template get_if(); -} - -template -const T* get_if(const choice_t& c) -{ - return c.template get_if(); -} - -template -T& get(choice_t& c) -{ - return c.template get(); -} - -template -auto get(const choice_t& c) -> decltype(c.template get()) -{ - return c.template get(); -} - -template -void visit(choice_t& u, Functor&& f) -{ - u.visit(std::forward(f)); -} - -template -void visit(const choice_t& u, Functor&& f) -{ - u.visit(std::forward(f)); -} - } // namespace srslte #endif // SRSLTE_CHOICE_TYPE_H diff --git a/lib/include/srslte/common/fsm.h b/lib/include/srslte/common/fsm.h index abb734c05..b6d06ff44 100644 --- a/lib/include/srslte/common/fsm.h +++ b/lib/include/srslte/common/fsm.h @@ -22,52 +22,47 @@ #ifndef SRSLTE_FSM_H #define SRSLTE_FSM_H -#include "choice_type.h" #include "srslte/common/logmap.h" -#include +#include "type_utils.h" #include -#include #include #include #include namespace srslte { -//! Helper to print the name of a type for logging -#if defined(__GNUC__) && !defined(__clang__) -template -std::string get_type_name() -{ - static const char* funcname = __PRETTY_FUNCTION__; - static const std::string s = []() { - static const char* pos1 = strchr(funcname, '=') + 2; - static const char* pos2 = strchr(pos1, ';'); - std::string s2{pos1, pos2}; - size_t colon_pos = s2.rfind(':'); - std::string s3 = colon_pos == std::string::npos ? s2 : s2.substr(colon_pos + 1, s2.size()); - return s3.find('>') == std::string::npos ? s3 : s2; - }(); - return s; -} -#else -template -std::string get_type_name() -{ - return "anonymous"; -} -#endif +//! Transition Type +template +struct to_state { + using next_state = NextState; +}; -//! This version leverages argument type deduction. (e.g. get_type_name(var)) -template -std::string get_type_name(const T& t) -{ - return get_type_name(); -} +template +struct to_states { + template + to_states(to_state) : state_idx(get_type_index()) + { + } + + template + bool is() const + { + return get_type_index() == state_idx; + } + + size_t get_type_idx() const { return state_idx; } + + size_t state_idx; +}; //! Return for when there is no state transition struct same_state { }; +//! Forward declaration +template +class fsm_t; + namespace fsm_details { //! Visitor to get a state's name string @@ -77,15 +72,15 @@ struct state_name_visitor { { name = get_type_name(s); } - std::string name = "invalid state"; + std::string name = "invalid"; }; -//! Visitor to convert a type inside a choice to another choice +//! Visitor to convert a to_state back to a single state template -struct choice_to_state_visitor { - choice_to_state_visitor(FSM* f_, PrevState* p_) : f(f_), p(p_) {} +struct to_state_visitor { + to_state_visitor(FSM* f_, PrevState* p_) : f(f_), p(p_) {} template - void operator()(State& s); + void operator()(); FSM* f; PrevState* p; }; @@ -99,25 +94,37 @@ struct enter_visitor { FSM* f; }; +//! Helper metafunctions +template +using enable_if_fsm_state = typename std::enable_if()>::type; +template +using disable_if_fsm_state = typename std::enable_if()>::type; +template +constexpr bool is_fsm() +{ + return std::is_base_of, FSM>::value; +} +template +constexpr bool is_nested_fsm() +{ + return is_fsm() and FSM::is_nested; +} + struct fsm_helper { //! Metafunction to determine if FSM can hold given State type template - using get_fsm_state_list = decltype(std::declval().states); - template - using enable_if_fsm_state = typename get_fsm_state_list::template enable_if_can_hold; - template - using disable_if_fsm_state = typename get_fsm_state_list::template disable_if_can_hold; + using fsm_state_list_type = decltype(std::declval().states); //! Call FSM/State enter method template - static auto call_enter(FSM* f, State* s) -> decltype(s->derived()->parent_fsm(), void()) + static typename std::enable_if()>::type call_enter(FSM* f, State* s) { f->enter(*s); fsm_details::enter_visitor visitor{s->derived()}; - s->derived()->states.visit(visitor); + srslte::visit(visitor, s->derived()->states); } template - static void call_enter(FSM* f, State* s, Args&&...) + static typename std::enable_if()>::type call_enter(FSM* f, State* s) { f->enter(*s); } @@ -130,30 +137,30 @@ struct fsm_helper { } //! TargetState is type-erased (a choice). Apply its stored type to the fsm current state template - static void handle_state_change(FSM* f, choice_t* s, PrevState* p) + static void handle_state_change(FSM* f, to_states* s, PrevState* p) { - choice_to_state_visitor visitor{f, p}; - s->visit(visitor); + to_state_visitor visitor{f, p}; + srslte::static_visit(visitor, *s); } //! Simple state transition in FSM (no same_state of entry in nested FSM) template - static enable_if_fsm_state handle_state_change(FSM* f, State* s, PrevState* p) + static auto handle_state_change(FSM* f, to_state* s, PrevState* p) -> enable_if_fsm_state { static_assert(not std::is_same::value, "State cannot transition to itself.\n"); - f->exit(srslte::get(f->states)); - f->states.transit(std::move(*s)); + f->exit(f->states.template get_unchecked()); + f->states.template transit(); f->log_h->info("FSM \"%s\": Detected transition \"%s\" -> \"%s\"", get_type_name().c_str(), get_type_name().c_str(), get_type_name().c_str()); - call_enter(f, &srslte::get(f->states)); + call_enter(f, &f->states.template get_unchecked()); } //! State not present in current FSM. Attempt state transition in parent FSM in the case of NestedFSM template - static disable_if_fsm_state handle_state_change(FSM* f, State* s, PrevState* p) + static auto handle_state_change(FSM* f, to_state* s, PrevState* p) -> disable_if_fsm_state { static_assert(FSM::is_nested, "State is not present in the FSM list of valid states"); - f->exit(srslte::get(f->states)); + f->exit(f->states.template get_unchecked()); handle_state_change(f->parent_fsm()->derived(), s, static_cast(f)); } @@ -203,9 +210,10 @@ struct fsm_helper { template template -void choice_to_state_visitor::operator()(State& s) +void to_state_visitor::operator()() { - fsm_helper::handle_state_change(f, &s, p); + to_state t; + fsm_helper::handle_state_change(f, &t, p); } template @@ -219,10 +227,10 @@ void enter_visitor::operator()(State&& s) //! Gets the typename currently stored in the choice_t template -std::string get_type_name(const srslte::choice_t& t) +std::string get_type_name(const srslte::to_states& t) { fsm_details::state_name_visitor v{}; - t.visit(v); + srslte::visit(v, t); return v.name; } @@ -232,6 +240,7 @@ class fsm_t { protected: using base_t = fsm_t; + //! get access to derived protected members from the base class derived_view : public Derived { @@ -251,24 +260,65 @@ protected: public: static const bool is_nested = false; + template + using to_state = srslte::to_state; + template + using to_states = srslte::to_states; //! Struct used to store FSM states template - struct state_list : public choice_t { - using base_t = choice_t; + struct state_list : public std::tuple { + using tuple_base_t = std::tuple; template - state_list(fsm_t* f, Args&&... args) : base_t(std::forward(args)...) + state_list(fsm_t* f, Args&&... args) : tuple_base_t(std::forward(args)...) { if (not Derived::is_nested) { + // If Root FSM, call initial state enter method fsm_details::enter_visitor visitor{f->derived()}; - f->derived()->states.visit(visitor); + srslte::visit(visitor, *this); } } + + template + bool is() const + { + return type_idx() == current_idx; + } + + template + State& get_unchecked() + { + return std::get()>(*this); + } + + template + const State& get_unchecked() const + { + return std::get()>(*this); + } + + template + void transit() + { + current_idx = type_idx(); + } + template - void transit(State&& s) + constexpr static bool can_hold_type() { - this->template emplace(std::forward(s)); + return srslte::type_list_contains(); } + + template + constexpr static size_t type_idx() + { + return get_type_index(); + } + + size_t get_type_idx() const { return current_idx; } + + private: + size_t current_idx = 0; }; explicit fsm_t(srslte::log_ref log_) : log_h(log_) {} @@ -278,7 +328,7 @@ public: void trigger(Ev&& e) { fsm_details::fsm_helper::trigger_visitor visitor{derived(), std::forward(e)}; - derived()->states.visit(visitor); + srslte::visit(visitor, derived()->states); } template @@ -290,13 +340,13 @@ public: template const State* get_state() const { - return srslte::get_if(derived()->states); + return is_in_state() ? &derived()->states.template get_unchecked() : nullptr; } std::string get_state_name() const { fsm_details::state_name_visitor visitor{}; - derived()->states.visit(visitor); + srslte::visit(visitor, derived()->states); return visitor.name; } @@ -304,7 +354,7 @@ public: template constexpr static bool can_hold_state() { - return fsm_details::fsm_helper::get_fsm_state_list >::template can_hold_type(); + return fsm_details::fsm_helper::fsm_state_list_type >::template can_hold_type(); } void set_fsm_event_log_level(srslte::LOG_LEVEL_ENUM e) { fsm_event_log_level = e; } @@ -395,7 +445,7 @@ struct proc_launch_ev { explicit proc_launch_ev(Args&&... args_) : args(std::forward(args_)...) {} }; -template +template class proc_fsm_t : public fsm_t { using fsm_type = Derived; @@ -425,9 +475,6 @@ public: struct idle_st { }; struct complete_st { - complete_st(bool success_) : success(success_) {} - bool success; - Result result; }; explicit proc_fsm_t(srslte::log_ref log_) : fsm_t(log_) {} @@ -448,10 +495,32 @@ protected: } void enter(complete_st& s) { trigger(reset_ev{}); } - auto react(complete_st& s, reset_ev ev) -> idle_st { return {}; } + auto react(complete_st& s, reset_ev ev) -> to_state { return {}; } + + srslte::to_state set_success(Result&& r = {}) + { + result = std::forward(r); + success = true; + return {}; + } + srslte::to_state set_failure() + { + success = false; + return {}; + } + bool is_success() const { return success; } + Result& get_result() const + { + if (is_success()) { + return result; + } + throw bad_type_access{"in proc_fsm_t::get_result"}; + } private: - int launch_counter = 0; + int launch_counter = 0; + bool success = false; + Result result; }; } // namespace srslte diff --git a/lib/include/srslte/common/type_utils.h b/lib/include/srslte/common/type_utils.h new file mode 100644 index 000000000..3ce2d863e --- /dev/null +++ b/lib/include/srslte/common/type_utils.h @@ -0,0 +1,263 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_TYPE_UTILS_H +#define SRSLTE_TYPE_UTILS_H + +#include +#include +#include +#include +#include + +namespace srslte { + +//! Helper to print the name of a type for logging +/** + * @brief Helper function that returns a type name string + */ +#if defined(__GNUC__) && !defined(__clang__) + +template +std::string get_type_name() +{ + static const char* funcname = __PRETTY_FUNCTION__; + static const std::string s = []() { + static const char* pos1 = strchr(funcname, '=') + 2; + static const char* pos2 = strchr(pos1, ';'); + std::string s2{pos1, pos2}; + size_t colon_pos = s2.rfind(':'); + std::string s3 = colon_pos == std::string::npos ? s2 : s2.substr(colon_pos + 1, s2.size()); + return s3.find('>') == std::string::npos ? s3 : s2; + }(); + return s; +} + +#else +template +std::string get_type_name() +{ + return "anonymous"; +} +#endif + +//! This version leverages argument type deduction for shorter syntax. (e.g. get_type_name(var)) +template +std::string get_type_name(const T& t) +{ + return get_type_name(); +} + +constexpr size_t invalid_type_index = std::numeric_limits::max(); + +namespace type_utils_details { + +//! Get Index of a type in a list of types (in reversed order) +template +struct type_list_reverse_index; + +template +struct type_list_reverse_index { + static constexpr size_t index = + std::is_same::value ? sizeof...(Types) : type_list_reverse_index::index; +}; + +template +struct type_list_reverse_index { + static constexpr size_t index = invalid_type_index; +}; + +//! Get a type of an index in a list of types +template +struct get_type_reverse; + +template +struct get_type_reverse { + using type = + typename std::conditional::type>::type; +}; + +template +struct get_type_reverse { + using type = void; +}; + +template +struct static_visit_impl; + +template +struct static_visit_impl { + static void apply(size_t idx, F&& f) + { + if (idx == sizeof...(Types)) { + f.template operator()(); + } else { + static_visit_impl::apply(idx, std::forward(f)); + } + } +}; + +template +struct static_visit_impl { + static void apply(size_t idx, F&& f) { f.template operator()(); } +}; + +/** + * @brief visit pattern implementation + * @tparam F functor + * @tparam V tagged union type + * @tparam Types remaining types to iterate + */ +template +struct visit_impl; + +template +struct visit_impl { + static void apply(TypeList& c, F&& f) + { + if (c.template is()) { + f(c.template get_unchecked()); + } else { + visit_impl::apply(c, std::forward(f)); + } + } + static void apply(const TypeList& c, F&& f) + { + if (c.template is()) { + f(c.template get_unchecked()); + } else { + visit_impl::apply(c, std::forward(f)); + } + } +}; +template +struct visit_impl { + static void apply(TypeList& c, F&& f) { f(c.template get_unchecked()); } + static void apply(const TypeList& c, F&& f) { f(c.template get_unchecked()); } +}; + +} // namespace type_utils_details + +class bad_type_access : public std::runtime_error +{ +public: + explicit bad_type_access(const std::string& what_arg) : runtime_error(what_arg) {} + explicit bad_type_access(const char* what_arg) : runtime_error(what_arg) {} +}; + +//! Get index of T in Types... +template +constexpr size_t get_type_index() +{ + using namespace type_utils_details; + return (type_list_reverse_index::index == invalid_type_index) + ? invalid_type_index + : sizeof...(Types) - type_list_reverse_index::index - 1; +} +template +constexpr bool type_list_contains() +{ + return get_type_index() != invalid_type_index; +} +template +struct get_index_type { + using type = typename type_utils_details::get_type_reverse::type; +}; + +//! srslte::get access methods +template +T* get_if(TypeContainer& c) +{ + return (c.template is()) ? &c.template get_unchecked() : nullptr; +} + +template +const T* get_if(const TypeContainer& c) +{ + return (c.template is()) ? &c.template get_unchecked() : nullptr; +} + +template +T& get(TypeContainer& c) +{ + if (c.template is()) { + return c.template get_unchecked(); + } + throw bad_type_access{"in get"}; +} + +template +const T& get(const TypeContainer& c) +{ + if (c.template is()) { + return c.template get_unchecked(); + } + throw bad_type_access{"in get"}; +} + +template class TypeContainer, + typename... Args, + typename T = typename get_index_type::type> +T& get(TypeContainer& c) +{ + return get(c); +} + +template class TypeContainer, + typename... Args, + typename T = typename get_index_type::type> +const T& get(const TypeContainer& c) +{ + return get(c); +} + +//! Function to static visit a template type that holds many variadic args +template +void static_visit(Visitor&& f, size_t current_idx) +{ + type_utils_details::static_visit_impl::apply(sizeof...(Args) - current_idx - 1, + std::forward(f)); +} +template class TypeSet, typename... Args> +void static_visit(Visitor&& f, const TypeSet& tset) +{ + static_visit(std::forward(f), tset.get_type_idx()); +} + +//! Function to visit a template type that holds many variadic args +template class TypeSet, typename... Args> +void visit(Visitor&& f, TypeSet& tset) +{ + using namespace type_utils_details; + visit_impl, Args...>::apply(tset, std::forward(f)); +} +template class TypeSet, typename... Args> +void visit(Visitor&& f, const TypeSet& tset) +{ + using namespace type_utils_details; + visit_impl, Args...>::apply(tset, std::forward(f)); +} + +} // namespace srslte + +#endif // SRSLTE_TYPE_UTILS_H diff --git a/lib/test/common/choice_type_test.cc b/lib/test/common/choice_type_test.cc index 930592e5c..4cd419030 100644 --- a/lib/test/common/choice_type_test.cc +++ b/lib/test/common/choice_type_test.cc @@ -63,17 +63,16 @@ namespace choice_details { static_assert(static_max<1, 2>::value == 2, "StaticMax not working"); static_assert(static_max<2, 1>::value == 2, "StaticMax not working"); -static_assert(type_indexer::index == 0, "Type indexer not working"); -static_assert(type_indexer::index == 4, "Type indexer not working"); -static_assert(type_indexer::index == invalid_idx, "Type Indexer not working"); +static_assert(get_type_index() == 4, "Type indexer not working"); +static_assert(get_type_index() == 0, "Type indexer not working"); +static_assert(get_type_index() == invalid_type_index, "Type Indexer not working"); static_assert(sizeof(choice_storage_t<5, 4>) == 8, "Size of storage wrongly computed"); static_assert(alignof(choice_storage_t<5, 4>) == 4, "Alignment of storage wrongly computed"); -static_assert(std::is_same::type, double>::value, +static_assert(std::is_same::type, char>::value, "type index-based search not working"); -static_assert(std::is_same::type, float>::value, +static_assert(std::is_same::type, long>::value, "type index-based search not working"); -static_assert(std::is_same::default_type, char>::value, - "Default type is incorrect\n"); +static_assert(std::is_same::default_type, char>::value, "Default type is incorrect\n"); static_assert(tagged_union_t::can_hold_type(), "Can hold type implementation is incorrect\n"); static_assert(not tagged_union_t::can_hold_type(), "Can hold type implementation is incorrect\n"); @@ -91,8 +90,7 @@ int test_tagged_union() tagged_union_t u; u.construct_unsafe(5); TESTASSERT(u.is()); - TESTASSERT(u.get_unsafe() == 5); - TESTASSERT(u.get_unsafe<1>() == 5); + TESTASSERT(u.get_unchecked() == 5); u.destroy_unsafe(); TESTASSERT(C::counter == 0); @@ -106,8 +104,8 @@ int test_tagged_union() int test_choice() { + using srslte::bad_type_access; using srslte::choice_t; - using srslte::choice_details::bad_choice_access; TESTASSERT(C::counter == 0); TESTASSERT(D::counter == 0); @@ -118,47 +116,47 @@ int test_choice() // TEST: correct construction, holding the right type and value choice_t c, c2{i}, c3{c0}; TESTASSERT(c.is()); - TESTASSERT(c2.is() and c2.get() == i and *c2.get_if() == i); - TESTASSERT(c2.get<1>() == c2.get()); + TESTASSERT(c2.is() and srslte::get(c2) == i and *srslte::get_if(c2) == i); + TESTASSERT(srslte::get<1>(c2) == srslte::get(c2)); TESTASSERT(c3.is()); TESTASSERT(C::counter == 2); // TEST: Invalid member access. get<>() should throw - TESTASSERT(c2.get_if() == nullptr); + TESTASSERT(srslte::get_if(c2) == nullptr); bool catched = false; try { char n = '1'; - n = c2.get(); + n = srslte::get(c2); TESTASSERT(n == '1'); - } catch (bad_choice_access& e) { + } catch (bad_type_access& e) { catched = true; } TESTASSERT(catched); // TEST: simple emplace after construction c2 = 'c'; - TESTASSERT(c2.is() and c2.get() == 'c'); + TESTASSERT(c2.is() and srslte::get(c2) == 'c'); // TEST: copy ctor test. choice_t c5{c3}; TESTASSERT(C::counter == 3); TESTASSERT(c5.is()); - TESTASSERT(c5.get_if() == &c5.get()); + TESTASSERT(srslte::get_if(c5) == &srslte::get(c5)); // TEST: copy assignment c = c5; TESTASSERT(C::counter == 4); - TESTASSERT(c.is() and c.get_if() != c5.get_if()); + TESTASSERT(c.is() and srslte::get_if(c) != srslte::get_if(c5)); c = c2; TESTASSERT(C::counter == 3); - TESTASSERT(c2.is() and c.get() == 'c'); + TESTASSERT(c2.is() and srslte::get(c) == 'c'); } TESTASSERT(C::counter == 0); TESTASSERT(D::counter == 0); { choice_t c, c2{5.0}, c3{C{}}, c4{D{}}; TESTASSERT(c.is()); - TESTASSERT(c2.is() and c2.get() == 5.0 and *c2.get_if() == 5.0); + TESTASSERT(c2.is() and srslte::get(c2) == 5.0 and *srslte::get_if(c2) == 5.0); TESTASSERT(c3.is()); TESTASSERT(c4.is()); TESTASSERT(C::counter == 1); @@ -182,7 +180,7 @@ int test_choice() TESTASSERT(D::counter == 3); c = std::move(c2); TESTASSERT(c.is() and c2.is() and c.holds_same_type(c2)); - TESTASSERT(c.get() == c2.get()); + TESTASSERT(srslte::get(c) == srslte::get(c2)); TESTASSERT(C::counter == 2 and D::counter == 2); } TESTASSERT(C::counter == 0); @@ -213,26 +211,26 @@ int test_visit() // TEST: visitor hits integer type which is noop EVisitor v; - srslte::visit(c, v); - TESTASSERT(c.is() and c.get() == 5); + srslte::visit(v, c); + TESTASSERT(c.is() and srslte::get(c) == 5); TESTASSERT(v.pdu == nullptr); // TEST: visitor hits type E and steals pdu E e; e.pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance()); c = std::move(e); - TESTASSERT(c.is() and c.get().pdu != nullptr); - srslte::visit(c, v); + TESTASSERT(c.is() and srslte::get(c).pdu != nullptr); + srslte::visit(v, c); TESTASSERT(v.pdu != nullptr); - TESTASSERT(c.is() and c.get().pdu == nullptr); + TESTASSERT(c.is() and srslte::get(c).pdu == nullptr); // TEST: visitor hits type E and steals pdu. Second type called there is no pdu to steal. v.pdu = nullptr; e.pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance()); c = std::move(e); - c.visit(v); + srslte::visit(v, c); TESTASSERT(v.pdu != nullptr); - c.visit(v); + srslte::visit(v, c); TESTASSERT(v.pdu == nullptr); return SRSLTE_SUCCESS; diff --git a/lib/test/common/fsm_test.cc b/lib/test/common/fsm_test.cc index 857838885..d1cbed688 100644 --- a/lib/test/common/fsm_test.cc +++ b/lib/test/common/fsm_test.cc @@ -42,7 +42,7 @@ public: struct state1 { }; - fsm1(srslte::log_ref log_) : srslte::fsm_t(log_) {} + explicit fsm1(srslte::log_ref log_) : srslte::fsm_t(log_) {} // this state is another FSM class fsm2 : public srslte::nested_fsm_t @@ -52,7 +52,7 @@ public: struct state_inner { }; - fsm2(fsm1* f_) : nested_fsm_t(f_) {} + explicit fsm2(fsm1* f_) : nested_fsm_t(f_) {} ~fsm2() { log_h->info("%s being destroyed!", get_type_name(*this).c_str()); } protected: @@ -65,7 +65,7 @@ public: // FSM2 transitions auto react(state_inner& s, ev1 e) -> srslte::same_state; - auto react(state_inner& s, ev2 e) -> state1; + auto react(state_inner& s, ev2 e) -> srslte::to_state; // list of states state_list states{this}; @@ -87,14 +87,14 @@ protected: void enter(state1& s); // transitions - auto react(idle_st& s, ev1 e) -> state1; - auto react(state1& s, ev1 e) -> fsm2; - auto react(state1& s, ev2 e) -> srslte::choice_t; + auto react(idle_st& s, ev1 e) -> srslte::to_state; + auto react(state1& s, ev1 e) -> srslte::to_state; + auto react(state1& s, ev2 e) -> srslte::to_states; void foo(ev1 e) { foo_counter++; } // list of states - state_list states{this, idle_st{}}; + state_list states = {this, idle_st{}, state1{}, fsm2{this}}; }; void fsm1::enter(idle_st& s) @@ -109,33 +109,33 @@ void fsm1::enter(state1& s) } // FSM event handlers -auto fsm1::fsm2::react(state_inner& s, ev1 e) -> srslte::same_state +auto fsm1::fsm2::react(state_inner& s, ev1) -> srslte::same_state { log_h->info("fsm2::state_inner::react called\n"); return {}; } -auto fsm1::fsm2::react(state_inner& s, ev2 e) -> state1 +auto fsm1::fsm2::react(state_inner& s, ev2) -> srslte::to_state { log_h->info("fsm2::state_inner::react called\n"); return {}; } -auto fsm1::react(idle_st& s, ev1 e) -> state1 +auto fsm1::react(idle_st& s, ev1 e) -> srslte::to_state { log_h->info("%s::react called\n", srslte::get_type_name(s).c_str()); foo(e); return {}; } -auto fsm1::react(state1& s, ev1 e) -> fsm2 +auto fsm1::react(state1& s, ev1) -> srslte::to_state { log_h->info("%s::react called\n", srslte::get_type_name(s).c_str()); - return {this}; + return {}; } -auto fsm1::react(state1& s, ev2 e) -> srslte::choice_t +auto fsm1::react(state1& s, ev2) -> srslte::to_states { log_h->info("%s::react called\n", srslte::get_type_name(s).c_str()); - return idle_st{}; + return srslte::to_state{}; } // Static Checks @@ -143,14 +143,15 @@ auto fsm1::react(state1& s, ev2 e) -> srslte::choice_t namespace srslte { namespace fsm_details { -static_assert(std::is_same, +static_assert(is_fsm(), "invalid metafunction\n"); +static_assert(is_nested_fsm(), "invalid metafunction\n"); +static_assert(std::is_same, fsm1::state_list >::value, "get state list failed\n"); -static_assert(std::is_same, void>::value, - "get state list failed\n"); -static_assert(std::is_same, void>::value, +static_assert(fsm1::can_hold_state(), "failed can_hold_state check\n"); +static_assert(std::is_same, void>::value, "get state list failed\n"); +static_assert(std::is_same, void>::value, "get state list failed\n"); -static_assert(fsm1::can_hold_state(), "can hold state method failed\n"); } // namespace fsm_details } // namespace srslte @@ -190,7 +191,7 @@ int test_hsm() // Moving fsm2 -> state1 f.trigger(ev2{}); - TESTASSERT(std::string{f.get_state_name()} == "state1"); + TESTASSERT(f.get_state_name() == "state1"); TESTASSERT(f.is_in_state()); TESTASSERT(f.state1_enter_counter == 2); @@ -208,7 +209,7 @@ int test_hsm() return SRSLTE_SUCCESS; } -/////////////////////////// +///////////////////////////// struct procevent1 { }; @@ -224,35 +225,35 @@ public: protected: // Transitions - auto react(idle_st& s, srslte::proc_launch_ev ev) -> procstate1; - auto react(procstate1& s, procevent1 ev) -> complete_st; - auto react(procstate1& s, procevent2 ev) -> complete_st; - auto react(complete_st& s, reset_ev ev) -> idle_st; + auto react(idle_st& s, srslte::proc_launch_ev ev) -> to_state; + auto react(procstate1& s, procevent1 ev) -> to_state; + auto react(procstate1& s, procevent2 ev) -> to_state; + auto react(complete_st& s, reset_ev ev) -> to_state; // example of uncaught event handling void unhandled_event(int e) { log_h->info("I dont know how to handle an \"int\" event\n"); } - state_list states{this}; + state_list states{this, idle_st{}, procstate1{}, complete_st{}}; }; -auto proc1::react(idle_st& s, srslte::proc_launch_ev ev) -> procstate1 +auto proc1::react(idle_st& s, srslte::proc_launch_ev ev) -> to_state { log_h->info("started!\n"); return {}; } -auto proc1::react(procstate1& s, procevent1 ev) -> complete_st +auto proc1::react(procstate1& s, procevent1 ev) -> to_state { log_h->info("success!\n"); - return {true}; + return set_success(); } -auto proc1::react(procstate1& s, procevent2 ev) -> complete_st +auto proc1::react(procstate1& s, procevent2 ev) -> to_state { log_h->info("failure!\n"); - return {false}; + return set_failure(); } -auto proc1::react(complete_st& s, reset_ev ev) -> idle_st +auto proc1::react(complete_st& s, reset_ev ev) -> to_state { - log_h->info("propagate results %s\n", s.success ? "success" : "failure"); + log_h->info("propagate results %s\n", is_success() ? "success" : "failure"); return {}; }