// // experimental/detail/coro_promise_allocator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2021-2023 Klemens D. Morgenstern // (klemens dot morgenstern at gmx dot net) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP #define ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP #include "asio/detail/config.hpp" #include "asio/experimental/coro_traits.hpp" namespace asio { namespace experimental { namespace detail { /// Allocate the memory and put the allocator behind the coro memory template void* allocate_coroutine(const std::size_t size, AllocatorType alloc_) { using alloc_type = typename std::allocator_traits::template rebind_alloc; alloc_type alloc{alloc_}; const auto align_needed = size % alignof(alloc_type); const auto align_offset = align_needed != 0 ? alignof(alloc_type) - align_needed : 0ull; const auto alloc_size = size + sizeof(alloc_type) + align_offset; const auto raw = std::allocator_traits::allocate(alloc, alloc_size); new(raw + size + align_offset) alloc_type(std::move(alloc)); return raw; } /// Deallocate the memory and destroy the allocator in the coro memory. template void deallocate_coroutine(void* raw_, const std::size_t size) { using alloc_type = typename std::allocator_traits::template rebind_alloc; const auto raw = static_cast(raw_); const auto align_needed = size % alignof(alloc_type); const auto align_offset = align_needed != 0 ? alignof(alloc_type) - align_needed : 0ull; const auto alloc_size = size + sizeof(alloc_type) + align_offset; auto alloc_p = reinterpret_cast(raw + size + align_offset); auto alloc = std::move(*alloc_p); alloc_p->~alloc_type(); std::allocator_traits::deallocate(alloc, raw, alloc_size); } template constexpr std::size_t variadic_first(std::size_t = 0u) { return std::numeric_limits::max(); } template constexpr std::size_t variadic_first(std::size_t pos = 0u) { if constexpr (std::is_same_v, T>) return pos; else return variadic_first(pos+1); } template requires (Idx <= sizeof...(Args)) constexpr decltype(auto) get_variadic(First&& first, Args&&... args) { if constexpr (Idx == 0u) return static_cast(first); else return get_variadic(static_cast(args)...); } template constexpr decltype(auto) get_variadic(); template struct coro_promise_allocator { using allocator_type = Allocator; allocator_type get_allocator() const {return alloc_;} template void* operator new(const std::size_t size, Args & ... args) { return allocate_coroutine(size, get_variadic...>() + 1u>(args...)); } void operator delete(void* raw, const std::size_t size) { deallocate_coroutine(raw, size); } template coro_promise_allocator(Args&& ... args) : alloc_( get_variadic...>() + 1u>(args...)) { } private: allocator_type alloc_; }; template <> struct coro_promise_allocator> { using allocator_type = std::allocator; template coro_promise_allocator(Args&&...) { } allocator_type get_allocator() const { return {}; } }; } // namespace detail } // namespace experimental } // namespace asio #endif // ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP