Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 09:43:58

0001 //
0002 // experimental/impl/promise.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2021-2023 Klemens D. Morgenstern
0006 //                         (klemens dot morgenstern at gmx dot net)
0007 //
0008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // defined(_MSC_VER) && (_MSC_VER >= 1200)
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) // get_associated_allocator(exec)
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 } // namespace detail
0251 } // namespace experimental
0252 } // namespace asio
0253 } // namespace boost
0254 
0255 #include <boost/asio/detail/pop_options.hpp>
0256 
0257 #endif // BOOST_ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP