#ifndef GNR_FORWARDER_HPP # define GNR_FORWARDER_HPP # pragma once // std::size_t #include #include #include #include namespace gnr { namespace detail::forwarder { enum : std::size_t { default_size = 4 * sizeof(void*) }; template class forwarder_impl2; template class forwarder_impl2 { protected: R (*stub_)(void const*, A...) noexcept(E) {}; std::aligned_storage_t store_; template static constexpr auto is_invocable() noexcept { return std::is_invocable_r_v; } public: using result_type = R; public: template R operator()(B&& ...b) const noexcept(E) { //assert(stub_); return stub_(std::addressof(store_), std::forward(b)...); } template > > void assign(F&& f) noexcept(noexcept(std::decay_t(std::forward(f)))) { using functor_type = std::decay_t; static_assert(sizeof(functor_type) <= sizeof(store_), "functor too large"); static_assert(std::is_trivially_copyable{}, "functor not trivially copyable"); ::new (std::addressof(store_)) functor_type(std::forward(f)); stub_ = [](void const* const ptr, A... a) noexcept(E) -> R { return std::invoke( *static_cast(const_cast(ptr)), std::forward(a)...); }; } }; template class forwarder_impl; template class forwarder_impl : public forwarder_impl2 { }; template class forwarder_impl : public forwarder_impl2 { }; } template class forwarder : public detail::forwarder::forwarder_impl { using inherited_t = detail::forwarder::forwarder_impl; public: enum : std::size_t { size = N }; forwarder() = default; forwarder(forwarder const&) = default; forwarder(forwarder&&) = default; template , forwarder> && inherited_t::template is_invocable() > > forwarder(F&& f) noexcept(noexcept(inherited_t::assign(std::forward(f)))) { inherited_t::assign(std::forward(f)); } forwarder& operator=(forwarder const&) = default; forwarder& operator=(forwarder&&) = default; template , forwarder> && inherited_t::template is_invocable() > > forwarder& operator=(F&& f) noexcept( noexcept(inherited_t::assign(std::forward(f)))) { static_assert(inherited_t::template is_invocable()); return inherited_t::assign(std::forward(f)), *this; } auto& operator=(std::nullptr_t) noexcept { return reset(), *this; } explicit operator bool() const noexcept { return inherited_t::stub_; } bool operator==(std::nullptr_t) noexcept { return *this; } bool operator!=(std::nullptr_t) noexcept { return !operator==(nullptr); } void assign(std::nullptr_t) noexcept { reset(); } void reset() noexcept { inherited_t::stub_ = {}; } void swap(forwarder& other) noexcept { std::swap(*this, other); } void swap(forwarder&& other) noexcept { std::swap(*this, std::move(other)); } template auto target() noexcept { return reinterpret_cast(std::addressof(inherited_t::store_)); } template auto target() const noexcept { return reinterpret_cast(std::addressof(inherited_t::store_)); } }; } #endif // GNR_FORWARDER_HPP