From 018f9e7db2a3c8f5561b542eef1df1dbc28983dd Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sun, 29 Mar 2020 18:28:34 +0100 Subject: [PATCH] implement visit pattern --- lib/include/srslte/common/choice_type.h | 36 ++++++-- lib/test/common/choice_type_test.cc | 118 +++++++++++++++++++----- 2 files changed, 120 insertions(+), 34 deletions(-) diff --git a/lib/include/srslte/common/choice_type.h b/lib/include/srslte/common/choice_type.h index 3a34d9ffa..db3150109 100644 --- a/lib/include/srslte/common/choice_type.h +++ b/lib/include/srslte/common/choice_type.h @@ -283,7 +283,7 @@ public: using base_t::get_if; using base_t::is; - choice_t() noexcept { this_union().construct_unsafe(); } + choice_t() noexcept { base_t::construct_unsafe(); } choice_t(const choice_t& other) noexcept { base_t::copy_unsafe(other); } @@ -325,20 +325,38 @@ public: choice_t& operator=(choice_t&& other) noexcept { base_t::dtor_unsafe(); - base_t::move_unsafe(other); + base_t::move_unsafe(std::move(other)); return *this; } + 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: - base_t& this_union() { return *this; } - const base_t& this_union() const { return *this; } }; -// template -// void visit(choice_t& u, Functor&& f) -//{ -// choice_details::visit_impl::template apply(u, f); -//} +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 diff --git a/lib/test/common/choice_type_test.cc b/lib/test/common/choice_type_test.cc index 937e98c42..880dabfba 100644 --- a/lib/test/common/choice_type_test.cc +++ b/lib/test/common/choice_type_test.cc @@ -22,26 +22,6 @@ #include "srslte/common/choice_type.h" #include "srslte/common/test_common.h" -namespace srslte { -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(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, - "type index-based search not working"); -static_assert(std::is_same::type, float>::value, - "type index-based search not working"); -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"); - struct C { static int counter; C() { counter++; } @@ -78,8 +58,32 @@ struct D { }; int D::counter = 0; +namespace srslte { +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(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, + "type index-based search not working"); +static_assert(std::is_same::type, float>::value, + "type index-based search not working"); +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"); + +} // namespace choice_details +} // namespace srslte + int test_tagged_union() { + using srslte::choice_details::tagged_union_t; tagged_union_t u; u.construct_unsafe(5); TESTASSERT(u.is()); @@ -98,6 +102,9 @@ int test_tagged_union() int test_choice() { + using srslte::choice_t; + using srslte::choice_details::bad_choice_access; + TESTASSERT(C::counter == 0); TESTASSERT(D::counter == 0); { @@ -118,7 +125,7 @@ int test_choice() char n = '1'; n = c2.get(); TESTASSERT(n == '1'); - } catch (choice_details::bad_choice_access& e) { + } catch (bad_choice_access& e) { catched = true; } TESTASSERT(catched); @@ -152,10 +159,26 @@ int test_choice() TESTASSERT(C::counter == 1); TESTASSERT(D::counter == 1); + // TEST: Move ctor choice_t c5{std::move(c3)}; TESTASSERT(C::counter == 2); choice_t c6{std::move(c4)}; TESTASSERT(D::counter == 2); + + // TEST: move assignment + c = std::move(c3); + TESTASSERT(c.is()); + TESTASSERT(c3.is() and c.holds_same_type(c3)); // move is not destructive + TESTASSERT(C::counter == 3); + c = std::move(c4); + TESTASSERT(c.is()); + TESTASSERT(c4.is() and c.holds_same_type(c4)); + TESTASSERT(C::counter == 2); + 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(C::counter == 2 and D::counter == 2); } TESTASSERT(C::counter == 0); TESTASSERT(D::counter == 0); @@ -163,11 +186,56 @@ int test_choice() return SRSLTE_SUCCESS; } -} // namespace choice_details -} // namespace srslte +struct E { + srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance()); +}; + +struct EVisitor { + template + void operator()(T&& t) + { + // do nothing + } + void operator()(E& e) { pdu = std::move(e.pdu); } + srslte::unique_byte_buffer_t pdu; +}; + +int test_visit() +{ + using srslte::choice_t; + + choice_t c{5}; + + // TEST: visitor hits integer type which is noop + EVisitor v; + srslte::visit(c, v); + TESTASSERT(c.is() and c.get() == 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(v.pdu != nullptr); + TESTASSERT(c.is() and c.get().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); + TESTASSERT(v.pdu != nullptr); + c.visit(v); + TESTASSERT(v.pdu == nullptr); + + return SRSLTE_SUCCESS; +} int main() { - TESTASSERT(srslte::choice_details::test_tagged_union() == SRSLTE_SUCCESS); - TESTASSERT(srslte::choice_details::test_choice() == SRSLTE_SUCCESS); + TESTASSERT(test_tagged_union() == SRSLTE_SUCCESS); + TESTASSERT(test_choice() == SRSLTE_SUCCESS); + TESTASSERT(test_visit() == SRSLTE_SUCCESS); }