diff --git a/lib/include/srslte/common/move_callback.h b/lib/include/srslte/common/move_callback.h index 03f3faa1b..70dcd153e 100644 --- a/lib/include/srslte/common/move_callback.h +++ b/lib/include/srslte/common/move_callback.h @@ -35,83 +35,68 @@ class move_callback; namespace task_details { -//! Class used to type-erase the functor/lambda capture move/call/dtor operators template -struct oper_table_t { - using call_oper_t = R (*)(void* src, Args&&... args); - using move_oper_t = void (*)(void* src, void* dest); - using dtor_oper_t = void (*)(void* src); +class oper_table_t +{ +public: + constexpr oper_table_t(bool in_buffer_) : is_in_buffer(in_buffer_) {} + virtual R call(void* src, Args&&... args) const = 0; + virtual void move(void* src, void* dest) const = 0; + virtual void dtor(void* src) const = 0; + bool is_in_buffer; +}; - //! Returns a operator table for when the move_function object is empty - const static oper_table_t* get_empty() noexcept - { - const static oper_table_t t{true, - [](void* src, Args&&... args) -> R { throw std::bad_function_call(); }, - [](void*, void*) {}, - [](void*) {}}; - return &t; - } +template +class empty_table_t : public oper_table_t +{ +public: + constexpr empty_table_t() : oper_table_t(true) {} + R call(void* src, Args&&... args) const final { throw std::bad_function_call(); } + void move(void* src, void* dest) const final {} + void dtor(void* src) const final {} +}; - //! Returns a operator table for when the move_function fits the small buffer - template - const static oper_table_t* get_small() noexcept +template +class smallbuffer_table_t : public oper_table_t +{ +public: + constexpr smallbuffer_table_t() : oper_table_t(true) {} + R call(void* src, Args&&... args) const final { return (*static_cast(src))(std::forward(args)...); } + void move(void* src, void* dest) const final { - const static oper_table_t t{ - true, - [](void* src, Args&&... args) -> R { return (*static_cast(src))(std::forward(args)...); }, - [](void* src, void* dest) -> void { - ::new (dest) Func{std::move(*static_cast(src))}; - static_cast(src)->~Func(); - }, - [](void* src) -> void { static_cast(src)->~Func(); }}; - return &t; + ::new (dest) FunT{std::move(*static_cast(src))}; + static_cast(src)->~FunT(); } + void dtor(void* src) const final { static_cast(src)->~FunT(); } +}; - //! Returns a operator table for when the move_function fits the big buffer - template - const static oper_table_t* get_big() noexcept +template +class heap_table_t : public oper_table_t +{ +public: + constexpr heap_table_t() : oper_table_t(false) {} + R call(void* src, Args&&... args) const final { return (**static_cast(src))(std::forward(args)...); } + void move(void* src, void* dest) const final { - const static oper_table_t t{ - false, - [](void* src, Args&&... args) -> R { return (**static_cast(src))(std::forward(args)...); }, - [](void* src, void* dest) -> void { - *static_cast(dest) = *static_cast(src); - *static_cast(src) = nullptr; - }, - [](void* src) -> void { delete (*static_cast(src)); }}; - return &t; + *static_cast(dest) = *static_cast(src); + *static_cast(src) = nullptr; } - - oper_table_t(const oper_table_t&) = delete; - oper_table_t(oper_table_t&&) = delete; - oper_table_t& operator=(const oper_table_t&) = delete; - oper_table_t& operator=(oper_table_t&&) = delete; - ~oper_table_t() = default; - - const bool is_in_buffer; - const call_oper_t call; - const move_oper_t move; - const dtor_oper_t dtor; - -private: - oper_table_t(bool is_in_buffer_, call_oper_t call_, move_oper_t move_, dtor_oper_t dtor_) : - is_in_buffer(is_in_buffer_), - call(call_), - move(move_), - dtor(dtor_) - {} + void dtor(void* src) const final { delete (*static_cast(src)); } }; +//! Metafunction to check if object is move_callback<> type template -struct is_inplace_task : std::false_type {}; +struct is_move_callback : std::false_type {}; template -struct is_inplace_task > : std::true_type {}; +struct is_move_callback > : std::true_type {}; +//! metafunctions to enable/disable functions based on whether the callback fits small buffer or not template ::type> -using enable_small_capture = - typename std::enable_if::value, bool>::type; +using enable_if_small_capture = + typename std::enable_if::value, bool>::type; template ::type> -using enable_big_capture = typename std::enable_if < Cap::value, bool>::type; +using enable_if_big_capture = + typename std::enable_if < Cap::value, bool>::type; } // namespace task_details @@ -121,30 +106,32 @@ class move_callback static constexpr size_t capacity = Capacity >= sizeof(void*) ? Capacity : sizeof(void*); using storage_t = typename std::aligned_storage::type; using oper_table_t = task_details::oper_table_t; + static constexpr task_details::empty_table_t empty_table{}; public: - move_callback() noexcept { oper_ptr = oper_table_t::get_empty(); } + move_callback() noexcept : oper_ptr(&empty_table) {} - template = true> + template = true> move_callback(T&& function) noexcept { using FunT = typename std::decay::type; - oper_ptr = oper_table_t::template get_small(); + static const task_details::smallbuffer_table_t small_oper_table{}; + oper_ptr = &small_oper_table; ::new (&buffer) FunT{std::forward(function)}; } - template = true> + template = true> move_callback(T&& function) { using FunT = typename std::decay::type; - oper_ptr = oper_table_t::template get_big(); - ptr = static_cast(new FunT{std::forward(function)}); + static const task_details::heap_table_t heap_oper_table{}; + oper_ptr = &heap_oper_table; + ptr = static_cast(new FunT{std::forward(function)}); } - move_callback(move_callback&& other) noexcept + move_callback(move_callback&& other) noexcept : oper_ptr(other.oper_ptr) { - oper_ptr = other.oper_ptr; - other.oper_ptr = oper_table_t::get_empty(); + other.oper_ptr = &empty_table; oper_ptr->move(&other.buffer, &buffer); } @@ -154,14 +141,14 @@ public: { oper_ptr->dtor(&buffer); oper_ptr = other.oper_ptr; - other.oper_ptr = oper_table_t::get_empty(); + other.oper_ptr = &empty_table; oper_ptr->move(&other.buffer, &buffer); return *this; } R operator()(Args&&... args) const noexcept { return oper_ptr->call(&buffer, std::forward(args)...); } - bool is_empty() const { return oper_ptr == oper_table_t::get_empty(); } + bool is_empty() const { return oper_ptr == empty_table; } bool is_in_small_buffer() const { return oper_ptr->is_in_buffer; } void swap(move_callback& other) noexcept @@ -198,6 +185,9 @@ private: const oper_table_t* oper_ptr; }; +template +constexpr task_details::empty_table_t move_callback::empty_table; + } // namespace srslte #endif // SRSLTE_MOVE_CALLBACK_H diff --git a/lib/test/common/queue_test.cc b/lib/test/common/queue_test.cc index b126ad8e1..189540689 100644 --- a/lib/test/common/queue_test.cc +++ b/lib/test/common/queue_test.cc @@ -339,9 +339,10 @@ int test_inplace_task() srslte::move_callback t{l0}; srslte::move_callback t2{[v]() mutable { v = 2; }}; // sanity static checks - static_assert(task_details::is_inplace_task::type>::value, "failed check\n"); - static_assert(std::is_base_of::type> >::value, - "failed check\n"); + static_assert(task_details::is_move_callback::type>::value, "failed check\n"); + static_assert( + std::is_base_of::type> >::value, + "failed check\n"); t(); t2();