File indexing completed on 2025-12-15 09:43:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP
0012 #define BOOST_ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/cancellation_signal.hpp>
0020 #include <boost/asio/detail/utility.hpp>
0021 #include <boost/asio/error.hpp>
0022 #include <boost/system/system_error.hpp>
0023 #include <tuple>
0024
0025 #include <boost/asio/detail/push_options.hpp>
0026
0027 namespace boost {
0028 namespace asio {
0029 namespace experimental {
0030
0031 template<typename Signature = void(),
0032 typename Executor = boost::asio::any_io_executor,
0033 typename Allocator = std::allocator<void>>
0034 struct promise;
0035
0036 namespace detail {
0037
0038 template<typename Signature, typename Executor, typename Allocator>
0039 struct promise_impl;
0040
0041 template<typename... Ts, typename Executor, typename Allocator>
0042 struct promise_impl<void(Ts...), Executor, Allocator>
0043 {
0044 using result_type = std::tuple<Ts...>;
0045
0046 promise_impl(Allocator allocator, Executor executor)
0047 : allocator(std::move(allocator)), executor(std::move(executor))
0048 {
0049 }
0050
0051 promise_impl(const promise_impl&) = delete;
0052
0053 ~promise_impl()
0054 {
0055 if (completion)
0056 this->cancel_();
0057
0058 if (done)
0059 reinterpret_cast<result_type*>(&result)->~result_type();
0060 }
0061
0062 aligned_storage_t<sizeof(result_type), alignof(result_type)> result;
0063 std::atomic<bool> done{false};
0064 cancellation_signal cancel;
0065 Allocator allocator;
0066 Executor executor;
0067
0068 template<typename Func, std::size_t... Idx>
0069 void apply_impl(Func f, boost::asio::detail::index_sequence<Idx...>)
0070 {
0071 auto& result_type = *reinterpret_cast<promise_impl::result_type*>(&result);
0072 f(std::get<Idx>(std::move(result_type))...);
0073 }
0074
0075 using allocator_type = Allocator;
0076 allocator_type get_allocator() {return allocator;}
0077
0078 using executor_type = Executor;
0079 executor_type get_executor() {return executor;}
0080
0081 template<typename Func>
0082 void apply(Func f)
0083 {
0084 apply_impl(std::forward<Func>(f),
0085 boost::asio::detail::make_index_sequence<sizeof...(Ts)>{});
0086 }
0087
0088 struct completion_base
0089 {
0090 virtual void invoke(Ts&&...ts) = 0;
0091 };
0092
0093 template<typename Alloc, typename WaitHandler_>
0094 struct completion_impl final : completion_base
0095 {
0096 WaitHandler_ handler;
0097 Alloc allocator;
0098 void invoke(Ts&&... ts)
0099 {
0100 auto h = std::move(handler);
0101
0102 using alloc_t = typename std::allocator_traits<
0103 typename boost::asio::decay<Alloc>::type>::template
0104 rebind_alloc<completion_impl>;
0105
0106 alloc_t alloc_{allocator};
0107 this->~completion_impl();
0108 std::allocator_traits<alloc_t>::deallocate(alloc_, this, 1u);
0109 std::move(h)(std::forward<Ts>(ts)...);
0110 }
0111
0112 template<typename Alloc_, typename Handler_>
0113 completion_impl(Alloc_&& alloc, Handler_&& wh)
0114 : handler(std::forward<Handler_>(wh)),
0115 allocator(std::forward<Alloc_>(alloc))
0116 {
0117 }
0118 };
0119
0120 completion_base* completion = nullptr;
0121 typename boost::asio::aligned_storage<sizeof(void*) * 4,
0122 alignof(completion_base)>::type completion_opt;
0123
0124 template<typename Alloc, typename Handler>
0125 void set_completion(Alloc&& alloc, Handler&& handler)
0126 {
0127 if (completion)
0128 cancel_();
0129
0130 using impl_t = completion_impl<
0131 typename boost::asio::decay<Alloc>::type, Handler>;
0132 using alloc_t = typename std::allocator_traits<
0133 typename boost::asio::decay<Alloc>::type>::template rebind_alloc<impl_t>;
0134
0135 alloc_t alloc_{alloc};
0136 auto p = std::allocator_traits<alloc_t>::allocate(alloc_, 1u);
0137 completion = new (p) impl_t(std::forward<Alloc>(alloc),
0138 std::forward<Handler>(handler));
0139 }
0140
0141 template<typename... T_>
0142 void complete(T_&&... ts)
0143 {
0144 assert(completion);
0145 std::exchange(completion, nullptr)->invoke(std::forward<T_>(ts)...);
0146 }
0147
0148 template<std::size_t... Idx>
0149 void complete_with_result_impl(boost::asio::detail::index_sequence<Idx...>)
0150 {
0151 auto& result_type = *reinterpret_cast<promise_impl::result_type*>(&result);
0152 this->complete(std::get<Idx>(std::move(result_type))...);
0153 }
0154
0155 void complete_with_result()
0156 {
0157 complete_with_result_impl(
0158 boost::asio::detail::make_index_sequence<sizeof...(Ts)>{});
0159 }
0160
0161 template<typename... T_>
0162 void cancel_impl_(std::exception_ptr*, T_*...)
0163 {
0164 complete(
0165 std::make_exception_ptr(
0166 boost::system::system_error(
0167 boost::asio::error::operation_aborted)),
0168 T_{}...);
0169 }
0170
0171 template<typename... T_>
0172 void cancel_impl_(boost::system::error_code*, T_*...)
0173 {
0174 complete(boost::asio::error::operation_aborted, T_{}...);
0175 }
0176
0177 template<typename... T_>
0178 void cancel_impl_(T_*...)
0179 {
0180 complete(T_{}...);
0181 }
0182
0183 void cancel_()
0184 {
0185 cancel_impl_(static_cast<Ts*>(nullptr)...);
0186 }
0187 };
0188
0189 template<typename Signature = void(),
0190 typename Executor = boost::asio::any_io_executor,
0191 typename Allocator = std::allocator<void>>
0192 struct promise_handler;
0193
0194 template<typename... Ts, typename Executor, typename Allocator>
0195 struct promise_handler<void(Ts...), Executor, Allocator>
0196 {
0197 using promise_type = promise<void(Ts...), Executor, Allocator>;
0198
0199 promise_handler(
0200 Allocator allocator, Executor executor)
0201 : impl_(
0202 std::allocate_shared<promise_impl<void(Ts...), Executor, Allocator>>(
0203 allocator, allocator, executor))
0204 {
0205 }
0206
0207 std::shared_ptr<promise_impl<void(Ts...), Executor, Allocator>> impl_;
0208
0209 using cancellation_slot_type = cancellation_slot;
0210
0211 cancellation_slot_type get_cancellation_slot() const noexcept
0212 {
0213 return impl_->cancel.slot();
0214 }
0215
0216 using allocator_type = Allocator;
0217
0218 allocator_type get_allocator() const noexcept
0219 {
0220 return impl_->get_allocator();
0221 }
0222
0223 using executor_type = Executor;
0224
0225 Executor get_executor() const noexcept
0226 {
0227 return impl_->get_executor();
0228 }
0229
0230 auto make_promise() -> promise<void(Ts...), executor_type, allocator_type>
0231 {
0232 return promise<void(Ts...), executor_type, allocator_type>{impl_};
0233 }
0234
0235 void operator()(std::remove_reference_t<Ts>... ts)
0236 {
0237 assert(impl_);
0238
0239 using result_type = typename promise_impl<
0240 void(Ts...), allocator_type, executor_type>::result_type ;
0241
0242 new (&impl_->result) result_type(std::move(ts)...);
0243 impl_->done = true;
0244
0245 if (impl_->completion)
0246 impl_->complete_with_result();
0247 }
0248 };
0249
0250 }
0251 }
0252 }
0253 }
0254
0255 #include <boost/asio/detail/pop_options.hpp>
0256
0257 #endif