Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 08:06:38

0001 //
0002 // experimental/detail/coro_promise_allocator.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2021-2023 Klemens D. Morgenstern
0006 //                         (klemens dot morgenstern at gmx dot net)
0007 //
0008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 //
0011 
0012 #ifndef BOOST_ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP
0013 #define BOOST_ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP
0014 
0015 #include <boost/asio/detail/config.hpp>
0016 #include <boost/asio/experimental/coro_traits.hpp>
0017 
0018 namespace boost {
0019 namespace asio {
0020 namespace experimental {
0021 namespace detail {
0022 
0023 /// Allocate the memory and put the allocator behind the coro memory
0024 template <typename AllocatorType>
0025 void* allocate_coroutine(const std::size_t size, AllocatorType alloc_)
0026 {
0027   using alloc_type = typename std::allocator_traits<AllocatorType>::template
0028     rebind_alloc<unsigned char>;
0029   alloc_type alloc{alloc_};
0030 
0031   const auto align_needed = size % alignof(alloc_type);
0032   const auto align_offset = align_needed != 0
0033     ? alignof(alloc_type) - align_needed : 0ull;
0034   const auto alloc_size = size + sizeof(alloc_type) + align_offset;
0035   const auto raw =
0036     std::allocator_traits<alloc_type>::allocate(alloc, alloc_size);
0037   new(raw + size + align_offset) alloc_type(std::move(alloc));
0038 
0039   return raw;
0040 }
0041 
0042 /// Deallocate the memory and destroy the allocator in the coro memory.
0043 template <typename AllocatorType>
0044 void deallocate_coroutine(void* raw_, const std::size_t size)
0045 {
0046   using alloc_type = typename std::allocator_traits<AllocatorType>::template
0047     rebind_alloc<unsigned char>;
0048 
0049   const auto raw = static_cast<unsigned char *>(raw_);
0050 
0051   const auto align_needed = size % alignof(alloc_type);
0052   const auto align_offset = align_needed != 0
0053     ? alignof(alloc_type) - align_needed : 0ull;
0054   const auto alloc_size = size + sizeof(alloc_type) + align_offset;
0055 
0056   auto alloc_p = reinterpret_cast<alloc_type *>(raw + size + align_offset);
0057   auto alloc = std::move(*alloc_p);
0058   alloc_p->~alloc_type();
0059   std::allocator_traits<alloc_type>::deallocate(alloc, raw, alloc_size);
0060 }
0061 
0062 template <typename T>
0063 constexpr std::size_t variadic_first(std::size_t = 0u)
0064 {
0065   return std::numeric_limits<std::size_t>::max();
0066 }
0067 
0068 template <typename T, typename First, typename... Args>
0069 constexpr std::size_t variadic_first(std::size_t pos = 0u)
0070 {
0071   if constexpr (std::is_same_v<std::decay_t<First>, T>)
0072     return pos;
0073   else
0074     return variadic_first<T, Args...>(pos+1);
0075 }
0076 
0077 template <std::size_t Idx, typename First, typename... Args>
0078   requires (Idx <= sizeof...(Args))
0079 constexpr decltype(auto) get_variadic(First&& first, Args&&... args)
0080 {
0081   if constexpr (Idx == 0u)
0082     return static_cast<First>(first);
0083   else
0084     return get_variadic<Idx-1u>(static_cast<Args>(args)...);
0085 }
0086 
0087 template <std::size_t Idx>
0088 constexpr decltype(auto) get_variadic();
0089 
0090 template <typename Allocator>
0091 struct coro_promise_allocator
0092 {
0093   using allocator_type = Allocator;
0094   allocator_type get_allocator() const {return alloc_;}
0095 
0096   template <typename... Args>
0097   void* operator new(std::size_t size, Args & ... args)
0098   {
0099     return allocate_coroutine(size,
0100         get_variadic<variadic_first<std::allocator_arg_t,
0101           std::decay_t<Args>...>() + 1u>(args...));
0102   }
0103 
0104   void operator delete(void* raw, std::size_t size)
0105   {
0106     deallocate_coroutine<allocator_type>(raw, size);
0107   }
0108 
0109   template <typename... Args>
0110   coro_promise_allocator(Args&& ... args)
0111     : alloc_(
0112         get_variadic<variadic_first<std::allocator_arg_t,
0113           std::decay_t<Args>...>() + 1u>(args...))
0114   {
0115   }
0116 
0117 private:
0118   allocator_type alloc_;
0119 };
0120 
0121 template <>
0122 struct coro_promise_allocator<std::allocator<void>>
0123 {
0124   using allocator_type = std::allocator<void>;
0125 
0126   template <typename... Args>
0127   coro_promise_allocator(Args&&...)
0128   {
0129   }
0130 
0131   allocator_type get_allocator() const
0132   {
0133     return {};
0134   }
0135 };
0136 
0137 } // namespace detail
0138 } // namespace experimental
0139 } // namespace asio
0140 } // namespace boost
0141 
0142 #endif // BOOST_ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP