diff --git a/headers/meta.hpp/meta_base.hpp b/headers/meta.hpp/meta_base.hpp index 55fad54..a52f0df 100644 --- a/headers/meta.hpp/meta_base.hpp +++ b/headers/meta.hpp/meta_base.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/headers/meta.hpp/meta_base/fixed_function.hpp b/headers/meta.hpp/meta_base/fixed_function.hpp index 6f61d3b..e891b0f 100644 --- a/headers/meta.hpp/meta_base/fixed_function.hpp +++ b/headers/meta.hpp/meta_base/fixed_function.hpp @@ -9,16 +9,17 @@ #include #include #include +#include #include #include namespace meta_hpp::detail { - template < typename Function, std::size_t MaxFunctorSize = sizeof(void*) * 2 > + template < typename Function > class fixed_function; - template < typename R, typename... Args, std::size_t MaxFunctorSize > - class fixed_function final { + template < typename R, typename... Args > + class fixed_function final { public: using result_type = R; @@ -78,59 +79,62 @@ namespace meta_hpp::detail struct vtable_t; vtable_t* vtable_{}; private: - using storage_t = std::aligned_storage_t; - storage_t storage_{}; + struct buffer_t final { + // NOLINTNEXTLINE(*-avoid-c-arrays) + alignas(std::max_align_t) std::byte data[sizeof(void*) * 2]; + } buffer_{}; }; - template < typename Function, std::size_t MaxFunctorSize > - inline void swap(fixed_function& l, fixed_function& r) noexcept { + template < typename Function > + inline void swap(fixed_function& l, fixed_function& r) noexcept { l.swap(r); } } namespace meta_hpp::detail { - template < typename R, typename... Args, std::size_t MaxFunctorSize > - struct fixed_function::vtable_t final { + template < typename R, typename... Args > + struct fixed_function::vtable_t final { R (*const call)(const fixed_function& self, Args... args); void (*const move)(fixed_function& from, fixed_function& to) noexcept; void (*const destroy)(fixed_function& self); template < typename T > - static T* storage_cast(storage_t& storage) noexcept { + static T* buffer_cast(buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&storage); + return std::launder(reinterpret_cast(buffer.data)); } template < typename T > - static const T* storage_cast(const storage_t& storage) noexcept { + static const T* buffer_cast(const buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&storage); + return std::launder(reinterpret_cast(buffer.data)); } - template < typename FunctionType > + template < typename Fp > static vtable_t* get() { static vtable_t table{ .call = +[](const fixed_function& self, Args... args) -> R { assert(self); - const FunctionType& src = *storage_cast(self.storage_); + const Fp& src = *buffer_cast(self.buffer_); return std::invoke(src, std::forward(args)...); }, .move = +[](fixed_function& from, fixed_function& to) noexcept { assert(from && !to); - FunctionType& src = *storage_cast(from.storage_); - ::new (&to.storage_) FunctionType(std::move(src)); + Fp& src = *buffer_cast(from.buffer_); + ::new (buffer_cast(to.buffer_)) Fp(std::move(src)); + src.~Fp(); to.vtable_ = from.vtable_; - from.vtable_->destroy(from); + from.vtable_ = nullptr; }, .destroy = +[](fixed_function& self){ assert(self); - FunctionType& src = *storage_cast(self.storage_); - src.~FunctionType(); + Fp& src = *buffer_cast(self.buffer_); + src.~Fp(); self.vtable_ = nullptr; }, @@ -142,12 +146,13 @@ namespace meta_hpp::detail static void construct(fixed_function& dst, Functor&& functor) { using Fp = std::decay_t; - static_assert(sizeof(Fp) <= MaxFunctorSize); - static_assert(alignof(Fp) <= alignof(storage_t)); + static_assert(sizeof(Fp) <= sizeof(buffer_t)); + static_assert(alignof(Fp) <= alignof(buffer_t)); static_assert(std::is_invocable_r_v); static_assert(std::is_nothrow_move_constructible_v); - ::new (&dst.storage_) Fp(std::forward(functor)); + ::new (buffer_cast(dst.buffer_)) Fp(std::forward(functor)); + dst.vtable_ = vtable_t::get(); } diff --git a/headers/meta.hpp/meta_uvalue.hpp b/headers/meta.hpp/meta_uvalue.hpp index b43bb6e..f30766f 100644 --- a/headers/meta.hpp/meta_uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue.hpp @@ -86,7 +86,10 @@ namespace meta_hpp struct vtable_t; vtable_t* vtable_{}; private: - using buffer_t = std::aligned_storage_t; + struct buffer_t final { + // NOLINTNEXTLINE(*-avoid-c-arrays) + alignas(std::max_align_t) std::byte data[sizeof(void*) * 2]; + }; using storage_u = std::variant; storage_u storage_{}; }; diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index a2c7b9a..cdc8832 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -41,13 +41,13 @@ namespace meta_hpp template < typename T > static T* buffer_cast(buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&buffer); + return std::launder(reinterpret_cast(buffer.data)); } template < typename T > static const T* buffer_cast(const buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&buffer); + return std::launder(reinterpret_cast(buffer.data)); } template < typename T > @@ -78,8 +78,7 @@ namespace meta_hpp std::is_nothrow_move_constructible_v; if constexpr ( in_buffer ) { - dst.storage_.emplace(); - ::new (storage_cast(dst.storage_)) Tp(std::forward(val)); + ::new (buffer_cast(dst.storage_.emplace())) Tp(std::forward(val)); } else { dst.storage_.emplace(std::make_unique(std::forward(val)).release()); } @@ -137,7 +136,7 @@ namespace meta_hpp }, [&to](buffer_t& buffer) { Tp& src = *buffer_cast(buffer); - ::new (&to.storage_.emplace()) Tp(std::move(src)); + ::new (buffer_cast(to.storage_.emplace())) Tp(std::move(src)); src.~Tp(); }, [](...){} @@ -153,11 +152,11 @@ namespace meta_hpp std::visit(detail::overloaded { [&to](void* ptr) { const Tp& src = *static_cast(ptr); - to.storage_.emplace(new Tp(src)); + to.storage_.emplace(std::make_unique(src).release()); }, [&to](const buffer_t& buffer) { const Tp& src = *buffer_cast(buffer); - ::new (&to.storage_.emplace()) Tp(src); + ::new (buffer_cast(to.storage_.emplace())) Tp(src); }, [](...){} }, from.storage_); diff --git a/singles/headers/meta.hpp/meta_all.hpp b/singles/headers/meta.hpp/meta_all.hpp index 921c424..9a5a090 100644 --- a/singles/headers/meta.hpp/meta_all.hpp +++ b/singles/headers/meta.hpp/meta_all.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -223,11 +224,11 @@ namespace meta_hpp::detail namespace meta_hpp::detail { - template < typename Function, std::size_t MaxFunctorSize = sizeof(void*) * 2 > + template < typename Function > class fixed_function; - template < typename R, typename... Args, std::size_t MaxFunctorSize > - class fixed_function final { + template < typename R, typename... Args > + class fixed_function final { public: using result_type = R; @@ -287,59 +288,62 @@ namespace meta_hpp::detail struct vtable_t; vtable_t* vtable_{}; private: - using storage_t = std::aligned_storage_t; - storage_t storage_{}; + struct buffer_t final { + // NOLINTNEXTLINE(*-avoid-c-arrays) + alignas(std::max_align_t) std::byte data[sizeof(void*) * 2]; + } buffer_{}; }; - template < typename Function, std::size_t MaxFunctorSize > - inline void swap(fixed_function& l, fixed_function& r) noexcept { + template < typename Function > + inline void swap(fixed_function& l, fixed_function& r) noexcept { l.swap(r); } } namespace meta_hpp::detail { - template < typename R, typename... Args, std::size_t MaxFunctorSize > - struct fixed_function::vtable_t final { + template < typename R, typename... Args > + struct fixed_function::vtable_t final { R (*const call)(const fixed_function& self, Args... args); void (*const move)(fixed_function& from, fixed_function& to) noexcept; void (*const destroy)(fixed_function& self); template < typename T > - static T* storage_cast(storage_t& storage) noexcept { + static T* buffer_cast(buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&storage); + return std::launder(reinterpret_cast(buffer.data)); } template < typename T > - static const T* storage_cast(const storage_t& storage) noexcept { + static const T* buffer_cast(const buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&storage); + return std::launder(reinterpret_cast(buffer.data)); } - template < typename FunctionType > + template < typename Fp > static vtable_t* get() { static vtable_t table{ .call = +[](const fixed_function& self, Args... args) -> R { assert(self); - const FunctionType& src = *storage_cast(self.storage_); + const Fp& src = *buffer_cast(self.buffer_); return std::invoke(src, std::forward(args)...); }, .move = +[](fixed_function& from, fixed_function& to) noexcept { assert(from && !to); - FunctionType& src = *storage_cast(from.storage_); - ::new (&to.storage_) FunctionType(std::move(src)); + Fp& src = *buffer_cast(from.buffer_); + ::new (buffer_cast(to.buffer_)) Fp(std::move(src)); + src.~Fp(); to.vtable_ = from.vtable_; - from.vtable_->destroy(from); + from.vtable_ = nullptr; }, .destroy = +[](fixed_function& self){ assert(self); - FunctionType& src = *storage_cast(self.storage_); - src.~FunctionType(); + Fp& src = *buffer_cast(self.buffer_); + src.~Fp(); self.vtable_ = nullptr; }, @@ -351,12 +355,13 @@ namespace meta_hpp::detail static void construct(fixed_function& dst, Functor&& functor) { using Fp = std::decay_t; - static_assert(sizeof(Fp) <= MaxFunctorSize); - static_assert(alignof(Fp) <= alignof(storage_t)); + static_assert(sizeof(Fp) <= sizeof(buffer_t)); + static_assert(alignof(Fp) <= alignof(buffer_t)); static_assert(std::is_invocable_r_v); static_assert(std::is_nothrow_move_constructible_v); - ::new (&dst.storage_) Fp(std::forward(functor)); + ::new (buffer_cast(dst.buffer_)) Fp(std::forward(functor)); + dst.vtable_ = vtable_t::get(); } @@ -2235,7 +2240,10 @@ namespace meta_hpp struct vtable_t; vtable_t* vtable_{}; private: - using buffer_t = std::aligned_storage_t; + struct buffer_t final { + // NOLINTNEXTLINE(*-avoid-c-arrays) + alignas(std::max_align_t) std::byte data[sizeof(void*) * 2]; + }; using storage_u = std::variant; storage_u storage_{}; }; @@ -7968,13 +7976,13 @@ namespace meta_hpp template < typename T > static T* buffer_cast(buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&buffer); + return std::launder(reinterpret_cast(buffer.data)); } template < typename T > static const T* buffer_cast(const buffer_t& buffer) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return reinterpret_cast(&buffer); + return std::launder(reinterpret_cast(buffer.data)); } template < typename T > @@ -8005,8 +8013,7 @@ namespace meta_hpp std::is_nothrow_move_constructible_v; if constexpr ( in_buffer ) { - dst.storage_.emplace(); - ::new (storage_cast(dst.storage_)) Tp(std::forward(val)); + ::new (buffer_cast(dst.storage_.emplace())) Tp(std::forward(val)); } else { dst.storage_.emplace(std::make_unique(std::forward(val)).release()); } @@ -8064,7 +8071,7 @@ namespace meta_hpp }, [&to](buffer_t& buffer) { Tp& src = *buffer_cast(buffer); - ::new (&to.storage_.emplace()) Tp(std::move(src)); + ::new (buffer_cast(to.storage_.emplace())) Tp(std::move(src)); src.~Tp(); }, [](...){} @@ -8080,11 +8087,11 @@ namespace meta_hpp std::visit(detail::overloaded { [&to](void* ptr) { const Tp& src = *static_cast(ptr); - to.storage_.emplace(new Tp(src)); + to.storage_.emplace(std::make_unique(src).release()); }, [&to](const buffer_t& buffer) { const Tp& src = *buffer_cast(buffer); - ::new (&to.storage_.emplace()) Tp(src); + ::new (buffer_cast(to.storage_.emplace())) Tp(src); }, [](...){} }, from.storage_);