File indexing completed on 2025-12-16 09:44:26
0001
0002
0003
0004
0005
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
0143 constexpr use_op_t()
0144 {
0145 }
0146
0147
0148
0149 template <typename InnerExecutor>
0150 struct executor_with_default : InnerExecutor
0151 {
0152
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
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
0175
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
0181
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