diff options
Diffstat (limited to '3rdparty/asio/include/asio/experimental/impl/promise.hpp')
-rw-r--r-- | 3rdparty/asio/include/asio/experimental/impl/promise.hpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/3rdparty/asio/include/asio/experimental/impl/promise.hpp b/3rdparty/asio/include/asio/experimental/impl/promise.hpp new file mode 100644 index 00000000000..a80cf110baa --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/promise.hpp @@ -0,0 +1,255 @@ +// +// 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 ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP +#define ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/cancellation_signal.hpp" +#include "asio/detail/utility.hpp" +#include "asio/error.hpp" +#include "asio/system_error.hpp" +#include <tuple> + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +template<typename Signature = void(), + typename Executor = 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, 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), + 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 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 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 asio::decay<Alloc>::type, Handler>; + using alloc_t = typename std::allocator_traits< + typename 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(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( + asio::detail::make_index_sequence<sizeof...(Ts)>{}); + } + + template<typename... T_> + void cancel_impl_(std::exception_ptr*, T_*...) + { + complete( + std::make_exception_ptr( + asio::system_error( + asio::error::operation_aborted)), + T_{}...); + } + + template<typename... T_> + void cancel_impl_(asio::error_code*, T_*...) + { + complete(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 = 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 + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_PROMISE_HPP |