Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:24:42

0001 //
0002 // Copyright (c) 2024 Klemens Morgenstern (klemens.morgenstern@gmx.net)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_COBALT_EXPERIMENTAL_COMPOSITION_HPP
0009 #define BOOST_COBALT_EXPERIMENTAL_COMPOSITION_HPP
0010 
0011 #include <boost/cobalt/op.hpp>
0012 #include <boost/cobalt/detail/sbo_resource.hpp>
0013 
0014 
0015 namespace boost::cobalt::detail
0016 {
0017 
0018 template<typename ... Args>
0019 struct composition_promise
0020     :
0021       promise_cancellation_base<asio::cancellation_slot, asio::enable_total_cancellation>,
0022       enable_await_allocator<composition_promise<Args...>>,
0023       enable_await_executor<composition_promise<Args...>>
0024 {
0025   void get_return_object() {}
0026 
0027   using promise_cancellation_base<asio::cancellation_slot, asio::enable_total_cancellation>::await_transform;
0028   using enable_await_allocator<composition_promise<Args...>>::await_transform;
0029   using enable_await_executor<composition_promise<Args...>>::await_transform;
0030 
0031   using handler_type = completion_handler<Args...>;
0032 
0033   using allocator_type = typename handler_type::allocator_type;
0034   allocator_type get_allocator() const {return handler.get_allocator();}
0035 #if !defined(BOOST_COBALT_NO_PMR)
0036   using resource_type = pmr::memory_resource;
0037 #else
0038   using resource_type = cobalt::detail::sbo_resource;
0039 #endif
0040 
0041   template<typename ... Args_, typename Initiation, typename ... InitArgs>
0042   BOOST_NOINLINE
0043   auto await_transform(asio::deferred_async_operation<void(Args_...), Initiation, InitArgs...> op_)
0044   {
0045     struct deferred_op : op<Args_...>
0046     {
0047       asio::deferred_async_operation<void(Args_...), Initiation, InitArgs...> op_;
0048       deferred_op(asio::deferred_async_operation<void(Args_...), Initiation, InitArgs...> op_,
0049                   resource_type * resource)
0050           : op_(std::move(op_)), resource(resource) {}
0051 
0052       void initiate(cobalt::completion_handler<Args_...> complete) override
0053       {
0054         std::move(op_)(std::move(complete));
0055       }
0056 
0057       resource_type * resource;
0058 
0059       typename op<Args_...>::awaitable_base operator co_await()
0060       {
0061         return static_cast<op<Args_...>&&>(*this).operator co_await().replace_resource(this->resource);
0062       }
0063     };
0064 
0065     return cobalt::as_tuple(deferred_op{std::move(op_), handler.get_allocator().resource()});
0066   }
0067 
0068   template<typename Op>
0069     requires requires (Op && op, resource_type* res)
0070     {
0071       {static_cast<Op>(op).operator co_await().replace_resource(res)} -> awaitable_type<composition_promise>;
0072     }
0073   BOOST_NOINLINE
0074   auto await_transform(Op && op_)
0075   {
0076     struct replacing_op
0077     {
0078       Op op;
0079 
0080       resource_type * resource;
0081 
0082       auto operator co_await()
0083       {
0084         return std::forward<Op>(op).operator co_await().replace_resource(this->resource);
0085       }
0086     };
0087 
0088     return cobalt::as_tuple(replacing_op{std::forward<Op>(op_), handler.get_allocator().resource()});
0089   }
0090 
0091 
0092   using executor_type = typename handler_type::executor_type ;
0093   const executor & get_executor() const {return handler.get_executor();}
0094 
0095   template<typename ... Ts>
0096   static void * operator new(const std::size_t size, Ts & ... args)
0097   {
0098     using tt = std::pair<resource_type *, std::size_t>;
0099 
0100     // | memory_resource | size_t | <padding> | coroutine.
0101     constexpr auto block_size =  sizeof(tt) / sizeof(std::max_align_t)
0102                                  + (sizeof(tt) % sizeof(std::max_align_t) ? 1 : 0);
0103 
0104 
0105     auto res = std::get<sizeof... (Ts) - 1>(std::tie(args...)).get_allocator().resource();
0106     const auto p = res->allocate(size + (block_size * sizeof(std::max_align_t)));
0107     new (p) tt(res, size);
0108     return static_cast<std::max_align_t*>(p) + block_size;
0109   }
0110 
0111   static void operator delete(void * raw) noexcept
0112   {
0113     using tt = std::pair<resource_type *, std::size_t>;
0114 
0115     // | memory_resource | size_t | <padding> | coroutine.
0116     constexpr auto block_size =  sizeof(tt) / sizeof(std::max_align_t)
0117                                  + (sizeof(tt) % sizeof(std::max_align_t) ? 1 : 0);
0118 
0119     const auto p = static_cast<std::max_align_t*>(raw) - block_size;
0120 
0121     const auto tp = *reinterpret_cast<tt*>(p);
0122     const auto res = tp.first;
0123     const auto size = tp.second;
0124 
0125     res->deallocate(p, size +  (block_size * sizeof(std::max_align_t)));
0126   }
0127 
0128   completion_handler<Args...> handler;
0129 
0130   template<typename ... Ts>
0131   composition_promise(Ts && ... args) : handler(std::move(std::get<sizeof... (Ts) - 1>(std::tie(args...))))
0132   {
0133 
0134   }
0135 
0136   void unhandled_exception() { throw ; }
0137   constexpr static std::suspend_never initial_suspend() {return {};}
0138 
0139   void return_value(std::tuple<Args ...> args)
0140   {
0141     handler.result.emplace(std::move(args));
0142   }
0143 
0144 
0145   struct final_awaitable
0146   {
0147     constexpr bool await_ready() noexcept  {return false;}
0148     completion_handler<Args...> handler;
0149 
0150     BOOST_NOINLINE
0151     std::coroutine_handle<void> await_suspend(std::coroutine_handle<composition_promise> h) noexcept
0152     {
0153       auto exec = handler.get_executor();
0154       auto ho = handler.self.release();
0155       detail::self_destroy(h, exec);
0156       return ho;
0157     }
0158 
0159     constexpr void await_resume() noexcept {}
0160   };
0161 
0162   BOOST_NOINLINE
0163   auto final_suspend() noexcept
0164   {
0165     return final_awaitable{std::move(handler)};
0166   }
0167 };
0168 
0169 }
0170 
0171 template<typename ... Args>
0172 struct std::coroutine_traits<void, boost::cobalt::completion_handler<Args...>>
0173 {
0174   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0175 };
0176 
0177 template<typename T0, typename ... Args>
0178 struct std::coroutine_traits<void, T0, boost::cobalt::completion_handler<Args...>>
0179 {
0180   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0181 };
0182 
0183 template<typename T0, typename T1, typename ... Args>
0184 struct std::coroutine_traits<void, T0, T1, boost::cobalt::completion_handler<Args...>>
0185 {
0186   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0187 };
0188 
0189 
0190 template<typename T0, typename T1, typename T2, typename ... Args>
0191 struct std::coroutine_traits<void, T0, T1, T2, boost::cobalt::completion_handler<Args...>>
0192 {
0193   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0194 };
0195 
0196 
0197 template<typename T0, typename T1, typename T2, typename T3, typename ... Args>
0198 struct std::coroutine_traits<void, T0, T1, T2, T3, boost::cobalt::completion_handler<Args...>>
0199 {
0200   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0201 };
0202 
0203 
0204 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename ... Args>
0205 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, boost::cobalt::completion_handler<Args...>>
0206 {
0207   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0208 };
0209 
0210 
0211 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename ... Args>
0212 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, boost::cobalt::completion_handler<Args...>>
0213 {
0214   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0215 };
0216 
0217 
0218 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename ... Args>
0219 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, T6, boost::cobalt::completion_handler<Args...>>
0220 {
0221   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0222 };
0223 
0224 
0225 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename ... Args>
0226 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, T6, T7, boost::cobalt::completion_handler<Args...>>
0227 {
0228   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0229 };
0230 
0231 
0232 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename ... Args>
0233 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, T6, T7, T8, boost::cobalt::completion_handler<Args...>>
0234 {
0235   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0236 };
0237 
0238 #endif //BOOST_COBALT_EXPERIMENTAL_COMPOSITION_HPP