123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- //
- // experimental/impl/promise.hpp
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- //
- // Copyright (c) 2021-2023 Klemens D. Morgenstern
- // (klemens dot morgenstern at gmx dot net)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- #ifndef BOOST_ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP
- #define BOOST_ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- # pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include <boost/asio/detail/config.hpp>
- #include <boost/asio/cancellation_signal.hpp>
- #include <boost/asio/detail/utility.hpp>
- #include <boost/asio/error.hpp>
- #include <boost/system/system_error.hpp>
- #include <tuple>
- #include <boost/asio/detail/push_options.hpp>
- namespace boost {
- namespace asio {
- namespace experimental {
- template<typename Signature = void(),
- typename Executor = boost::asio::any_io_executor,
- typename Allocator = std::allocator<void>>
- struct promise;
- namespace detail {
- template<typename Signature, typename Executor, typename Allocator>
- struct promise_impl;
- template<typename... Ts, typename Executor, typename Allocator>
- struct promise_impl<void(Ts...), Executor, Allocator>
- {
- using result_type = std::tuple<Ts...>;
- promise_impl(Allocator allocator, Executor executor)
- : allocator(std::move(allocator)), executor(std::move(executor))
- {
- }
- promise_impl(const promise_impl&) = delete;
- ~promise_impl()
- {
- if (completion)
- this->cancel_();
- if (done)
- reinterpret_cast<result_type*>(&result)->~result_type();
- }
- aligned_storage_t<sizeof(result_type), alignof(result_type)> result;
- std::atomic<bool> done{false};
- cancellation_signal cancel;
- Allocator allocator;
- Executor executor;
- template<typename Func, std::size_t... Idx>
- void apply_impl(Func f, boost::asio::detail::index_sequence<Idx...>)
- {
- auto& result_type = *reinterpret_cast<promise_impl::result_type*>(&result);
- f(std::get<Idx>(std::move(result_type))...);
- }
- using allocator_type = Allocator;
- allocator_type get_allocator() {return allocator;}
- using executor_type = Executor;
- executor_type get_executor() {return executor;}
- template<typename Func>
- void apply(Func f)
- {
- apply_impl(std::forward<Func>(f),
- boost::asio::detail::make_index_sequence<sizeof...(Ts)>{});
- }
- struct completion_base
- {
- virtual void invoke(Ts&&...ts) = 0;
- };
- template<typename Alloc, typename WaitHandler_>
- struct completion_impl final : completion_base
- {
- WaitHandler_ handler;
- Alloc allocator;
- void invoke(Ts&&... ts)
- {
- auto h = std::move(handler);
- using alloc_t = typename std::allocator_traits<
- typename boost::asio::decay<Alloc>::type>::template
- rebind_alloc<completion_impl>;
- alloc_t alloc_{allocator};
- this->~completion_impl();
- std::allocator_traits<alloc_t>::deallocate(alloc_, this, 1u);
- std::move(h)(std::forward<Ts>(ts)...);
- }
- template<typename Alloc_, typename Handler_>
- completion_impl(Alloc_&& alloc, Handler_&& wh)
- : handler(std::forward<Handler_>(wh)),
- allocator(std::forward<Alloc_>(alloc))
- {
- }
- };
- completion_base* completion = nullptr;
- typename boost::asio::aligned_storage<sizeof(void*) * 4,
- alignof(completion_base)>::type completion_opt;
- template<typename Alloc, typename Handler>
- void set_completion(Alloc&& alloc, Handler&& handler)
- {
- if (completion)
- cancel_();
- using impl_t = completion_impl<
- typename boost::asio::decay<Alloc>::type, Handler>;
- using alloc_t = typename std::allocator_traits<
- typename boost::asio::decay<Alloc>::type>::template rebind_alloc<impl_t>;
- alloc_t alloc_{alloc};
- auto p = std::allocator_traits<alloc_t>::allocate(alloc_, 1u);
- completion = new (p) impl_t(std::forward<Alloc>(alloc),
- std::forward<Handler>(handler));
- }
- template<typename... T_>
- void complete(T_&&... ts)
- {
- assert(completion);
- std::exchange(completion, nullptr)->invoke(std::forward<T_>(ts)...);
- }
- template<std::size_t... Idx>
- void complete_with_result_impl(boost::asio::detail::index_sequence<Idx...>)
- {
- auto& result_type = *reinterpret_cast<promise_impl::result_type*>(&result);
- this->complete(std::get<Idx>(std::move(result_type))...);
- }
- void complete_with_result()
- {
- complete_with_result_impl(
- boost::asio::detail::make_index_sequence<sizeof...(Ts)>{});
- }
- template<typename... T_>
- void cancel_impl_(std::exception_ptr*, T_*...)
- {
- complete(
- std::make_exception_ptr(
- boost::system::system_error(
- boost::asio::error::operation_aborted)),
- T_{}...);
- }
- template<typename... T_>
- void cancel_impl_(boost::system::error_code*, T_*...)
- {
- complete(boost::asio::error::operation_aborted, T_{}...);
- }
- template<typename... T_>
- void cancel_impl_(T_*...)
- {
- complete(T_{}...);
- }
- void cancel_()
- {
- cancel_impl_(static_cast<Ts*>(nullptr)...);
- }
- };
- template<typename Signature = void(),
- typename Executor = boost::asio::any_io_executor,
- typename Allocator = any_io_executor>
- struct promise_handler;
- template<typename... Ts, typename Executor, typename Allocator>
- struct promise_handler<void(Ts...), Executor, Allocator>
- {
- using promise_type = promise<void(Ts...), Executor, Allocator>;
- promise_handler(
- Allocator allocator, Executor executor) // get_associated_allocator(exec)
- : impl_(
- std::allocate_shared<promise_impl<void(Ts...), Executor, Allocator>>(
- allocator, allocator, executor))
- {
- }
- std::shared_ptr<promise_impl<void(Ts...), Executor, Allocator>> impl_;
- using cancellation_slot_type = cancellation_slot;
- cancellation_slot_type get_cancellation_slot() const noexcept
- {
- return impl_->cancel.slot();
- }
- using allocator_type = Allocator;
- allocator_type get_allocator() const noexcept
- {
- return impl_->get_allocator();
- }
- using executor_type = Executor;
- Executor get_executor() const noexcept
- {
- return impl_->get_executor();
- }
- auto make_promise() -> promise<void(Ts...), executor_type, allocator_type>
- {
- return promise<void(Ts...), executor_type, allocator_type>{impl_};
- }
- void operator()(std::remove_reference_t<Ts>... ts)
- {
- assert(impl_);
- using result_type = typename promise_impl<
- void(Ts...), allocator_type, executor_type>::result_type ;
- new (&impl_->result) result_type(std::move(ts)...);
- impl_->done = true;
- if (impl_->completion)
- impl_->complete_with_result();
- }
- };
- } // namespace detail
- } // namespace experimental
- } // namespace asio
- } // namespace boost
- #include <boost/asio/detail/pop_options.hpp>
- #endif // BOOST_ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP
|