From a1cf64663387a7cdb1c174bf6c87d0918f5d0c07 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 22 Nov 2020 12:06:55 +0300 Subject: [PATCH] Rename movable_function -> function & better SSO --- libs/async/include/psemek/async/executor.hpp | 4 +- .../async/include/psemek/async/threadpool.hpp | 2 - libs/util/include/psemek/util/function.hpp | 166 ++++++++++++++++++ .../include/psemek/util/movable_function.hpp | 89 ---------- .../{movable_function.cpp => function.cpp} | 2 +- 5 files changed, 169 insertions(+), 94 deletions(-) create mode 100644 libs/util/include/psemek/util/function.hpp delete mode 100644 libs/util/include/psemek/util/movable_function.hpp rename libs/util/source/{movable_function.cpp => function.cpp} (77%) diff --git a/libs/async/include/psemek/async/executor.hpp b/libs/async/include/psemek/async/executor.hpp index dbce58d8..01167acd 100644 --- a/libs/async/include/psemek/async/executor.hpp +++ b/libs/async/include/psemek/async/executor.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -135,7 +135,7 @@ namespace psemek::async struct executor { - using task = util::movable_function; + using task = util::function; using clock = std::chrono::high_resolution_clock; // Post the task for execution. Where and when will diff --git a/libs/async/include/psemek/async/threadpool.hpp b/libs/async/include/psemek/async/threadpool.hpp index aa8211da..23419c81 100644 --- a/libs/async/include/psemek/async/threadpool.hpp +++ b/libs/async/include/psemek/async/threadpool.hpp @@ -1,10 +1,8 @@ #pragma once #include - #include #include -#include #include #include diff --git a/libs/util/include/psemek/util/function.hpp b/libs/util/include/psemek/util/function.hpp new file mode 100644 index 00000000..666f0539 --- /dev/null +++ b/libs/util/include/psemek/util/function.hpp @@ -0,0 +1,166 @@ +#pragma once + +#include +#include + +namespace psemek::util +{ + + namespace detail + { + + // Implemented in cpp to prevent dependency on + [[noreturn]] void bad_function_call(); + + } + + template + struct function; + + template + struct function + { + using signature = R(Args...); + + function() noexcept = default; + + template + function(F && f); + + function (function &&) noexcept; + function & operator = (function &&) noexcept; + + function (function const &) = delete; + function & operator = (function const &) = delete; + + template + function & operator = (F && f); + + explicit operator bool() const + { + return static_cast(vtable_); + } + + template + R operator()(Args1 && ... args) const; + + void reset(); + + private: + static constexpr std::size_t storage_size = sizeof(void*) * 3; + static constexpr std::size_t storage_align = alignof(void*); + + std::aligned_storage_t storage_; + + struct vtable + { + using move_func = void(*)(void *, void *); + using destroy_func = void(*)(void *); + using call_func = R(*)(void *, Args ...); + + move_func move; + destroy_func destroy; + call_func call; + }; + + vtable * vtable_ = nullptr; + + template + void assign(F && f); + }; + + template + template + function::function(F && f) + { + assign(std::forward(f)); + } + + template + template + function & function::operator = (F && f) + { + reset(); + assign(std::forward(f)); + return *this; + } + + template + function::function (function && other) noexcept + { + vtable_ = other.vtable_; + vtable_->move(&other.storage_, &storage_); + other.reset(); + } + + template + function & function::operator = (function && other) noexcept + { + if (this == &other) + return *this; + + vtable_ = other.vtable_; + vtable_->move(&other.storage_, &storage_); + other.reset(); + return *this; + } + + template + template + R function::operator()(Args1 && ... args) const + { + if (!vtable_) + detail::bad_function_call(); + + return vtable_->call(const_cast(static_cast(&storage_)), std::forward(args)...); + } + + template + void function::reset() + { + if (!vtable_) return; + + vtable_->destroy(&storage_); + vtable_ = nullptr; + } + + template + template + void function::assign(F && f) + { + using T = std::decay_t; + + constexpr bool static_storage = true + && sizeof(T) <= storage_size + && alignof(T) <= storage_align + && ((storage_align % alignof(T)) == 0) + && std::is_nothrow_move_constructible_v + ; + + if constexpr (static_storage) + { + new (reinterpret_cast(&storage_)) T(std::move(f)); + + static vtable m = { + [](void * src, void * dst){ new (reinterpret_cast(dst)) T(std::move(*reinterpret_cast(src))); }, + [](void * src){ reinterpret_cast(src)->~T(); }, + [](void * src, Args ... args) -> R { return (*reinterpret_cast(src))(static_cast(args)...); } + }; + + vtable_ = &m; + } + else + { + *reinterpret_cast(&storage_) = new T(std::move(f)); + + static vtable m = { + [](void * src, void * dst){ *reinterpret_cast(dst) = *reinterpret_cast(src); *reinterpret_cast(src) = nullptr; }, + [](void * src){ delete *reinterpret_cast(src); }, + [](void * src, Args ... args) -> R { return (**reinterpret_cast(src))(static_cast(args)...); } + }; + + vtable_ = &m; + } + } + +} diff --git a/libs/util/include/psemek/util/movable_function.hpp b/libs/util/include/psemek/util/movable_function.hpp deleted file mode 100644 index 6bdc4a5c..00000000 --- a/libs/util/include/psemek/util/movable_function.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include - -#include - -namespace psemek::util -{ - - namespace detail - { - - template - struct movable_function_node_base; - - template - struct movable_function_node_base - { - virtual R call(Args ...) = 0; - - virtual ~movable_function_node_base() = default; - }; - - template - struct movable_function_node; - - template - struct movable_function_node - : movable_function_node_base - { - F f; - - movable_function_node(F && f) - : f(std::move(f)) - {} - - R call(Args ... args) override - { - return f(args...); - } - }; - - // Implemented in cpp to prevent dependency on - [[noreturn]] void bad_function_call(); - - } - - template - struct movable_function; - - template - struct movable_function - { - using signature = R(Args...); - - movable_function() noexcept = default; - - template - movable_function(F f) - { - storage_.template emplace>>(std::move(f)); - } - - movable_function (movable_function &&) noexcept = default; - movable_function & operator = (movable_function &&) noexcept = default; - - movable_function (movable_function const &) = delete; - movable_function & operator = (movable_function const &) = delete; - - explicit operator bool() const - { - return static_cast(storage_); - } - - template - R operator()(Args1 && ... args) const - { - if (!storage_) - detail::bad_function_call(); - - return storage_.get()->call(std::forward(args)...); - } - - private: - static constexpr std::size_t small_storage_size = sizeof(void*) * 3; - polymorhpic_storage, small_storage_size> storage_; - }; - -} diff --git a/libs/util/source/movable_function.cpp b/libs/util/source/function.cpp similarity index 77% rename from libs/util/source/movable_function.cpp rename to libs/util/source/function.cpp index 26fb51e5..b2c513fb 100644 --- a/libs/util/source/movable_function.cpp +++ b/libs/util/source/function.cpp @@ -1,4 +1,4 @@ -#include +#include #include