Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:39:20

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_COBALT_MSVC_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_COBALT_MSVC_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_COBALT_MSVC_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 
0157       if (handler.completed_immediately != nullptr
0158        && *handler.completed_immediately == completed_immediately_t::initiating)
0159         //not maybe here, because we don't go through the immediate executor
0160       {
0161         *handler.completed_immediately = completed_immediately_t::yes;
0162         return std::noop_coroutine();
0163       }
0164 
0165       return ho;
0166     }
0167 
0168     constexpr void await_resume() noexcept {}
0169   };
0170 
0171   BOOST_COBALT_MSVC_NOINLINE
0172   auto final_suspend() noexcept
0173   {
0174     return final_awaitable{std::move(handler)};
0175   }
0176 };
0177 
0178 }
0179 
0180 template<typename ... Args>
0181 struct std::coroutine_traits<void, boost::cobalt::completion_handler<Args...>>
0182 {
0183   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0184 };
0185 
0186 template<typename T0, typename ... Args>
0187 struct std::coroutine_traits<void, T0, boost::cobalt::completion_handler<Args...>>
0188 {
0189   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0190 };
0191 
0192 template<typename T0, typename T1, typename ... Args>
0193 struct std::coroutine_traits<void, T0, T1, boost::cobalt::completion_handler<Args...>>
0194 {
0195   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0196 };
0197 
0198 
0199 template<typename T0, typename T1, typename T2, typename ... Args>
0200 struct std::coroutine_traits<void, T0, T1, T2, boost::cobalt::completion_handler<Args...>>
0201 {
0202   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0203 };
0204 
0205 
0206 template<typename T0, typename T1, typename T2, typename T3, typename ... Args>
0207 struct std::coroutine_traits<void, T0, T1, T2, T3, boost::cobalt::completion_handler<Args...>>
0208 {
0209   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0210 };
0211 
0212 
0213 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename ... Args>
0214 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, boost::cobalt::completion_handler<Args...>>
0215 {
0216   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0217 };
0218 
0219 
0220 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename ... Args>
0221 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, boost::cobalt::completion_handler<Args...>>
0222 {
0223   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0224 };
0225 
0226 
0227 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename ... Args>
0228 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, T6, boost::cobalt::completion_handler<Args...>>
0229 {
0230   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0231 };
0232 
0233 
0234 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename ... Args>
0235 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, T6, T7, boost::cobalt::completion_handler<Args...>>
0236 {
0237   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0238 };
0239 
0240 
0241 template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename ... Args>
0242 struct std::coroutine_traits<void, T0, T1, T2, T3, T4, T5, T6, T7, T8, boost::cobalt::completion_handler<Args...>>
0243 {
0244   using promise_type = ::boost::cobalt::detail::composition_promise<Args...>;
0245 };
0246 
0247 #endif //BOOST_COBALT_EXPERIMENTAL_COMPOSITION_HPP