Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:44:26

0001 //
0002 // Copyright (c) 2022 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_OP_HPP
0009 #define BOOST_COBALT_OP_HPP
0010 
0011 #include <boost/cobalt/detail/handler.hpp>
0012 #include <boost/cobalt/detail/sbo_resource.hpp>
0013 #include <boost/cobalt/result.hpp>
0014 #include <boost/core/no_exceptions_support.hpp>
0015 
0016 #include <boost/asio/deferred.hpp>
0017 
0018 
0019 namespace boost::cobalt
0020 {
0021 
0022 
0023 template<typename ... Args>
0024 struct op
0025 {
0026   virtual void ready(cobalt::handler<Args...>) {};
0027   virtual void initiate(cobalt::completion_handler<Args...> complete) = 0 ;
0028   virtual ~op() = default;
0029 
0030   struct awaitable_base
0031   {
0032     op<Args...> &op_;
0033     std::optional<std::tuple<Args...>> result;
0034 
0035 #if !defined(BOOST_COBALT_NO_PMR)
0036     using resource_type = pmr::memory_resource;
0037 #else
0038     using resource_type = detail::sbo_resource;
0039 #endif
0040 
0041     awaitable_base(op<Args...> * op_, resource_type *resource) : op_(*op_), resource(resource) {}
0042     awaitable_base(awaitable_base && lhs) noexcept = default;
0043 
0044 #if defined(_MSC_VER)
0045     BOOST_NOINLINE ~awaitable_base() {}
0046 #endif
0047 
0048     bool await_ready()
0049     {
0050       op_.ready(handler<Args...>(result));
0051       return result.has_value();
0052     }
0053 
0054     detail::completed_immediately_t completed_immediately = detail::completed_immediately_t::no;
0055     std::exception_ptr init_ep;
0056 
0057     resource_type *resource;
0058 
0059     template<typename Promise>
0060     bool await_suspend(std::coroutine_handle<Promise> h
0061 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0062                      , const boost::source_location & loc = BOOST_CURRENT_LOCATION
0063 #endif
0064     ) noexcept
0065     {
0066       BOOST_TRY
0067       {
0068         completed_immediately = detail::completed_immediately_t::initiating;
0069 
0070 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0071         op_.initiate(completion_handler<Args...>{h, result, resource, &completed_immediately, loc});
0072 #else
0073         op_.initiate(completion_handler<Args...>{h, result, resource, &completed_immediately});
0074 #endif
0075         if (completed_immediately == detail::completed_immediately_t::initiating)
0076           completed_immediately = detail::completed_immediately_t::no;
0077         return completed_immediately != detail::completed_immediately_t::yes;
0078       }
0079       BOOST_CATCH(...)
0080       {
0081         init_ep = std::current_exception();
0082         return false;
0083       }
0084       BOOST_CATCH_END
0085     }
0086 
0087     auto await_resume(const boost::source_location & loc = BOOST_CURRENT_LOCATION)
0088     {
0089       if (init_ep)
0090         std::rethrow_exception(init_ep);
0091       return await_resume(as_result_tag{}).value(loc);
0092     }
0093 
0094 #if defined(_MSC_VER)
0095     BOOST_NOINLINE
0096 #endif
0097     auto await_resume(const struct as_tuple_tag &)
0098     {
0099       if (init_ep)
0100         std::rethrow_exception(init_ep);
0101       return *std::move(result);
0102     }
0103 
0104 #if defined(_MSC_VER)
0105     BOOST_NOINLINE
0106 #endif
0107     auto await_resume(const struct as_result_tag &)
0108     {
0109       if (init_ep)
0110         std::rethrow_exception(init_ep);
0111       return interpret_as_result(*std::move(result));
0112     }
0113   };
0114 
0115   struct awaitable : awaitable_base
0116   {
0117     char buffer[BOOST_COBALT_SBO_BUFFER_SIZE];
0118     detail::sbo_resource resource{buffer, sizeof(buffer)};
0119 
0120     awaitable(op<Args...> * op_) : awaitable_base(op_, &resource) {}
0121     awaitable(awaitable && rhs) : awaitable_base(std::move(rhs))
0122     {
0123       this->awaitable_base::resource = &resource;
0124     }
0125 
0126     awaitable_base replace_resource(typename awaitable_base::resource_type * resource) &&
0127     {
0128       awaitable_base nw = std::move(*this);
0129       nw.resource = resource;
0130       return nw;
0131     }
0132   };
0133 
0134   awaitable operator co_await() &&
0135   {
0136     return awaitable{this};
0137   }
0138 };
0139 
0140 struct use_op_t
0141 {
0142   /// Default constructor.
0143   constexpr use_op_t()
0144   {
0145   }
0146 
0147   /// Adapts an executor to add the @c use_op_t completion token as the
0148   /// default.
0149   template <typename InnerExecutor>
0150   struct executor_with_default : InnerExecutor
0151   {
0152     /// Specify @c use_op_t as the default completion token type.
0153     typedef use_op_t default_completion_token_type;
0154 
0155     executor_with_default(const InnerExecutor& ex) noexcept
0156         : InnerExecutor(ex)
0157     {
0158     }
0159 
0160     /// Construct the adapted executor from the inner executor type.
0161     template <typename InnerExecutor1>
0162     executor_with_default(const InnerExecutor1& ex,
0163                           typename std::enable_if<
0164                               std::conditional<
0165                               !std::is_same<InnerExecutor1, executor_with_default>::value,
0166                                   std::is_convertible<InnerExecutor1, InnerExecutor>,
0167                           std::false_type
0168           >::type::value>::type = 0) noexcept
0169       : InnerExecutor(ex)
0170     {
0171     }
0172   };
0173 
0174   /// Type alias to adapt an I/O object to use @c use_op_t as its
0175   /// default completion token type.
0176   template <typename T>
0177   using as_default_on_t = typename T::template rebind_executor<
0178         executor_with_default<typename T::executor_type> >::other;
0179 
0180   /// Function helper to adapt an I/O object to use @c use_op_t as its
0181   /// default completion token type.
0182   template <typename T>
0183   static typename std::decay_t<T>::template rebind_executor<
0184       executor_with_default<typename std::decay_t<T>::executor_type>
0185     >::other
0186   as_default_on(T && object)
0187   {
0188     return typename std::decay_t<T>::template rebind_executor<
0189         executor_with_default<typename std::decay_t<T>::executor_type>
0190       >::other(std::forward<T>(object));
0191   }
0192 
0193 };
0194 
0195 constexpr use_op_t use_op{};
0196 
0197 struct enable_await_deferred
0198 {
0199   template<typename ... Args, typename Initiation, typename ... InitArgs>
0200   auto await_transform(asio::deferred_async_operation<void(Args...), Initiation, InitArgs...> op_)
0201   {
0202     struct deferred_op : op<Args...>
0203     {
0204       asio::deferred_async_operation<void(Args...), Initiation, InitArgs...> op_;
0205       deferred_op(asio::deferred_async_operation<void(Args...), Initiation, InitArgs...> op_)
0206           : op_(std::move(op_)) {}
0207 
0208       void initiate(cobalt::completion_handler<Args...> complete) override
0209       {
0210         std::move(op_)(std::move(complete));
0211       }
0212     };
0213 
0214     return deferred_op{std::move(op_)};
0215   }
0216 };
0217 
0218 }
0219 
0220 namespace boost::asio
0221 {
0222 
0223 template<typename ... Args>
0224 struct async_result<boost::cobalt::use_op_t, void(Args...)>
0225 {
0226   using return_type = boost::cobalt::op<Args...>;
0227 
0228   template <typename Initiation, typename... InitArgs>
0229   struct op_impl final : boost::cobalt::op<Args...>
0230   {
0231     Initiation initiation;
0232     std::tuple<InitArgs...> args;
0233     template<typename Initiation_, typename ...InitArgs_>
0234     op_impl(Initiation_ initiation,
0235             InitArgs_   && ... args)
0236             : initiation(std::forward<Initiation_>(initiation))
0237             , args(std::forward<InitArgs_>(args)...) {}
0238 
0239     void initiate(cobalt::completion_handler<Args...> complete) final override
0240     {
0241       std::apply(
0242           [&](InitArgs && ... args)
0243           {
0244             std::move(initiation)(std::move(complete),
0245                                   std::move(args)...);
0246           }, std::move(args));
0247     }
0248   };
0249 
0250   template <typename Initiation, typename... InitArgs>
0251   static auto initiate(Initiation && initiation,
0252                        boost::cobalt::use_op_t,
0253                        InitArgs &&... args)
0254       -> op_impl<std::decay_t<Initiation>, std::decay_t<InitArgs>...>
0255   {
0256     return op_impl<std::decay_t<Initiation>, std::decay_t<InitArgs>...>(
0257         std::forward<Initiation>(initiation),
0258         std::forward<InitArgs>(args)...);
0259   }
0260 };
0261 
0262 
0263 
0264 }
0265 #endif //BOOST_COBALT_OP_HPP