diff options
Diffstat (limited to '3rdparty/asio/include/asio')
653 files changed, 84538 insertions, 23353 deletions
diff --git a/3rdparty/asio/include/asio/any_completion_executor.hpp b/3rdparty/asio/include/asio/any_completion_executor.hpp new file mode 100644 index 00000000000..650ff7bafdd --- /dev/null +++ b/3rdparty/asio/include/asio/any_completion_executor.hpp @@ -0,0 +1,336 @@ +// +// any_completion_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_ANY_COMPLETION_EXECUTOR_HPP +#define ASIO_ANY_COMPLETION_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/executor.hpp" +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/execution.hpp" +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +typedef executor any_completion_executor; + +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +/// Polymorphic executor type for use with I/O objects. +/** + * The @c any_completion_executor type is a polymorphic executor that supports + * the set of properties required for the execution of completion handlers. It + * is defined as the execution::any_executor class template parameterised as + * follows: + * @code execution::any_executor< + * execution::prefer_only<execution::outstanding_work_t::tracked_t>, + * execution::prefer_only<execution::outstanding_work_t::untracked_t> + * execution::prefer_only<execution::relationship_t::fork_t>, + * execution::prefer_only<execution::relationship_t::continuation_t> + * > @endcode + */ +class any_completion_executor : +#if defined(GENERATING_DOCUMENTATION) + public execution::any_executor<...> +#else // defined(GENERATING_DOCUMENTATION) + public execution::any_executor< + execution::prefer_only<execution::outstanding_work_t::tracked_t>, + execution::prefer_only<execution::outstanding_work_t::untracked_t>, + execution::prefer_only<execution::relationship_t::fork_t>, + execution::prefer_only<execution::relationship_t::continuation_t> + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +public: +#if !defined(GENERATING_DOCUMENTATION) + typedef execution::any_executor< + execution::prefer_only<execution::outstanding_work_t::tracked_t>, + execution::prefer_only<execution::outstanding_work_t::untracked_t>, + execution::prefer_only<execution::relationship_t::fork_t>, + execution::prefer_only<execution::relationship_t::continuation_t> + > base_type; + + typedef void supportable_properties_type( + execution::prefer_only<execution::outstanding_work_t::tracked_t>, + execution::prefer_only<execution::outstanding_work_t::untracked_t>, + execution::prefer_only<execution::relationship_t::fork_t>, + execution::prefer_only<execution::relationship_t::continuation_t> + ); +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Default constructor. + ASIO_DECL any_completion_executor() noexcept; + + /// Construct in an empty state. Equivalent effects to default constructor. + ASIO_DECL any_completion_executor(nullptr_t) noexcept; + + /// Copy constructor. + ASIO_DECL any_completion_executor( + const any_completion_executor& e) noexcept; + + /// Move constructor. + ASIO_DECL any_completion_executor( + any_completion_executor&& e) noexcept; + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template <class... OtherSupportableProperties> + any_completion_executor( + execution::any_executor<OtherSupportableProperties...> e); +#else // defined(GENERATING_DOCUMENTATION) + template <typename OtherAnyExecutor> + any_completion_executor(OtherAnyExecutor e, + constraint_t< + conditional< + !is_same<OtherAnyExecutor, any_completion_executor>::value + && is_base_of<execution::detail::any_executor_base, + OtherAnyExecutor>::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target<OtherAnyExecutor>, + false_type + >::type::value + > = 0) + : base_type(static_cast<OtherAnyExecutor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template <class... OtherSupportableProperties> + any_completion_executor(std::nothrow_t, + execution::any_executor<OtherSupportableProperties...> e); +#else // defined(GENERATING_DOCUMENTATION) + template <typename OtherAnyExecutor> + any_completion_executor(std::nothrow_t, OtherAnyExecutor e, + constraint_t< + conditional< + !is_same<OtherAnyExecutor, any_completion_executor>::value + && is_base_of<execution::detail::any_executor_base, + OtherAnyExecutor>::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target<OtherAnyExecutor>, + false_type + >::type::value + > = 0) noexcept + : base_type(std::nothrow, static_cast<OtherAnyExecutor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_completion_executor(std::nothrow_t, + const any_completion_executor& e) noexcept; + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_completion_executor(std::nothrow_t, + any_completion_executor&& e) noexcept; + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_completion_executor(Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_completion_executor(Executor e, + constraint_t< + conditional< + !is_same<Executor, any_completion_executor>::value + && !is_base_of<execution::detail::any_executor_base, + Executor>::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::type::value + > = 0) + : base_type(static_cast<Executor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_completion_executor(std::nothrow_t, Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_completion_executor(std::nothrow_t, Executor e, + constraint_t< + conditional< + !is_same<Executor, any_completion_executor>::value + && !is_base_of<execution::detail::any_executor_base, + Executor>::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::type::value + > = 0) noexcept + : base_type(std::nothrow, static_cast<Executor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + ASIO_DECL any_completion_executor& operator=( + const any_completion_executor& e) noexcept; + + /// Move assignment operator. + ASIO_DECL any_completion_executor& operator=( + any_completion_executor&& e) noexcept; + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + ASIO_DECL any_completion_executor& operator=(nullptr_t); + + /// Destructor. + ASIO_DECL ~any_completion_executor(); + + /// Swap targets with another polymorphic wrapper. + ASIO_DECL void swap(any_completion_executor& other) noexcept; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require and asio::prefer customisation points. + * + * For example: + * @code any_completion_executor ex = ...; + * auto ex2 = asio::require(ex, execution::relationship.fork); @endcode + */ + template <typename Property> + any_completion_executor require(const Property& p, + constraint_t< + traits::require_member<const base_type&, const Property&>::is_valid + > = 0) const + { + return static_cast<const base_type&>(*this).require(p); + } + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code any_completion_executor ex = ...; + * auto ex2 = asio::prefer(ex, execution::relationship.fork); @endcode + */ + template <typename Property> + any_completion_executor prefer(const Property& p, + constraint_t< + traits::prefer_member<const base_type&, const Property&>::is_valid + > = 0) const + { + return static_cast<const base_type&>(*this).prefer(p); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::outstanding_work_t::tracked_t&, int) const; + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::outstanding_work_t::untracked_t&, int) const; + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::relationship_t::fork_t&, int) const; + +template <> +ASIO_DECL any_completion_executor any_completion_executor::prefer( + const execution::relationship_t::continuation_t&, int) const; + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <> +struct equality_comparable<any_completion_executor> +{ + static const bool is_valid = true; + static const bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename F> +struct execute_member<any_completion_executor, F> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Prop> +struct query_member<any_completion_executor, Prop> : + query_member<any_completion_executor::base_type, Prop> +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Prop> +struct require_member<any_completion_executor, Prop> : + require_member<any_completion_executor::base_type, Prop> +{ + typedef any_completion_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template <typename Prop> +struct prefer_member<any_completion_executor, Prop> : + prefer_member<any_completion_executor::base_type, Prop> +{ + typedef any_completion_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) \ + && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/impl/any_completion_executor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + // && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#endif // ASIO_ANY_COMPLETION_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/any_completion_handler.hpp b/3rdparty/asio/include/asio/any_completion_handler.hpp new file mode 100644 index 00000000000..45b3e75fec7 --- /dev/null +++ b/3rdparty/asio/include/asio/any_completion_handler.hpp @@ -0,0 +1,822 @@ +// +// any_completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_ANY_COMPLETION_HANDLER_HPP +#define ASIO_ANY_COMPLETION_HANDLER_HPP + +#include "asio/detail/config.hpp" +#include <cstring> +#include <functional> +#include <memory> +#include <utility> +#include "asio/any_completion_executor.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_immediate_executor.hpp" +#include "asio/cancellation_state.hpp" +#include "asio/recycling_allocator.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class any_completion_handler_impl_base +{ +public: + template <typename S> + explicit any_completion_handler_impl_base(S&& slot) + : cancel_state_(static_cast<S&&>(slot), enable_total_cancellation()) + { + } + + cancellation_slot get_cancellation_slot() const noexcept + { + return cancel_state_.slot(); + } + +private: + cancellation_state cancel_state_; +}; + +template <typename Handler> +class any_completion_handler_impl : + public any_completion_handler_impl_base +{ +public: + template <typename S, typename H> + any_completion_handler_impl(S&& slot, H&& h) + : any_completion_handler_impl_base(static_cast<S&&>(slot)), + handler_(static_cast<H&&>(h)) + { + } + + struct uninit_deleter + { + typename std::allocator_traits< + associated_allocator_t<Handler, + asio::recycling_allocator<void>>>::template + rebind_alloc<any_completion_handler_impl> alloc; + + void operator()(any_completion_handler_impl* ptr) + { + std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1); + } + }; + + struct deleter + { + typename std::allocator_traits< + associated_allocator_t<Handler, + asio::recycling_allocator<void>>>::template + rebind_alloc<any_completion_handler_impl> alloc; + + void operator()(any_completion_handler_impl* ptr) + { + std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr); + std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1); + } + }; + + template <typename S, typename H> + static any_completion_handler_impl* create(S&& slot, H&& h) + { + uninit_deleter d{ + (get_associated_allocator)(h, + asio::recycling_allocator<void>())}; + + std::unique_ptr<any_completion_handler_impl, uninit_deleter> uninit_ptr( + std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d); + + any_completion_handler_impl* ptr = + new (uninit_ptr.get()) any_completion_handler_impl( + static_cast<S&&>(slot), static_cast<H&&>(h)); + + uninit_ptr.release(); + return ptr; + } + + void destroy() + { + deleter d{ + (get_associated_allocator)(handler_, + asio::recycling_allocator<void>())}; + + d(this); + } + + any_completion_executor executor( + const any_completion_executor& candidate) const noexcept + { + return any_completion_executor(std::nothrow, + (get_associated_executor)(handler_, candidate)); + } + + any_completion_executor immediate_executor( + const any_io_executor& candidate) const noexcept + { + return any_completion_executor(std::nothrow, + (get_associated_immediate_executor)(handler_, candidate)); + } + + void* allocate(std::size_t size, std::size_t align) const + { + typename std::allocator_traits< + associated_allocator_t<Handler, + asio::recycling_allocator<void>>>::template + rebind_alloc<unsigned char> alloc( + (get_associated_allocator)(handler_, + asio::recycling_allocator<void>())); + + std::size_t space = size + align - 1; + unsigned char* base = + std::allocator_traits<decltype(alloc)>::allocate( + alloc, space + sizeof(std::ptrdiff_t)); + + void* p = base; + if (detail::align(align, size, p, space)) + { + std::ptrdiff_t off = static_cast<unsigned char*>(p) - base; + std::memcpy(static_cast<unsigned char*>(p) + size, &off, sizeof(off)); + return p; + } + + std::bad_alloc ex; + asio::detail::throw_exception(ex); + return nullptr; + } + + void deallocate(void* p, std::size_t size, std::size_t align) const + { + if (p) + { + typename std::allocator_traits< + associated_allocator_t<Handler, + asio::recycling_allocator<void>>>::template + rebind_alloc<unsigned char> alloc( + (get_associated_allocator)(handler_, + asio::recycling_allocator<void>())); + + std::ptrdiff_t off; + std::memcpy(&off, static_cast<unsigned char*>(p) + size, sizeof(off)); + unsigned char* base = static_cast<unsigned char*>(p) - off; + + std::allocator_traits<decltype(alloc)>::deallocate( + alloc, base, size + align -1 + sizeof(std::ptrdiff_t)); + } + } + + template <typename... Args> + void call(Args&&... args) + { + deleter d{ + (get_associated_allocator)(handler_, + asio::recycling_allocator<void>())}; + + std::unique_ptr<any_completion_handler_impl, deleter> ptr(this, d); + Handler handler(static_cast<Handler&&>(handler_)); + ptr.reset(); + + static_cast<Handler&&>(handler)( + static_cast<Args&&>(args)...); + } + +private: + Handler handler_; +}; + +template <typename Signature> +class any_completion_handler_call_fn; + +template <typename R, typename... Args> +class any_completion_handler_call_fn<R(Args...)> +{ +public: + using type = void(*)(any_completion_handler_impl_base*, Args...); + + constexpr any_completion_handler_call_fn(type fn) + : call_fn_(fn) + { + } + + void call(any_completion_handler_impl_base* impl, Args... args) const + { + call_fn_(impl, static_cast<Args&&>(args)...); + } + + template <typename Handler> + static void impl(any_completion_handler_impl_base* impl, Args... args) + { + static_cast<any_completion_handler_impl<Handler>*>(impl)->call( + static_cast<Args&&>(args)...); + } + +private: + type call_fn_; +}; + +template <typename... Signatures> +class any_completion_handler_call_fns; + +template <typename Signature> +class any_completion_handler_call_fns<Signature> : + public any_completion_handler_call_fn<Signature> +{ +public: + using any_completion_handler_call_fn< + Signature>::any_completion_handler_call_fn; + using any_completion_handler_call_fn<Signature>::call; +}; + +template <typename Signature, typename... Signatures> +class any_completion_handler_call_fns<Signature, Signatures...> : + public any_completion_handler_call_fn<Signature>, + public any_completion_handler_call_fns<Signatures...> +{ +public: + template <typename CallFn, typename... CallFns> + constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns) + : any_completion_handler_call_fn<Signature>(fn), + any_completion_handler_call_fns<Signatures...>(fns...) + { + } + + using any_completion_handler_call_fn<Signature>::call; + using any_completion_handler_call_fns<Signatures...>::call; +}; + +class any_completion_handler_destroy_fn +{ +public: + using type = void(*)(any_completion_handler_impl_base*); + + constexpr any_completion_handler_destroy_fn(type fn) + : destroy_fn_(fn) + { + } + + void destroy(any_completion_handler_impl_base* impl) const + { + destroy_fn_(impl); + } + + template <typename Handler> + static void impl(any_completion_handler_impl_base* impl) + { + static_cast<any_completion_handler_impl<Handler>*>(impl)->destroy(); + } + +private: + type destroy_fn_; +}; + +class any_completion_handler_executor_fn +{ +public: + using type = any_completion_executor(*)( + any_completion_handler_impl_base*, const any_completion_executor&); + + constexpr any_completion_handler_executor_fn(type fn) + : executor_fn_(fn) + { + } + + any_completion_executor executor(any_completion_handler_impl_base* impl, + const any_completion_executor& candidate) const + { + return executor_fn_(impl, candidate); + } + + template <typename Handler> + static any_completion_executor impl(any_completion_handler_impl_base* impl, + const any_completion_executor& candidate) + { + return static_cast<any_completion_handler_impl<Handler>*>(impl)->executor( + candidate); + } + +private: + type executor_fn_; +}; + +class any_completion_handler_immediate_executor_fn +{ +public: + using type = any_completion_executor(*)( + any_completion_handler_impl_base*, const any_io_executor&); + + constexpr any_completion_handler_immediate_executor_fn(type fn) + : immediate_executor_fn_(fn) + { + } + + any_completion_executor immediate_executor( + any_completion_handler_impl_base* impl, + const any_io_executor& candidate) const + { + return immediate_executor_fn_(impl, candidate); + } + + template <typename Handler> + static any_completion_executor impl(any_completion_handler_impl_base* impl, + const any_io_executor& candidate) + { + return static_cast<any_completion_handler_impl<Handler>*>( + impl)->immediate_executor(candidate); + } + +private: + type immediate_executor_fn_; +}; + +class any_completion_handler_allocate_fn +{ +public: + using type = void*(*)(any_completion_handler_impl_base*, + std::size_t, std::size_t); + + constexpr any_completion_handler_allocate_fn(type fn) + : allocate_fn_(fn) + { + } + + void* allocate(any_completion_handler_impl_base* impl, + std::size_t size, std::size_t align) const + { + return allocate_fn_(impl, size, align); + } + + template <typename Handler> + static void* impl(any_completion_handler_impl_base* impl, + std::size_t size, std::size_t align) + { + return static_cast<any_completion_handler_impl<Handler>*>(impl)->allocate( + size, align); + } + +private: + type allocate_fn_; +}; + +class any_completion_handler_deallocate_fn +{ +public: + using type = void(*)(any_completion_handler_impl_base*, + void*, std::size_t, std::size_t); + + constexpr any_completion_handler_deallocate_fn(type fn) + : deallocate_fn_(fn) + { + } + + void deallocate(any_completion_handler_impl_base* impl, + void* p, std::size_t size, std::size_t align) const + { + deallocate_fn_(impl, p, size, align); + } + + template <typename Handler> + static void impl(any_completion_handler_impl_base* impl, + void* p, std::size_t size, std::size_t align) + { + static_cast<any_completion_handler_impl<Handler>*>(impl)->deallocate( + p, size, align); + } + +private: + type deallocate_fn_; +}; + +template <typename... Signatures> +class any_completion_handler_fn_table + : private any_completion_handler_destroy_fn, + private any_completion_handler_executor_fn, + private any_completion_handler_immediate_executor_fn, + private any_completion_handler_allocate_fn, + private any_completion_handler_deallocate_fn, + private any_completion_handler_call_fns<Signatures...> +{ +public: + template <typename... CallFns> + constexpr any_completion_handler_fn_table( + any_completion_handler_destroy_fn::type destroy_fn, + any_completion_handler_executor_fn::type executor_fn, + any_completion_handler_immediate_executor_fn::type immediate_executor_fn, + any_completion_handler_allocate_fn::type allocate_fn, + any_completion_handler_deallocate_fn::type deallocate_fn, + CallFns... call_fns) + : any_completion_handler_destroy_fn(destroy_fn), + any_completion_handler_executor_fn(executor_fn), + any_completion_handler_immediate_executor_fn(immediate_executor_fn), + any_completion_handler_allocate_fn(allocate_fn), + any_completion_handler_deallocate_fn(deallocate_fn), + any_completion_handler_call_fns<Signatures...>(call_fns...) + { + } + + using any_completion_handler_destroy_fn::destroy; + using any_completion_handler_executor_fn::executor; + using any_completion_handler_immediate_executor_fn::immediate_executor; + using any_completion_handler_allocate_fn::allocate; + using any_completion_handler_deallocate_fn::deallocate; + using any_completion_handler_call_fns<Signatures...>::call; +}; + +template <typename Handler, typename... Signatures> +struct any_completion_handler_fn_table_instance +{ + static constexpr any_completion_handler_fn_table<Signatures...> + value = any_completion_handler_fn_table<Signatures...>( + &any_completion_handler_destroy_fn::impl<Handler>, + &any_completion_handler_executor_fn::impl<Handler>, + &any_completion_handler_immediate_executor_fn::impl<Handler>, + &any_completion_handler_allocate_fn::impl<Handler>, + &any_completion_handler_deallocate_fn::impl<Handler>, + &any_completion_handler_call_fn<Signatures>::template impl<Handler>...); +}; + +template <typename Handler, typename... Signatures> +constexpr any_completion_handler_fn_table<Signatures...> +any_completion_handler_fn_table_instance<Handler, Signatures...>::value; + +} // namespace detail + +template <typename... Signatures> +class any_completion_handler; + +/// An allocator type that forwards memory allocation operations through an +/// instance of @c any_completion_handler. +template <typename T, typename... Signatures> +class any_completion_handler_allocator +{ +private: + template <typename...> + friend class any_completion_handler; + + template <typename, typename...> + friend class any_completion_handler_allocator; + + const detail::any_completion_handler_fn_table<Signatures...>* fn_table_; + detail::any_completion_handler_impl_base* impl_; + + constexpr any_completion_handler_allocator(int, + const any_completion_handler<Signatures...>& h) noexcept + : fn_table_(h.fn_table_), + impl_(h.impl_) + { + } + +public: + /// The type of objects that may be allocated by the allocator. + typedef T value_type; + + /// Rebinds an allocator to another value type. + template <typename U> + struct rebind + { + /// Specifies the type of the rebound allocator. + typedef any_completion_handler_allocator<U, Signatures...> other; + }; + + /// Construct from another @c any_completion_handler_allocator. + template <typename U> + constexpr any_completion_handler_allocator( + const any_completion_handler_allocator<U, Signatures...>& a) + noexcept + : fn_table_(a.fn_table_), + impl_(a.impl_) + { + } + + /// Equality operator. + constexpr bool operator==( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ == other.fn_table_ && impl_ == other.impl_; + } + + /// Inequality operator. + constexpr bool operator!=( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ != other.fn_table_ || impl_ != other.impl_; + } + + /// Allocate space for @c n objects of the allocator's value type. + T* allocate(std::size_t n) const + { + if (fn_table_) + { + return static_cast<T*>( + fn_table_->allocate( + impl_, sizeof(T) * n, alignof(T))); + } + std::bad_alloc ex; + asio::detail::throw_exception(ex); + return nullptr; + } + + /// Deallocate space for @c n objects of the allocator's value type. + void deallocate(T* p, std::size_t n) const + { + fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T)); + } +}; + +/// A protoco-allocator type that may be rebound to obtain an allocator that +/// forwards memory allocation operations through an instance of +/// @c any_completion_handler. +template <typename... Signatures> +class any_completion_handler_allocator<void, Signatures...> +{ +private: + template <typename...> + friend class any_completion_handler; + + template <typename, typename...> + friend class any_completion_handler_allocator; + + const detail::any_completion_handler_fn_table<Signatures...>* fn_table_; + detail::any_completion_handler_impl_base* impl_; + + constexpr any_completion_handler_allocator(int, + const any_completion_handler<Signatures...>& h) noexcept + : fn_table_(h.fn_table_), + impl_(h.impl_) + { + } + +public: + /// @c void as no objects can be allocated through a proto-allocator. + typedef void value_type; + + /// Rebinds an allocator to another value type. + template <typename U> + struct rebind + { + /// Specifies the type of the rebound allocator. + typedef any_completion_handler_allocator<U, Signatures...> other; + }; + + /// Construct from another @c any_completion_handler_allocator. + template <typename U> + constexpr any_completion_handler_allocator( + const any_completion_handler_allocator<U, Signatures...>& a) + noexcept + : fn_table_(a.fn_table_), + impl_(a.impl_) + { + } + + /// Equality operator. + constexpr bool operator==( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ == other.fn_table_ && impl_ == other.impl_; + } + + /// Inequality operator. + constexpr bool operator!=( + const any_completion_handler_allocator& other) const noexcept + { + return fn_table_ != other.fn_table_ || impl_ != other.impl_; + } +}; + +/// Polymorphic wrapper for completion handlers. +/** + * The @c any_completion_handler class template is a polymorphic wrapper for + * completion handlers that propagates the associated executor, associated + * allocator, and associated cancellation slot through a type-erasing interface. + * + * When using @c any_completion_handler, specify one or more completion + * signatures as template parameters. These will dictate the arguments that may + * be passed to the handler through the polymorphic interface. + * + * Typical uses for @c any_completion_handler include: + * + * @li Separate compilation of asynchronous operation implementations. + * + * @li Enabling interoperability between asynchronous operations and virtual + * functions. + */ +template <typename... Signatures> +class any_completion_handler +{ +#if !defined(GENERATING_DOCUMENTATION) +private: + template <typename, typename...> + friend class any_completion_handler_allocator; + + template <typename, typename> + friend struct associated_executor; + + template <typename, typename> + friend struct associated_immediate_executor; + + const detail::any_completion_handler_fn_table<Signatures...>* fn_table_; + detail::any_completion_handler_impl_base* impl_; +#endif // !defined(GENERATING_DOCUMENTATION) + +public: + /// The associated allocator type. + using allocator_type = any_completion_handler_allocator<void, Signatures...>; + + /// The associated cancellation slot type. + using cancellation_slot_type = cancellation_slot; + + /// Construct an @c any_completion_handler in an empty state, without a target + /// object. + constexpr any_completion_handler() + : fn_table_(nullptr), + impl_(nullptr) + { + } + + /// Construct an @c any_completion_handler in an empty state, without a target + /// object. + constexpr any_completion_handler(nullptr_t) + : fn_table_(nullptr), + impl_(nullptr) + { + } + + /// Construct an @c any_completion_handler to contain the specified target. + template <typename H, typename Handler = decay_t<H>> + any_completion_handler(H&& h, + constraint_t< + !is_same<decay_t<H>, any_completion_handler>::value + > = 0) + : fn_table_( + &detail::any_completion_handler_fn_table_instance< + Handler, Signatures...>::value), + impl_(detail::any_completion_handler_impl<Handler>::create( + (get_associated_cancellation_slot)(h), static_cast<H&&>(h))) + { + } + + /// Move-construct an @c any_completion_handler from another. + /** + * After the operation, the moved-from object @c other has no target. + */ + any_completion_handler(any_completion_handler&& other) noexcept + : fn_table_(other.fn_table_), + impl_(other.impl_) + { + other.fn_table_ = nullptr; + other.impl_ = nullptr; + } + + /// Move-assign an @c any_completion_handler from another. + /** + * After the operation, the moved-from object @c other has no target. + */ + any_completion_handler& operator=( + any_completion_handler&& other) noexcept + { + any_completion_handler( + static_cast<any_completion_handler&&>(other)).swap(*this); + return *this; + } + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + any_completion_handler& operator=(nullptr_t) noexcept + { + any_completion_handler().swap(*this); + return *this; + } + + /// Destructor. + ~any_completion_handler() + { + if (impl_) + fn_table_->destroy(impl_); + } + + /// Test if the polymorphic wrapper is empty. + constexpr explicit operator bool() const noexcept + { + return impl_ != nullptr; + } + + /// Test if the polymorphic wrapper is non-empty. + constexpr bool operator!() const noexcept + { + return impl_ == nullptr; + } + + /// Swap the content of an @c any_completion_handler with another. + void swap(any_completion_handler& other) noexcept + { + std::swap(fn_table_, other.fn_table_); + std::swap(impl_, other.impl_); + } + + /// Get the associated allocator. + allocator_type get_allocator() const noexcept + { + return allocator_type(0, *this); + } + + /// Get the associated cancellation slot. + cancellation_slot_type get_cancellation_slot() const noexcept + { + return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type(); + } + + /// Function call operator. + /** + * Invokes target completion handler with the supplied arguments. + * + * This function may only be called once, as the target handler is moved from. + * The polymorphic wrapper is left in an empty state. + * + * Throws @c std::bad_function_call if the polymorphic wrapper is empty. + */ + template <typename... Args> + auto operator()(Args&&... args) + -> decltype(fn_table_->call(impl_, static_cast<Args&&>(args)...)) + { + if (detail::any_completion_handler_impl_base* impl = impl_) + { + impl_ = nullptr; + return fn_table_->call(impl, static_cast<Args&&>(args)...); + } + std::bad_function_call ex; + asio::detail::throw_exception(ex); + } + + /// Equality operator. + friend constexpr bool operator==( + const any_completion_handler& a, nullptr_t) noexcept + { + return a.impl_ == nullptr; + } + + /// Equality operator. + friend constexpr bool operator==( + nullptr_t, const any_completion_handler& b) noexcept + { + return nullptr == b.impl_; + } + + /// Inequality operator. + friend constexpr bool operator!=( + const any_completion_handler& a, nullptr_t) noexcept + { + return a.impl_ != nullptr; + } + + /// Inequality operator. + friend constexpr bool operator!=( + nullptr_t, const any_completion_handler& b) noexcept + { + return nullptr != b.impl_; + } +}; + +template <typename... Signatures, typename Candidate> +struct associated_executor<any_completion_handler<Signatures...>, Candidate> +{ + using type = any_completion_executor; + + static type get(const any_completion_handler<Signatures...>& handler, + const Candidate& candidate = Candidate()) noexcept + { + any_completion_executor any_candidate(std::nothrow, candidate); + return handler.fn_table_ + ? handler.fn_table_->executor(handler.impl_, any_candidate) + : any_candidate; + } +}; + +template <typename... Signatures, typename Candidate> +struct associated_immediate_executor< + any_completion_handler<Signatures...>, Candidate> +{ + using type = any_completion_executor; + + static type get(const any_completion_handler<Signatures...>& handler, + const Candidate& candidate = Candidate()) noexcept + { + any_io_executor any_candidate(std::nothrow, candidate); + return handler.fn_table_ + ? handler.fn_table_->immediate_executor(handler.impl_, any_candidate) + : any_candidate; + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ANY_COMPLETION_HANDLER_HPP diff --git a/3rdparty/asio/include/asio/any_io_executor.hpp b/3rdparty/asio/include/asio/any_io_executor.hpp new file mode 100644 index 00000000000..d35acf44ae3 --- /dev/null +++ b/3rdparty/asio/include/asio/any_io_executor.hpp @@ -0,0 +1,351 @@ +// +// any_io_executor.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_ANY_IO_EXECUTOR_HPP +#define ASIO_ANY_IO_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/executor.hpp" +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/execution.hpp" +# include "asio/execution_context.hpp" +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +typedef executor any_io_executor; + +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +/// Polymorphic executor type for use with I/O objects. +/** + * The @c any_io_executor type is a polymorphic executor that supports the set + * of properties required by I/O objects. It is defined as the + * execution::any_executor class template parameterised as follows: + * @code execution::any_executor< + * execution::context_as_t<execution_context&>, + * execution::blocking_t::never_t, + * execution::prefer_only<execution::blocking_t::possibly_t>, + * execution::prefer_only<execution::outstanding_work_t::tracked_t>, + * execution::prefer_only<execution::outstanding_work_t::untracked_t>, + * execution::prefer_only<execution::relationship_t::fork_t>, + * execution::prefer_only<execution::relationship_t::continuation_t> + * > @endcode + */ +class any_io_executor : +#if defined(GENERATING_DOCUMENTATION) + public execution::any_executor<...> +#else // defined(GENERATING_DOCUMENTATION) + public execution::any_executor< + execution::context_as_t<execution_context&>, + execution::blocking_t::never_t, + execution::prefer_only<execution::blocking_t::possibly_t>, + execution::prefer_only<execution::outstanding_work_t::tracked_t>, + execution::prefer_only<execution::outstanding_work_t::untracked_t>, + execution::prefer_only<execution::relationship_t::fork_t>, + execution::prefer_only<execution::relationship_t::continuation_t> + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +public: +#if !defined(GENERATING_DOCUMENTATION) + typedef execution::any_executor< + execution::context_as_t<execution_context&>, + execution::blocking_t::never_t, + execution::prefer_only<execution::blocking_t::possibly_t>, + execution::prefer_only<execution::outstanding_work_t::tracked_t>, + execution::prefer_only<execution::outstanding_work_t::untracked_t>, + execution::prefer_only<execution::relationship_t::fork_t>, + execution::prefer_only<execution::relationship_t::continuation_t> + > base_type; + + typedef void supportable_properties_type( + execution::context_as_t<execution_context&>, + execution::blocking_t::never_t, + execution::prefer_only<execution::blocking_t::possibly_t>, + execution::prefer_only<execution::outstanding_work_t::tracked_t>, + execution::prefer_only<execution::outstanding_work_t::untracked_t>, + execution::prefer_only<execution::relationship_t::fork_t>, + execution::prefer_only<execution::relationship_t::continuation_t> + ); +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Default constructor. + ASIO_DECL any_io_executor() noexcept; + + /// Construct in an empty state. Equivalent effects to default constructor. + ASIO_DECL any_io_executor(nullptr_t) noexcept; + + /// Copy constructor. + ASIO_DECL any_io_executor(const any_io_executor& e) noexcept; + + /// Move constructor. + ASIO_DECL any_io_executor(any_io_executor&& e) noexcept; + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template <class... OtherSupportableProperties> + any_io_executor(execution::any_executor<OtherSupportableProperties...> e); +#else // defined(GENERATING_DOCUMENTATION) + template <typename OtherAnyExecutor> + any_io_executor(OtherAnyExecutor e, + constraint_t< + conditional_t< + !is_same<OtherAnyExecutor, any_io_executor>::value + && is_base_of<execution::detail::any_executor_base, + OtherAnyExecutor>::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target<OtherAnyExecutor>, + false_type + >::value + > = 0) + : base_type(static_cast<OtherAnyExecutor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. +#if defined(GENERATING_DOCUMENTATION) + template <class... OtherSupportableProperties> + any_io_executor(std::nothrow_t, + execution::any_executor<OtherSupportableProperties...> e); +#else // defined(GENERATING_DOCUMENTATION) + template <typename OtherAnyExecutor> + any_io_executor(std::nothrow_t, OtherAnyExecutor e, + constraint_t< + conditional_t< + !is_same<OtherAnyExecutor, any_io_executor>::value + && is_base_of<execution::detail::any_executor_base, + OtherAnyExecutor>::value, + typename execution::detail::supportable_properties< + 0, supportable_properties_type>::template + is_valid_target<OtherAnyExecutor>, + false_type + >::value + > = 0) noexcept + : base_type(std::nothrow, static_cast<OtherAnyExecutor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_io_executor(std::nothrow_t, + const any_io_executor& e) noexcept; + + /// Construct to point to the same target as another any_executor. + ASIO_DECL any_io_executor(std::nothrow_t, any_io_executor&& e) noexcept; + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_io_executor(Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_io_executor(Executor e, + constraint_t< + conditional_t< + !is_same<Executor, any_io_executor>::value + && !is_base_of<execution::detail::any_executor_base, + Executor>::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::value + > = 0) + : base_type(static_cast<Executor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct a polymorphic wrapper for the specified executor. +#if defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_io_executor(std::nothrow_t, Executor e); +#else // defined(GENERATING_DOCUMENTATION) + template <ASIO_EXECUTION_EXECUTOR Executor> + any_io_executor(std::nothrow_t, Executor e, + constraint_t< + conditional_t< + !is_same<Executor, any_io_executor>::value + && !is_base_of<execution::detail::any_executor_base, + Executor>::value, + execution::detail::is_valid_target_executor< + Executor, supportable_properties_type>, + false_type + >::value + > = 0) noexcept + : base_type(std::nothrow, static_cast<Executor&&>(e)) + { + } +#endif // defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + ASIO_DECL any_io_executor& operator=( + const any_io_executor& e) noexcept; + + /// Move assignment operator. + ASIO_DECL any_io_executor& operator=(any_io_executor&& e) noexcept; + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + ASIO_DECL any_io_executor& operator=(nullptr_t); + + /// Destructor. + ASIO_DECL ~any_io_executor(); + + /// Swap targets with another polymorphic wrapper. + ASIO_DECL void swap(any_io_executor& other) noexcept; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require and asio::prefer customisation points. + * + * For example: + * @code any_io_executor ex = ...; + * auto ex2 = asio::require(ex, execution::blocking.possibly); @endcode + */ + template <typename Property> + any_io_executor require(const Property& p, + constraint_t< + traits::require_member<const base_type&, const Property&>::is_valid + > = 0) const + { + return static_cast<const base_type&>(*this).require(p); + } + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code any_io_executor ex = ...; + * auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode + */ + template <typename Property> + any_io_executor prefer(const Property& p, + constraint_t< + traits::prefer_member<const base_type&, const Property&>::is_valid + > = 0) const + { + return static_cast<const base_type&>(*this).prefer(p); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) + +template <> +ASIO_DECL any_io_executor any_io_executor::require( + const execution::blocking_t::never_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::blocking_t::possibly_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::outstanding_work_t::tracked_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::outstanding_work_t::untracked_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::relationship_t::fork_t&, int) const; + +template <> +ASIO_DECL any_io_executor any_io_executor::prefer( + const execution::relationship_t::continuation_t&, int) const; + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <> +struct equality_comparable<any_io_executor> +{ + static const bool is_valid = true; + static const bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename F> +struct execute_member<any_io_executor, F> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Prop> +struct query_member<any_io_executor, Prop> : + query_member<any_io_executor::base_type, Prop> +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Prop> +struct require_member<any_io_executor, Prop> : + require_member<any_io_executor::base_type, Prop> +{ + typedef any_io_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template <typename Prop> +struct prefer_member<any_io_executor, Prop> : + prefer_member<any_io_executor::base_type, Prop> +{ + typedef any_io_executor result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) \ + && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include "asio/impl/any_io_executor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + // && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#endif // ASIO_ANY_IO_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/append.hpp b/3rdparty/asio/include/asio/append.hpp new file mode 100644 index 00000000000..04608924280 --- /dev/null +++ b/3rdparty/asio/include/asio/append.hpp @@ -0,0 +1,65 @@ +// +// append.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_APPEND_HPP +#define ASIO_APPEND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <tuple> +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Completion token type used to specify that the completion handler +/// arguments should be passed additional values after the results of the +/// operation. +template <typename CompletionToken, typename... Values> +class append_t +{ +public: + /// Constructor. + template <typename T, typename... V> + constexpr explicit append_t(T&& completion_token, V&&... values) + : token_(static_cast<T&&>(completion_token)), + values_(static_cast<V&&>(values)...) + { + } + +//private: + CompletionToken token_; + std::tuple<Values...> values_; +}; + +/// Completion token type used to specify that the completion handler +/// arguments should be passed additional values after the results of the +/// operation. +template <typename CompletionToken, typename... Values> +ASIO_NODISCARD inline constexpr +append_t<decay_t<CompletionToken>, decay_t<Values>...> +append(CompletionToken&& completion_token, Values&&... values) +{ + return append_t<decay_t<CompletionToken>, decay_t<Values>...>( + static_cast<CompletionToken&&>(completion_token), + static_cast<Values&&>(values)...); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/append.hpp" + +#endif // ASIO_APPEND_HPP diff --git a/3rdparty/asio/include/asio/as_tuple.hpp b/3rdparty/asio/include/asio/as_tuple.hpp new file mode 100644 index 00000000000..60008bda5c2 --- /dev/null +++ b/3rdparty/asio/include/asio/as_tuple.hpp @@ -0,0 +1,126 @@ +// +// as_tuple.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_AS_TUPLE_HPP +#define ASIO_AS_TUPLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// A @ref completion_token adapter used to specify that the completion handler +/// arguments should be combined into a single tuple argument. +/** + * The as_tuple_t class is used to indicate that any arguments to the + * completion handler should be combined and passed as a single tuple argument. + * The arguments are first moved into a @c std::tuple and that tuple is then + * passed to the completion handler. + */ +template <typename CompletionToken> +class as_tuple_t +{ +public: + /// Tag type used to prevent the "default" constructor from being used for + /// conversions. + struct default_constructor_tag {}; + + /// Default constructor. + /** + * This constructor is only valid if the underlying completion token is + * default constructible and move constructible. The underlying completion + * token is itself defaulted as an argument to allow it to capture a source + * location. + */ + constexpr as_tuple_t( + default_constructor_tag = default_constructor_tag(), + CompletionToken token = CompletionToken()) + : token_(static_cast<CompletionToken&&>(token)) + { + } + + /// Constructor. + template <typename T> + constexpr explicit as_tuple_t( + T&& completion_token) + : token_(static_cast<T&&>(completion_token)) + { + } + + /// Adapts an executor to add the @c as_tuple_t completion token as the + /// default. + template <typename InnerExecutor> + struct executor_with_default : InnerExecutor + { + /// Specify @c as_tuple_t as the default completion token type. + typedef as_tuple_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + template <typename InnerExecutor1> + executor_with_default(const InnerExecutor1& ex, + constraint_t< + conditional_t< + !is_same<InnerExecutor1, executor_with_default>::value, + is_convertible<InnerExecutor1, InnerExecutor>, + false_type + >::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c as_tuple_t as its + /// default completion token type. + template <typename T> + using as_default_on_t = typename T::template rebind_executor< + executor_with_default<typename T::executor_type>>::other; + + /// Function helper to adapt an I/O object to use @c as_tuple_t as its + /// default completion token type. + template <typename T> + static typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other(static_cast<T&&>(object)); + } + +//private: + CompletionToken token_; +}; + +/// Adapt a @ref completion_token to specify that the completion handler +/// arguments should be combined into a single tuple argument. +template <typename CompletionToken> +ASIO_NODISCARD inline +constexpr as_tuple_t<decay_t<CompletionToken>> +as_tuple(CompletionToken&& completion_token) +{ + return as_tuple_t<decay_t<CompletionToken>>( + static_cast<CompletionToken&&>(completion_token)); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/as_tuple.hpp" + +#endif // ASIO_AS_TUPLE_HPP diff --git a/3rdparty/asio/include/asio/associated_allocator.hpp b/3rdparty/asio/include/asio/associated_allocator.hpp index 3834b862a5c..f21ea250efb 100644 --- a/3rdparty/asio/include/asio/associated_allocator.hpp +++ b/3rdparty/asio/include/asio/associated_allocator.hpp @@ -2,7 +2,7 @@ // associated_allocator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,42 +17,76 @@ #include "asio/detail/config.hpp" #include <memory> +#include "asio/associator.hpp" +#include "asio/detail/functional.hpp" #include "asio/detail/type_traits.hpp" #include "asio/detail/push_options.hpp" namespace asio { + +template <typename T, typename Allocator> +struct associated_allocator; + namespace detail { -template <typename> -struct associated_allocator_check +template <typename T, typename = void> +struct has_allocator_type : false_type +{ +}; + +template <typename T> +struct has_allocator_type<T, void_t<typename T::allocator_type>> : true_type { - typedef void type; }; -template <typename T, typename E, typename = void> +template <typename T, typename A, typename = void, typename = void> struct associated_allocator_impl { - typedef E type; + typedef void asio_associated_allocator_is_unspecialised; + + typedef A type; + + static type get(const T&) noexcept + { + return type(); + } - static type get(const T&, const E& e) ASIO_NOEXCEPT + static const type& get(const T&, const A& a) noexcept { - return e; + return a; } }; -template <typename T, typename E> -struct associated_allocator_impl<T, E, - typename associated_allocator_check<typename T::allocator_type>::type> +template <typename T, typename A> +struct associated_allocator_impl<T, A, void_t<typename T::allocator_type>> { typedef typename T::allocator_type type; - static type get(const T& t, const E&) ASIO_NOEXCEPT + static auto get(const T& t) noexcept + -> decltype(t.get_allocator()) + { + return t.get_allocator(); + } + + static auto get(const T& t, const A&) noexcept + -> decltype(t.get_allocator()) { return t.get_allocator(); } }; +template <typename T, typename A> +struct associated_allocator_impl<T, A, + enable_if_t< + !has_allocator_type<T>::value + >, + void_t< + typename associator<associated_allocator, T, A>::type + >> : associator<associated_allocator, T, A> +{ +}; + } // namespace detail /// Traits type used to obtain the allocator associated with an object. @@ -69,29 +103,32 @@ struct associated_allocator_impl<T, E, * Allocator requirements. * * @li Provide a noexcept static member function named @c get, callable as @c - * get(t) and with return type @c type. + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. * * @li Provide a noexcept static member function named @c get, callable as @c - * get(t,a) and with return type @c type. + * get(t,a) and with return type @c type or a (possibly const) reference to @c + * type. */ -template <typename T, typename Allocator = std::allocator<void> > +template <typename T, typename Allocator = std::allocator<void>> struct associated_allocator +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_allocator_impl<T, Allocator> +#endif // !defined(GENERATING_DOCUMENTATION) { +#if defined(GENERATING_DOCUMENTATION) /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>. /// Otherwise @c Allocator. -#if defined(GENERATING_DOCUMENTATION) typedef see_below type; -#else // defined(GENERATING_DOCUMENTATION) - typedef typename detail::associated_allocator_impl<T, Allocator>::type type; -#endif // defined(GENERATING_DOCUMENTATION) + + /// If @c T has a nested type @c allocator_type, returns + /// <tt>t.get_allocator()</tt>. Otherwise returns @c type(). + static decltype(auto) get(const T& t) noexcept; /// If @c T has a nested type @c allocator_type, returns /// <tt>t.get_allocator()</tt>. Otherwise returns @c a. - static type get(const T& t, - const Allocator& a = Allocator()) ASIO_NOEXCEPT - { - return detail::associated_allocator_impl<T, Allocator>::get(t, a); - } + static decltype(auto) get(const T& t, const Allocator& a) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) }; /// Helper function to obtain an object's associated allocator. @@ -99,8 +136,8 @@ struct associated_allocator * @returns <tt>associated_allocator<T>::get(t)</tt> */ template <typename T> -inline typename associated_allocator<T>::type -get_associated_allocator(const T& t) ASIO_NOEXCEPT +ASIO_NODISCARD inline typename associated_allocator<T>::type +get_associated_allocator(const T& t) noexcept { return associated_allocator<T>::get(t); } @@ -110,12 +147,66 @@ get_associated_allocator(const T& t) ASIO_NOEXCEPT * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt> */ template <typename T, typename Allocator> -inline typename associated_allocator<T, Allocator>::type -get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT +ASIO_NODISCARD inline auto get_associated_allocator( + const T& t, const Allocator& a) noexcept + -> decltype(associated_allocator<T, Allocator>::get(t, a)) { return associated_allocator<T, Allocator>::get(t, a); } +template <typename T, typename Allocator = std::allocator<void>> +using associated_allocator_t + = typename associated_allocator<T, Allocator>::type; + +namespace detail { + +template <typename T, typename A, typename = void> +struct associated_allocator_forwarding_base +{ +}; + +template <typename T, typename A> +struct associated_allocator_forwarding_base<T, A, + enable_if_t< + is_same< + typename associated_allocator<T, + A>::asio_associated_allocator_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_allocator_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_allocator for @c std::reference_wrapper. +template <typename T, typename Allocator> +struct associated_allocator<reference_wrapper<T>, Allocator> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_allocator_forwarding_base<T, Allocator> +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_allocator<T, Allocator>::type type; + + /// Forwards the request to get the allocator to the associator specialisation + /// for the unwrapped type @c T. + static type get(reference_wrapper<T> t) noexcept + { + return associated_allocator<T, Allocator>::get(t.get()); + } + + /// Forwards the request to get the allocator to the associator specialisation + /// for the unwrapped type @c T. + static auto get(reference_wrapper<T> t, const Allocator& a) noexcept + -> decltype(associated_allocator<T, Allocator>::get(t.get(), a)) + { + return associated_allocator<T, Allocator>::get(t.get(), a); + } +}; + } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/associated_cancellation_slot.hpp b/3rdparty/asio/include/asio/associated_cancellation_slot.hpp new file mode 100644 index 00000000000..518bd881eaf --- /dev/null +++ b/3rdparty/asio/include/asio/associated_cancellation_slot.hpp @@ -0,0 +1,221 @@ +// +// associated_cancellation_slot.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_ASSOCIATED_CANCELLATION_SLOT_HPP +#define ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/cancellation_signal.hpp" +#include "asio/detail/functional.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename T, typename CancellationSlot> +struct associated_cancellation_slot; + +namespace detail { + +template <typename T, typename = void> +struct has_cancellation_slot_type : false_type +{ +}; + +template <typename T> +struct has_cancellation_slot_type<T, void_t<typename T::cancellation_slot_type>> + : true_type +{ +}; + +template <typename T, typename S, typename = void, typename = void> +struct associated_cancellation_slot_impl +{ + typedef void asio_associated_cancellation_slot_is_unspecialised; + + typedef S type; + + static type get(const T&) noexcept + { + return type(); + } + + static const type& get(const T&, const S& s) noexcept + { + return s; + } +}; + +template <typename T, typename S> +struct associated_cancellation_slot_impl<T, S, + void_t<typename T::cancellation_slot_type>> +{ + typedef typename T::cancellation_slot_type type; + + static auto get(const T& t) noexcept + -> decltype(t.get_cancellation_slot()) + { + return t.get_cancellation_slot(); + } + + static auto get(const T& t, const S&) noexcept + -> decltype(t.get_cancellation_slot()) + { + return t.get_cancellation_slot(); + } +}; + +template <typename T, typename S> +struct associated_cancellation_slot_impl<T, S, + enable_if_t< + !has_cancellation_slot_type<T>::value + >, + void_t< + typename associator<associated_cancellation_slot, T, S>::type + >> : associator<associated_cancellation_slot, T, S> +{ +}; + +} // namespace detail + +/// Traits type used to obtain the cancellation_slot associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * CancellationSlot shall be a type meeting the CancellationSlot requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c s is an object of type @c + * CancellationSlot. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * CancellationSlot requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,s) and with return type @c type or a (possibly const) reference to @c + * type. + */ +template <typename T, typename CancellationSlot = cancellation_slot> +struct associated_cancellation_slot +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_cancellation_slot_impl<T, CancellationSlot> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// If @c T has a nested type @c cancellation_slot_type, + /// <tt>T::cancellation_slot_type</tt>. Otherwise + /// @c CancellationSlot. + typedef see_below type; + + /// If @c T has a nested type @c cancellation_slot_type, returns + /// <tt>t.get_cancellation_slot()</tt>. Otherwise returns @c type(). + static decltype(auto) get(const T& t) noexcept; + + /// If @c T has a nested type @c cancellation_slot_type, returns + /// <tt>t.get_cancellation_slot()</tt>. Otherwise returns @c s. + static decltype(auto) get(const T& t, + const CancellationSlot& s) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +/// Helper function to obtain an object's associated cancellation_slot. +/** + * @returns <tt>associated_cancellation_slot<T>::get(t)</tt> + */ +template <typename T> +ASIO_NODISCARD inline typename associated_cancellation_slot<T>::type +get_associated_cancellation_slot(const T& t) noexcept +{ + return associated_cancellation_slot<T>::get(t); +} + +/// Helper function to obtain an object's associated cancellation_slot. +/** + * @returns <tt>associated_cancellation_slot<T, + * CancellationSlot>::get(t, st)</tt> + */ +template <typename T, typename CancellationSlot> +ASIO_NODISCARD inline auto get_associated_cancellation_slot( + const T& t, const CancellationSlot& st) noexcept + -> decltype(associated_cancellation_slot<T, CancellationSlot>::get(t, st)) +{ + return associated_cancellation_slot<T, CancellationSlot>::get(t, st); +} + +template <typename T, typename CancellationSlot = cancellation_slot> +using associated_cancellation_slot_t = + typename associated_cancellation_slot<T, CancellationSlot>::type; + +namespace detail { + +template <typename T, typename S, typename = void> +struct associated_cancellation_slot_forwarding_base +{ +}; + +template <typename T, typename S> +struct associated_cancellation_slot_forwarding_base<T, S, + enable_if_t< + is_same< + typename associated_cancellation_slot<T, + S>::asio_associated_cancellation_slot_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_cancellation_slot_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_cancellation_slot for @c +/// std::reference_wrapper. +template <typename T, typename CancellationSlot> +struct associated_cancellation_slot<reference_wrapper<T>, CancellationSlot> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_cancellation_slot_forwarding_base<T, CancellationSlot> +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_cancellation_slot<T, CancellationSlot>::type type; + + /// Forwards the request to get the cancellation slot to the associator + /// specialisation for the unwrapped type @c T. + static type get(reference_wrapper<T> t) noexcept + { + return associated_cancellation_slot<T, CancellationSlot>::get(t.get()); + } + + /// Forwards the request to get the cancellation slot to the associator + /// specialisation for the unwrapped type @c T. + static auto get(reference_wrapper<T> t, const CancellationSlot& s) noexcept + -> decltype( + associated_cancellation_slot<T, CancellationSlot>::get(t.get(), s)) + { + return associated_cancellation_slot<T, CancellationSlot>::get(t.get(), s); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP diff --git a/3rdparty/asio/include/asio/associated_executor.hpp b/3rdparty/asio/include/asio/associated_executor.hpp index 74603c593f0..4ca7ba149e9 100644 --- a/3rdparty/asio/include/asio/associated_executor.hpp +++ b/3rdparty/asio/include/asio/associated_executor.hpp @@ -2,7 +2,7 @@ // associated_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,44 +16,80 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/detail/functional.hpp" #include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" #include "asio/is_executor.hpp" #include "asio/system_executor.hpp" #include "asio/detail/push_options.hpp" namespace asio { + +template <typename T, typename Executor> +struct associated_executor; + namespace detail { -template <typename> -struct associated_executor_check +template <typename T, typename = void> +struct has_executor_type : false_type { - typedef void type; }; -template <typename T, typename E, typename = void> +template <typename T> +struct has_executor_type<T, void_t<typename T::executor_type>> + : true_type +{ +}; + +template <typename T, typename E, typename = void, typename = void> struct associated_executor_impl { + typedef void asio_associated_executor_is_unspecialised; + typedef E type; - static type get(const T&, const E& e) ASIO_NOEXCEPT + static type get(const T&) noexcept + { + return type(); + } + + static const type& get(const T&, const E& e) noexcept { return e; } }; template <typename T, typename E> -struct associated_executor_impl<T, E, - typename associated_executor_check<typename T::executor_type>::type> +struct associated_executor_impl<T, E, void_t<typename T::executor_type>> { typedef typename T::executor_type type; - static type get(const T& t, const E&) ASIO_NOEXCEPT + static auto get(const T& t) noexcept + -> decltype(t.get_executor()) + { + return t.get_executor(); + } + + static auto get(const T& t, const E&) noexcept + -> decltype(t.get_executor()) { return t.get_executor(); } }; +template <typename T, typename E> +struct associated_executor_impl<T, E, + enable_if_t< + !has_executor_type<T>::value + >, + void_t< + typename associator<associated_executor, T, E>::type + >> : associator<associated_executor, T, E> +{ +}; + } // namespace detail /// Traits type used to obtain the executor associated with an object. @@ -70,29 +106,32 @@ struct associated_executor_impl<T, E, * Executor requirements. * * @li Provide a noexcept static member function named @c get, callable as @c - * get(t) and with return type @c type. + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. * * @li Provide a noexcept static member function named @c get, callable as @c - * get(t,e) and with return type @c type. + * get(t,e) and with return type @c type or a (possibly const) reference to @c + * type. */ template <typename T, typename Executor = system_executor> struct associated_executor +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_executor_impl<T, Executor> +#endif // !defined(GENERATING_DOCUMENTATION) { +#if defined(GENERATING_DOCUMENTATION) /// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>. /// Otherwise @c Executor. -#if defined(GENERATING_DOCUMENTATION) typedef see_below type; -#else // defined(GENERATING_DOCUMENTATION) - typedef typename detail::associated_executor_impl<T, Executor>::type type; -#endif // defined(GENERATING_DOCUMENTATION) + + /// If @c T has a nested type @c executor_type, returns + /// <tt>t.get_executor()</tt>. Otherwise returns @c type(). + static decltype(auto) get(const T& t) noexcept; /// If @c T has a nested type @c executor_type, returns /// <tt>t.get_executor()</tt>. Otherwise returns @c ex. - static type get(const T& t, - const Executor& ex = Executor()) ASIO_NOEXCEPT - { - return detail::associated_executor_impl<T, Executor>::get(t, ex); - } + static decltype(auto) get(const T& t, const Executor& ex) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) }; /// Helper function to obtain an object's associated executor. @@ -100,8 +139,8 @@ struct associated_executor * @returns <tt>associated_executor<T>::get(t)</tt> */ template <typename T> -inline typename associated_executor<T>::type -get_associated_executor(const T& t) ASIO_NOEXCEPT +ASIO_NODISCARD inline typename associated_executor<T>::type +get_associated_executor(const T& t) noexcept { return associated_executor<T>::get(t); } @@ -111,10 +150,12 @@ get_associated_executor(const T& t) ASIO_NOEXCEPT * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt> */ template <typename T, typename Executor> -inline typename associated_executor<T, Executor>::type -get_associated_executor(const T& t, const Executor& ex, - typename enable_if<is_executor< - Executor>::value>::type* = 0) ASIO_NOEXCEPT +ASIO_NODISCARD inline auto get_associated_executor( + const T& t, const Executor& ex, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) noexcept + -> decltype(associated_executor<T, Executor>::get(t, ex)) { return associated_executor<T, Executor>::get(t, ex); } @@ -125,16 +166,68 @@ get_associated_executor(const T& t, const Executor& ex, * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> */ template <typename T, typename ExecutionContext> -inline typename associated_executor<T, - typename ExecutionContext::executor_type>::type +ASIO_NODISCARD inline typename associated_executor<T, + typename ExecutionContext::executor_type>::type get_associated_executor(const T& t, ExecutionContext& ctx, - typename enable_if<is_convertible<ExecutionContext&, - execution_context&>::value>::type* = 0) ASIO_NOEXCEPT + constraint_t<is_convertible<ExecutionContext&, + execution_context&>::value> = 0) noexcept { return associated_executor<T, typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); } +template <typename T, typename Executor = system_executor> +using associated_executor_t = typename associated_executor<T, Executor>::type; + +namespace detail { + +template <typename T, typename E, typename = void> +struct associated_executor_forwarding_base +{ +}; + +template <typename T, typename E> +struct associated_executor_forwarding_base<T, E, + enable_if_t< + is_same< + typename associated_executor<T, + E>::asio_associated_executor_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_executor_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_executor for @c std::reference_wrapper. +template <typename T, typename Executor> +struct associated_executor<reference_wrapper<T>, Executor> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_executor_forwarding_base<T, Executor> +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_executor<T, Executor>::type type; + + /// Forwards the request to get the executor to the associator specialisation + /// for the unwrapped type @c T. + static type get(reference_wrapper<T> t) noexcept + { + return associated_executor<T, Executor>::get(t.get()); + } + + /// Forwards the request to get the executor to the associator specialisation + /// for the unwrapped type @c T. + static auto get(reference_wrapper<T> t, const Executor& ex) noexcept + -> decltype(associated_executor<T, Executor>::get(t.get(), ex)) + { + return associated_executor<T, Executor>::get(t.get(), ex); + } +}; + } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/associated_immediate_executor.hpp b/3rdparty/asio/include/asio/associated_immediate_executor.hpp new file mode 100644 index 00000000000..aa6e0fcfee7 --- /dev/null +++ b/3rdparty/asio/include/asio/associated_immediate_executor.hpp @@ -0,0 +1,280 @@ +// +// associated_immediate_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP +#define ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/detail/functional.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/is_executor.hpp" +#include "asio/require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename T, typename Executor> +struct associated_immediate_executor; + +namespace detail { + +template <typename T, typename = void> +struct has_immediate_executor_type : false_type +{ +}; + +template <typename T> +struct has_immediate_executor_type<T, + void_t<typename T::immediate_executor_type>> + : true_type +{ +}; + +template <typename E, typename = void, typename = void> +struct default_immediate_executor +{ + typedef require_result_t<E, execution::blocking_t::never_t> type; + + static type get(const E& e) noexcept + { + return asio::require(e, execution::blocking.never); + } +}; + +template <typename E> +struct default_immediate_executor<E, + enable_if_t< + !execution::is_executor<E>::value + >, + enable_if_t< + is_executor<E>::value + >> +{ + class type : public E + { + public: + template <typename Executor1> + explicit type(const Executor1& e, + constraint_t< + conditional_t< + !is_same<Executor1, type>::value, + is_convertible<Executor1, E>, + false_type + >::value + > = 0) noexcept + : E(e) + { + } + + type(const type& other) noexcept + : E(static_cast<const E&>(other)) + { + } + + type(type&& other) noexcept + : E(static_cast<E&&>(other)) + { + } + + template <typename Function, typename Allocator> + void dispatch(Function&& f, const Allocator& a) const + { + this->post(static_cast<Function&&>(f), a); + } + + friend bool operator==(const type& a, const type& b) noexcept + { + return static_cast<const E&>(a) == static_cast<const E&>(b); + } + + friend bool operator!=(const type& a, const type& b) noexcept + { + return static_cast<const E&>(a) != static_cast<const E&>(b); + } + }; + + static type get(const E& e) noexcept + { + return type(e); + } +}; + +template <typename T, typename E, typename = void, typename = void> +struct associated_immediate_executor_impl +{ + typedef void asio_associated_immediate_executor_is_unspecialised; + + typedef typename default_immediate_executor<E>::type type; + + static auto get(const T&, const E& e) noexcept + -> decltype(default_immediate_executor<E>::get(e)) + { + return default_immediate_executor<E>::get(e); + } +}; + +template <typename T, typename E> +struct associated_immediate_executor_impl<T, E, + void_t<typename T::immediate_executor_type>> +{ + typedef typename T::immediate_executor_type type; + + static auto get(const T& t, const E&) noexcept + -> decltype(t.get_immediate_executor()) + { + return t.get_immediate_executor(); + } +}; + +template <typename T, typename E> +struct associated_immediate_executor_impl<T, E, + enable_if_t< + !has_immediate_executor_type<T>::value + >, + void_t< + typename associator<associated_immediate_executor, T, E>::type + >> : associator<associated_immediate_executor, T, E> +{ +}; + +} // namespace detail + +/// Traits type used to obtain the immediate executor associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Executor shall be a type meeting the Executor requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c e is an object of type @c + * Executor. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Executor requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type or a (possibly const) reference to @c + * type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,e) and with return type @c type or a (possibly const) reference to @c + * type. + */ +template <typename T, typename Executor> +struct associated_immediate_executor +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_immediate_executor_impl<T, Executor> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +#if defined(GENERATING_DOCUMENTATION) + /// If @c T has a nested type @c immediate_executor_type, + // <tt>T::immediate_executor_type</tt>. Otherwise @c Executor. + typedef see_below type; + + /// If @c T has a nested type @c immediate_executor_type, returns + /// <tt>t.get_immediate_executor()</tt>. Otherwise returns + /// <tt>asio::require(ex, asio::execution::blocking.never)</tt>. + static decltype(auto) get(const T& t, const Executor& ex) noexcept; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +/// Helper function to obtain an object's associated executor. +/** + * @returns <tt>associated_immediate_executor<T, Executor>::get(t, ex)</tt> + */ +template <typename T, typename Executor> +ASIO_NODISCARD inline auto get_associated_immediate_executor( + const T& t, const Executor& ex, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) noexcept + -> decltype(associated_immediate_executor<T, Executor>::get(t, ex)) +{ + return associated_immediate_executor<T, Executor>::get(t, ex); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns <tt>associated_immediate_executor<T, typename + * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> + */ +template <typename T, typename ExecutionContext> +ASIO_NODISCARD inline typename associated_immediate_executor<T, + typename ExecutionContext::executor_type>::type +get_associated_immediate_executor(const T& t, ExecutionContext& ctx, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) noexcept +{ + return associated_immediate_executor<T, + typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); +} + +template <typename T, typename Executor> +using associated_immediate_executor_t = + typename associated_immediate_executor<T, Executor>::type; + +namespace detail { + +template <typename T, typename E, typename = void> +struct associated_immediate_executor_forwarding_base +{ +}; + +template <typename T, typename E> +struct associated_immediate_executor_forwarding_base<T, E, + enable_if_t< + is_same< + typename associated_immediate_executor<T, + E>::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >> +{ + typedef void asio_associated_immediate_executor_is_unspecialised; +}; + +} // namespace detail + +/// Specialisation of associated_immediate_executor for +/// @c std::reference_wrapper. +template <typename T, typename Executor> +struct associated_immediate_executor<reference_wrapper<T>, Executor> +#if !defined(GENERATING_DOCUMENTATION) + : detail::associated_immediate_executor_forwarding_base<T, Executor> +#endif // !defined(GENERATING_DOCUMENTATION) +{ + /// Forwards @c type to the associator specialisation for the unwrapped type + /// @c T. + typedef typename associated_immediate_executor<T, Executor>::type type; + + /// Forwards the request to get the executor to the associator specialisation + /// for the unwrapped type @c T. + static auto get(reference_wrapper<T> t, const Executor& ex) noexcept + -> decltype(associated_immediate_executor<T, Executor>::get(t.get(), ex)) + { + return associated_immediate_executor<T, Executor>::get(t.get(), ex); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/associator.hpp b/3rdparty/asio/include/asio/associator.hpp new file mode 100644 index 00000000000..7952fcc51ba --- /dev/null +++ b/3rdparty/asio/include/asio/associator.hpp @@ -0,0 +1,35 @@ +// +// associator.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_ASSOCIATOR_HPP +#define ASIO_ASSOCIATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Used to generically specialise associators for a type. +template <template <typename, typename> class Associator, + typename T, typename DefaultCandidate> +struct associator +{ +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ASSOCIATOR_HPP diff --git a/3rdparty/asio/include/asio/async_result.hpp b/3rdparty/asio/include/asio/async_result.hpp index cd866bbd0e6..cdae9ede687 100644 --- a/3rdparty/asio/include/asio/async_result.hpp +++ b/3rdparty/asio/include/asio/async_result.hpp @@ -2,7 +2,7 @@ // async_result.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,12 +17,321 @@ #include "asio/detail/config.hpp" #include "asio/detail/type_traits.hpp" -#include "asio/handler_type.hpp" #include "asio/detail/push_options.hpp" namespace asio { +#if defined(ASIO_HAS_CONCEPTS) + +namespace detail { + +template <typename T> +struct is_completion_signature : false_type +{ +}; + +template <typename R, typename... Args> +struct is_completion_signature<R(Args...)> : true_type +{ +}; + +template <typename R, typename... Args> +struct is_completion_signature<R(Args...) &> : true_type +{ +}; + +template <typename R, typename... Args> +struct is_completion_signature<R(Args...) &&> : true_type +{ +}; + +# if defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename R, typename... Args> +struct is_completion_signature<R(Args...) noexcept> : true_type +{ +}; + +template <typename R, typename... Args> +struct is_completion_signature<R(Args...) & noexcept> : true_type +{ +}; + +template <typename R, typename... Args> +struct is_completion_signature<R(Args...) && noexcept> : true_type +{ +}; + +# endif // defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename... T> +struct are_completion_signatures : false_type +{ +}; + +template <typename T0> +struct are_completion_signatures<T0> + : is_completion_signature<T0> +{ +}; + +template <typename T0, typename... TN> +struct are_completion_signatures<T0, TN...> + : integral_constant<bool, ( + is_completion_signature<T0>::value + && are_completion_signatures<TN...>::value)> +{ +}; + +template <typename T, typename... Args> +ASIO_CONCEPT callable_with = requires(T&& t, Args&&... args) +{ + static_cast<T&&>(t)(static_cast<Args&&>(args)...); +}; + +template <typename T, typename... Signatures> +struct is_completion_handler_for : false_type +{ +}; + +template <typename T, typename R, typename... Args> +struct is_completion_handler_for<T, R(Args...)> + : integral_constant<bool, (callable_with<decay_t<T>, Args...>)> +{ +}; + +template <typename T, typename R, typename... Args> +struct is_completion_handler_for<T, R(Args...) &> + : integral_constant<bool, (callable_with<decay_t<T>&, Args...>)> +{ +}; + +template <typename T, typename R, typename... Args> +struct is_completion_handler_for<T, R(Args...) &&> + : integral_constant<bool, (callable_with<decay_t<T>&&, Args...>)> +{ +}; + +# if defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename T, typename R, typename... Args> +struct is_completion_handler_for<T, R(Args...) noexcept> + : integral_constant<bool, (callable_with<decay_t<T>, Args...>)> +{ +}; + +template <typename T, typename R, typename... Args> +struct is_completion_handler_for<T, R(Args...) & noexcept> + : integral_constant<bool, (callable_with<decay_t<T>&, Args...>)> +{ +}; + +template <typename T, typename R, typename... Args> +struct is_completion_handler_for<T, R(Args...) && noexcept> + : integral_constant<bool, (callable_with<decay_t<T>&&, Args...>)> +{ +}; + +# endif // defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename T, typename Signature0, typename... SignatureN> +struct is_completion_handler_for<T, Signature0, SignatureN...> + : integral_constant<bool, ( + is_completion_handler_for<T, Signature0>::value + && is_completion_handler_for<T, SignatureN...>::value)> +{ +}; + +} // namespace detail + +template <typename T> +ASIO_CONCEPT completion_signature = + detail::is_completion_signature<T>::value; + +#define ASIO_COMPLETION_SIGNATURE \ + ::asio::completion_signature + +template <typename T, typename... Signatures> +ASIO_CONCEPT completion_handler_for = + detail::are_completion_signatures<Signatures...>::value + && detail::is_completion_handler_for<T, Signatures...>::value; + +#define ASIO_COMPLETION_HANDLER_FOR(sig) \ + ::asio::completion_handler_for<sig> +#define ASIO_COMPLETION_HANDLER_FOR2(sig0, sig1) \ + ::asio::completion_handler_for<sig0, sig1> +#define ASIO_COMPLETION_HANDLER_FOR3(sig0, sig1, sig2) \ + ::asio::completion_handler_for<sig0, sig1, sig2> + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_COMPLETION_SIGNATURE typename +#define ASIO_COMPLETION_HANDLER_FOR(sig) typename +#define ASIO_COMPLETION_HANDLER_FOR2(sig0, sig1) typename +#define ASIO_COMPLETION_HANDLER_FOR3(sig0, sig1, sig2) typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +namespace detail { + +template <typename T> +struct is_lvalue_completion_signature : false_type +{ +}; + +template <typename R, typename... Args> +struct is_lvalue_completion_signature<R(Args...) &> : true_type +{ +}; + +# if defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename R, typename... Args> +struct is_lvalue_completion_signature<R(Args...) & noexcept> : true_type +{ +}; + +# endif // defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename... Signatures> +struct are_any_lvalue_completion_signatures : false_type +{ +}; + +template <typename Sig0> +struct are_any_lvalue_completion_signatures<Sig0> + : is_lvalue_completion_signature<Sig0> +{ +}; + +template <typename Sig0, typename... SigN> +struct are_any_lvalue_completion_signatures<Sig0, SigN...> + : integral_constant<bool, ( + is_lvalue_completion_signature<Sig0>::value + || are_any_lvalue_completion_signatures<SigN...>::value)> +{ +}; + +template <typename T> +struct is_rvalue_completion_signature : false_type +{ +}; + +template <typename R, typename... Args> +struct is_rvalue_completion_signature<R(Args...) &&> : true_type +{ +}; + +# if defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename R, typename... Args> +struct is_rvalue_completion_signature<R(Args...) && noexcept> : true_type +{ +}; + +# endif // defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename... Signatures> +struct are_any_rvalue_completion_signatures : false_type +{ +}; + +template <typename Sig0> +struct are_any_rvalue_completion_signatures<Sig0> + : is_rvalue_completion_signature<Sig0> +{ +}; + +template <typename Sig0, typename... SigN> +struct are_any_rvalue_completion_signatures<Sig0, SigN...> + : integral_constant<bool, ( + is_rvalue_completion_signature<Sig0>::value + || are_any_rvalue_completion_signatures<SigN...>::value)> +{ +}; + +template <typename T> +struct simple_completion_signature; + +template <typename R, typename... Args> +struct simple_completion_signature<R(Args...)> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct simple_completion_signature<R(Args...) &> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct simple_completion_signature<R(Args...) &&> +{ + typedef R type(Args...); +}; + +# if defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename R, typename... Args> +struct simple_completion_signature<R(Args...) noexcept> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct simple_completion_signature<R(Args...) & noexcept> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct simple_completion_signature<R(Args...) && noexcept> +{ + typedef R type(Args...); +}; + +# endif // defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename CompletionToken, + ASIO_COMPLETION_SIGNATURE... Signatures> +class completion_handler_async_result +{ +public: + typedef CompletionToken completion_handler_type; + typedef void return_type; + + explicit completion_handler_async_result(completion_handler_type&) + { + } + + return_type get() + { + } + + template <typename Initiation, + ASIO_COMPLETION_HANDLER_FOR(Signatures...) RawCompletionToken, + typename... Args> + static return_type initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + { + static_cast<Initiation&&>(initiation)( + static_cast<RawCompletionToken&&>(token), + static_cast<Args&&>(args)...); + } + +private: + completion_handler_async_result( + const completion_handler_async_result&) = delete; + completion_handler_async_result& operator=( + const completion_handler_async_result&) = delete; +}; + +} // namespace detail + +#if defined(GENERATING_DOCUMENTATION) + /// An interface for customising the behaviour of an initiating function. /** * The async_result traits class is used for determining: @@ -41,30 +350,16 @@ namespace asio { * The primary template assumes that the CompletionToken is the completion * handler. */ -#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) -template <typename CompletionToken, typename Signature> -#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) -template <typename CompletionToken, typename Signature = void> -#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +template <typename CompletionToken, + ASIO_COMPLETION_SIGNATURE... Signatures> class async_result { public: -#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) /// The concrete completion handler type for the specific signature. typedef CompletionToken completion_handler_type; /// The return type of the initiating function. typedef void return_type; -#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - // For backward compatibility, determine the concrete completion handler type - // by using the legacy handler_type trait. - typedef typename handler_type<CompletionToken, Signature>::type - completion_handler_type; - - // For backward compatibility, determine the initiating function return type - // using the legacy single-parameter version of async_result. - typedef typename async_result<completion_handler_type>::type return_type; -#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) /// Construct an async result from a given handler. /** @@ -72,150 +367,576 @@ public: * to initialise some state associated with the completion handler, which is * then returned from the initiating function. */ - explicit async_result(completion_handler_type& h) -#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - // No data members to initialise. -#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - : legacy_result_(h) -#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - { - (void)h; - } + explicit async_result(completion_handler_type& h); /// Obtain the value to be returned from the initiating function. - return_type get() - { -#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - // Nothing to do. -#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - return legacy_result_.get(); -#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - } + return_type get(); -private: - async_result(const async_result&) ASIO_DELETED; - async_result& operator=(const async_result&) ASIO_DELETED; + /// Initiate the asynchronous operation that will produce the result, and + /// obtain the value to be returned from the initiating function. + template <typename Initiation, typename RawCompletionToken, typename... Args> + static return_type initiate( + Initiation&& initiation, + RawCompletionToken&& token, + Args&&... args); -#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - // No data members. -#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - async_result<completion_handler_type> legacy_result_; -#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +private: + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; }; -#if !defined(ASIO_NO_DEPRECATED) +#else // defined(GENERATING_DOCUMENTATION) -/// (Deprecated: Use two-parameter version of async_result.) An interface for -/// customising the behaviour of an initiating function. -/** - * This template may be specialised for user-defined handler types. - */ -template <typename Handler> -class async_result<Handler> +template <typename CompletionToken, + ASIO_COMPLETION_SIGNATURE... Signatures> +class async_result : + public conditional_t< + detail::are_any_lvalue_completion_signatures<Signatures...>::value + || !detail::are_any_rvalue_completion_signatures<Signatures...>::value, + detail::completion_handler_async_result<CompletionToken, Signatures...>, + async_result<CompletionToken, + typename detail::simple_completion_signature<Signatures>::type...> + > { public: - /// The return type of the initiating function. - typedef void type; + typedef conditional_t< + detail::are_any_lvalue_completion_signatures<Signatures...>::value + || !detail::are_any_rvalue_completion_signatures<Signatures...>::value, + detail::completion_handler_async_result<CompletionToken, Signatures...>, + async_result<CompletionToken, + typename detail::simple_completion_signature<Signatures>::type...> + > base_type; - /// Construct an async result from a given handler. - /** - * When using a specalised async_result, the constructor has an opportunity - * to initialise some state associated with the handler, which is then - * returned from the initiating function. - */ - explicit async_result(Handler&) - { - } + using base_type::base_type; - /// Obtain the value to be returned from the initiating function. - type get() - { - } +private: + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; }; -#endif // !defined(ASIO_NO_DEPRECATED) +template <ASIO_COMPLETION_SIGNATURE... Signatures> +class async_result<void, Signatures...> +{ + // Empty. +}; + +#endif // defined(GENERATING_DOCUMENTATION) /// Helper template to deduce the handler type from a CompletionToken, capture /// a local copy of the handler, and then create an async_result for the /// handler. -template <typename CompletionToken, typename Signature> +template <typename CompletionToken, + ASIO_COMPLETION_SIGNATURE... Signatures> struct async_completion { /// The real handler type to be used for the asynchronous operation. typedef typename asio::async_result< - typename decay<CompletionToken>::type, - Signature>::completion_handler_type completion_handler_type; + decay_t<CompletionToken>, Signatures...>::completion_handler_type + completion_handler_type; -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Constructor. /** * The constructor creates the concrete completion handler and makes the link * between the handler and the asynchronous result. */ explicit async_completion(CompletionToken& token) - : completion_handler(static_cast<typename conditional< + : completion_handler(static_cast<conditional_t< is_same<CompletionToken, completion_handler_type>::value, - completion_handler_type&, CompletionToken&&>::type>(token)), - result(completion_handler) - { - } -#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - explicit async_completion(typename decay<CompletionToken>::type& token) - : completion_handler(token), - result(completion_handler) - { - } - - explicit async_completion(const typename decay<CompletionToken>::type& token) - : completion_handler(token), + completion_handler_type&, CompletionToken&&>>(token)), result(completion_handler) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// A copy of, or reference to, a real handler object. -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - typename conditional< + conditional_t< is_same<CompletionToken, completion_handler_type>::value, - completion_handler_type&, completion_handler_type>::type completion_handler; -#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - completion_handler_type completion_handler; -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + completion_handler_type&, completion_handler_type> completion_handler; /// The result of the asynchronous operation's initiating function. - async_result<typename decay<CompletionToken>::type, Signature> result; + async_result<decay_t<CompletionToken>, Signatures...> result; }; namespace detail { -template <typename CompletionToken, typename Signature> -struct async_result_helper - : async_result<typename decay<CompletionToken>::type, Signature> +struct async_result_memfns_base { + void initiate(); }; -} // namespace detail -} // namespace asio +template <typename T> +struct async_result_memfns_derived + : T, async_result_memfns_base +{ +}; -#include "asio/detail/pop_options.hpp" +template <typename T, T> +struct async_result_memfns_check +{ +}; + +template <typename> +char (&async_result_initiate_memfn_helper(...))[2]; + +template <typename T> +char async_result_initiate_memfn_helper( + async_result_memfns_check< + void (async_result_memfns_base::*)(), + &async_result_memfns_derived<T>::initiate>*); + +template <typename CompletionToken, + ASIO_COMPLETION_SIGNATURE... Signatures> +struct async_result_has_initiate_memfn + : integral_constant<bool, sizeof(async_result_initiate_memfn_helper< + async_result<decay_t<CompletionToken>, Signatures...> + >(0)) != 1> +{ +}; + +} // namespace detail #if defined(GENERATING_DOCUMENTATION) # define ASIO_INITFN_RESULT_TYPE(ct, sig) \ void_or_deduced -#elif defined(_MSC_VER) && (_MSC_VER < 1500) -# define ASIO_INITFN_RESULT_TYPE(ct, sig) \ - typename ::asio::detail::async_result_helper< \ - ct, sig>::return_type -#define ASIO_HANDLER_TYPE(ct, sig) \ - typename ::asio::detail::async_result_helper< \ - ct, sig>::completion_handler_type +# define ASIO_INITFN_RESULT_TYPE2(ct, sig0, sig1) \ + void_or_deduced +# define ASIO_INITFN_RESULT_TYPE3(ct, sig0, sig1, sig2) \ + void_or_deduced #else # define ASIO_INITFN_RESULT_TYPE(ct, sig) \ typename ::asio::async_result< \ typename ::asio::decay<ct>::type, sig>::return_type +# define ASIO_INITFN_RESULT_TYPE2(ct, sig0, sig1) \ + typename ::asio::async_result< \ + typename ::asio::decay<ct>::type, sig0, sig1>::return_type +# define ASIO_INITFN_RESULT_TYPE3(ct, sig0, sig1, sig2) \ + typename ::asio::async_result< \ + typename ::asio::decay<ct>::type, sig0, sig1, sig2>::return_type #define ASIO_HANDLER_TYPE(ct, sig) \ typename ::asio::async_result< \ typename ::asio::decay<ct>::type, sig>::completion_handler_type +#define ASIO_HANDLER_TYPE2(ct, sig0, sig1) \ + typename ::asio::async_result< \ + typename ::asio::decay<ct>::type, \ + sig0, sig1>::completion_handler_type +#define ASIO_HANDLER_TYPE3(ct, sig0, sig1, sig2) \ + typename ::asio::async_result< \ + typename ::asio::decay<ct>::type, \ + sig0, sig1, sig2>::completion_handler_type +#endif + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE2(ct, sig0, sig1) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE3(ct, sig0, sig1, sig2) \ + auto +#elif defined(ASIO_HAS_RETURN_TYPE_DEDUCTION) +# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE2(ct, sig0, sig1) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE3(ct, sig0, sig1, sig2) \ + auto +#else +# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + ASIO_INITFN_RESULT_TYPE(ct, sig) +# define ASIO_INITFN_AUTO_RESULT_TYPE2(ct, sig0, sig1) \ + ASIO_INITFN_RESULT_TYPE2(ct, sig0, sig1) +# define ASIO_INITFN_AUTO_RESULT_TYPE3(ct, sig0, sig1, sig2) \ + ASIO_INITFN_RESULT_TYPE3(ct, sig0, sig1, sig2) +#endif + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(ct, sig) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX2(ct, sig0, sig1) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX3(ct, sig0, sig1, sig2) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(expr) +#elif defined(ASIO_HAS_RETURN_TYPE_DEDUCTION) +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(ct, sig) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX2(ct, sig0, sig1) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX3(ct, sig0, sig1, sig2) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(expr) +#else +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(ct, sig) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX2(ct, sig0, sig1) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX3(ct, sig0, sig1, sig2) \ + auto +# define ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(expr) -> decltype expr +#endif + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + void_or_deduced +# define ASIO_INITFN_DEDUCED_RESULT_TYPE2(ct, sig0, sig1, expr) \ + void_or_deduced +# define ASIO_INITFN_DEDUCED_RESULT_TYPE3(ct, sig0, sig1, sig2, expr) \ + void_or_deduced +#else +# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + decltype expr +# define ASIO_INITFN_DEDUCED_RESULT_TYPE2(ct, sig0, sig1, expr) \ + decltype expr +# define ASIO_INITFN_DEDUCED_RESULT_TYPE3(ct, sig0, sig1, sig2, expr) \ + decltype expr +#endif + +#if defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, + completion_signature... Signatures, + typename Initiation, typename... Args> +void_or_deduced async_initiate( + Initiation&& initiation, + type_identity_t<CompletionToken>& token, + Args&&... args); + +#else // defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, + ASIO_COMPLETION_SIGNATURE... Signatures, + typename Initiation, typename... Args> +inline auto async_initiate(Initiation&& initiation, + type_identity_t<CompletionToken>& token, Args&&... args) + -> constraint_t< + detail::async_result_has_initiate_memfn< + CompletionToken, Signatures...>::value, + decltype( + async_result<decay_t<CompletionToken>, Signatures...>::initiate( + static_cast<Initiation&&>(initiation), + static_cast<CompletionToken&&>(token), + static_cast<Args&&>(args)...))> +{ + return async_result<decay_t<CompletionToken>, Signatures...>::initiate( + static_cast<Initiation&&>(initiation), + static_cast<CompletionToken&&>(token), + static_cast<Args&&>(args)...); +} + +template <typename CompletionToken, + ASIO_COMPLETION_SIGNATURE... Signatures, + typename Initiation, typename... Args> +inline constraint_t< + !detail::async_result_has_initiate_memfn< + CompletionToken, Signatures...>::value, + typename async_result<decay_t<CompletionToken>, Signatures...>::return_type> +async_initiate(Initiation&& initiation, + type_identity_t<CompletionToken>& token, Args&&... args) +{ + async_completion<CompletionToken, Signatures...> completion(token); + + static_cast<Initiation&&>(initiation)( + static_cast< + typename async_result<decay_t<CompletionToken>, + Signatures...>::completion_handler_type&&>( + completion.completion_handler), + static_cast<Args&&>(args)...); + + return completion.result.get(); +} + +#endif // defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_CONCEPTS) + +namespace detail { + +template <typename... Signatures> +struct initiation_archetype +{ + template <completion_handler_for<Signatures...> CompletionHandler> + void operator()(CompletionHandler&&) const + { + } +}; + +} // namespace detail + +template <typename T, typename... Signatures> +ASIO_CONCEPT completion_token_for = + detail::are_completion_signatures<Signatures...>::value + && + requires(T&& t) + { + async_initiate<T, Signatures...>( + detail::initiation_archetype<Signatures...>{}, t); + }; + +#define ASIO_COMPLETION_TOKEN_FOR(sig) \ + ::asio::completion_token_for<sig> +#define ASIO_COMPLETION_TOKEN_FOR2(sig0, sig1) \ + ::asio::completion_token_for<sig0, sig1> +#define ASIO_COMPLETION_TOKEN_FOR3(sig0, sig1, sig2) \ + ::asio::completion_token_for<sig0, sig1, sig2> + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_COMPLETION_TOKEN_FOR(sig) typename +#define ASIO_COMPLETION_TOKEN_FOR2(sig0, sig1) typename +#define ASIO_COMPLETION_TOKEN_FOR3(sig0, sig1, sig2) typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +namespace detail { + +struct async_operation_probe {}; +struct async_operation_probe_result {}; + +template <typename Call, typename = void> +struct is_async_operation_call : false_type +{ +}; + +template <typename Call> +struct is_async_operation_call<Call, + void_t< + enable_if_t< + is_same< + result_of_t<Call>, + async_operation_probe_result + >::value + > + > + > : true_type +{ +}; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename... Signatures> +class async_result<detail::async_operation_probe, Signatures...> +{ +public: + typedef detail::async_operation_probe_result return_type; + + template <typename Initiation, typename... InitArgs> + static return_type initiate(Initiation&&, + detail::async_operation_probe, InitArgs&&...) + { + return return_type(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +#if defined(GENERATING_DOCUMENTATION) + +/// The is_async_operation trait detects whether a type @c T and arguments +/// @c Args... may be used to initiate an asynchronous operation. +/** + * Class template @c is_async_operation is a trait is derived from @c true_type + * if the expression <tt>T(Args..., token)</tt> initiates an asynchronous + * operation, where @c token is an unspecified completion token type. Otherwise, + * @c is_async_operation is derived from @c false_type. + */ +template <typename T, typename... Args> +struct is_async_operation : integral_constant<bool, automatically_determined> +{ +}; + +#else // defined(GENERATING_DOCUMENTATION) + +template <typename T, typename... Args> +struct is_async_operation : + detail::is_async_operation_call< + T(Args..., detail::async_operation_probe)> +{ +}; + +#endif // defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_CONCEPTS) + +template <typename T, typename... Args> +ASIO_CONCEPT async_operation = is_async_operation<T, Args...>::value; + +#define ASIO_ASYNC_OPERATION(t) \ + ::asio::async_operation<t> +#define ASIO_ASYNC_OPERATION1(t, a0) \ + ::asio::async_operation<t, a0> +#define ASIO_ASYNC_OPERATION2(t, a0, a1) \ + ::asio::async_operation<t, a0, a1> +#define ASIO_ASYNC_OPERATION3(t, a0, a1, a2) \ + ::asio::async_operation<t, a0, a1, a2> + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_ASYNC_OPERATION(t) typename +#define ASIO_ASYNC_OPERATION1(t, a0) typename +#define ASIO_ASYNC_OPERATION2(t, a0, a1) typename +#define ASIO_ASYNC_OPERATION3(t, a0, a1, a2) typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +namespace detail { + +struct completion_signature_probe {}; + +template <typename... T> +struct completion_signature_probe_result +{ + template <template <typename...> class Op> + struct apply + { + typedef Op<T...> type; + }; +}; + +template <typename T> +struct completion_signature_probe_result<T> +{ + typedef T type; + + template <template <typename...> class Op> + struct apply + { + typedef Op<T> type; + }; +}; + +template <> +struct completion_signature_probe_result<void> +{ + template <template <typename...> class Op> + struct apply + { + typedef Op<> type; + }; +}; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename... Signatures> +class async_result<detail::completion_signature_probe, Signatures...> +{ +public: + typedef detail::completion_signature_probe_result<Signatures...> return_type; + + template <typename Initiation, typename... InitArgs> + static return_type initiate(Initiation&&, + detail::completion_signature_probe, InitArgs&&...) + { + return return_type(); + } +}; + +template <typename Signature> +class async_result<detail::completion_signature_probe, Signature> +{ +public: + typedef detail::completion_signature_probe_result<Signature> return_type; + + template <typename Initiation, typename... InitArgs> + static return_type initiate(Initiation&&, + detail::completion_signature_probe, InitArgs&&...) + { + return return_type(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +#if defined(GENERATING_DOCUMENTATION) + +/// The completion_signature_of trait determines the completion signature +/// of an asynchronous operation. +/** + * Class template @c completion_signature_of is a trait with a member type + * alias @c type that denotes the completion signature of the asynchronous + * operation initiated by the expression <tt>T(Args..., token)</tt> operation, + * where @c token is an unspecified completion token type. If the asynchronous + * operation does not have exactly one completion signature, the instantion of + * the trait is well-formed but the member type alias @c type is omitted. If + * the expression <tt>T(Args..., token)</tt> is not an asynchronous operation + * then use of the trait is ill-formed. + */ +template <typename T, typename... Args> +struct completion_signature_of +{ + typedef automatically_determined type; +}; + +#else // defined(GENERATING_DOCUMENTATION) + +template <typename T, typename... Args> +struct completion_signature_of : + result_of_t<T(Args..., detail::completion_signature_probe)> +{ +}; + +#endif // defined(GENERATING_DOCUMENTATION) + +template <typename T, typename... Args> +using completion_signature_of_t = + typename completion_signature_of<T, Args...>::type; + +namespace detail { + +template <typename T, typename = void> +struct default_completion_token_impl +{ + typedef void type; +}; + +template <typename T> +struct default_completion_token_impl<T, + void_t<typename T::default_completion_token_type> + > +{ + typedef typename T::default_completion_token_type type; +}; + +} // namespace detail + +#if defined(GENERATING_DOCUMENTATION) + +/// Traits type used to determine the default completion token type associated +/// with a type (such as an executor). +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. + * + * Specialisations of this trait may provide a nested typedef @c type, which is + * a default-constructible completion token type. + */ +template <typename T> +struct default_completion_token +{ + /// If @c T has a nested type @c default_completion_token_type, + /// <tt>T::default_completion_token_type</tt>. Otherwise the typedef @c type + /// is not defined. + typedef see_below type; +}; +#else +template <typename T> +struct default_completion_token + : detail::default_completion_token_impl<T> +{ +}; #endif +template <typename T> +using default_completion_token_t = typename default_completion_token<T>::type; + +#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) \ + = typename ::asio::default_completion_token<e>::type +#define ASIO_DEFAULT_COMPLETION_TOKEN(e) \ + = typename ::asio::default_completion_token<e>::type() + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + #endif // ASIO_ASYNC_RESULT_HPP diff --git a/3rdparty/asio/include/asio/awaitable.hpp b/3rdparty/asio/include/asio/awaitable.hpp new file mode 100644 index 00000000000..7e4ee7a2f22 --- /dev/null +++ b/3rdparty/asio/include/asio/awaitable.hpp @@ -0,0 +1,142 @@ +// +// awaitable.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_AWAITABLE_HPP +#define ASIO_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_STD_COROUTINE) +# include <coroutine> +#else // defined(ASIO_HAS_STD_COROUTINE) +# include <experimental/coroutine> +#endif // defined(ASIO_HAS_STD_COROUTINE) + +#include <utility> +#include "asio/any_io_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_COROUTINE) +using std::coroutine_handle; +using std::suspend_always; +#else // defined(ASIO_HAS_STD_COROUTINE) +using std::experimental::coroutine_handle; +using std::experimental::suspend_always; +#endif // defined(ASIO_HAS_STD_COROUTINE) + +template <typename> class awaitable_thread; +template <typename, typename> class awaitable_frame; + +} // namespace detail + +/// The return type of a coroutine or asynchronous operation. +template <typename T, typename Executor = any_io_executor> +class ASIO_NODISCARD awaitable +{ +public: + /// The type of the awaited value. + typedef T value_type; + + /// The executor type that will be used for the coroutine. + typedef Executor executor_type; + + /// Default constructor. + constexpr awaitable() noexcept + : frame_(nullptr) + { + } + + /// Move constructor. + awaitable(awaitable&& other) noexcept + : frame_(std::exchange(other.frame_, nullptr)) + { + } + + /// Destructor + ~awaitable() + { + if (frame_) + frame_->destroy(); + } + + /// Move assignment. + awaitable& operator=(awaitable&& other) noexcept + { + if (this != &other) + frame_ = std::exchange(other.frame_, nullptr); + return *this; + } + + /// Checks if the awaitable refers to a future result. + bool valid() const noexcept + { + return !!frame_; + } + +#if !defined(GENERATING_DOCUMENTATION) + + // Support for co_await keyword. + bool await_ready() const noexcept + { + return false; + } + + // Support for co_await keyword. + template <class U> + void await_suspend( + detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h) + { + frame_->push_frame(&h.promise()); + } + + // Support for co_await keyword. + T await_resume() + { + return awaitable(static_cast<awaitable&&>(*this)).frame_->get(); + } + +#endif // !defined(GENERATING_DOCUMENTATION) + +private: + template <typename> friend class detail::awaitable_thread; + template <typename, typename> friend class detail::awaitable_frame; + + // Not copy constructible or copy assignable. + awaitable(const awaitable&) = delete; + awaitable& operator=(const awaitable&) = delete; + + // Construct the awaitable from a coroutine's frame object. + explicit awaitable(detail::awaitable_frame<T, Executor>* a) + : frame_(a) + { + } + + detail::awaitable_frame<T, Executor>* frame_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/awaitable.hpp" + +#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_AWAITABLE_HPP diff --git a/3rdparty/asio/include/asio/basic_datagram_socket.hpp b/3rdparty/asio/include/asio/basic_datagram_socket.hpp index a451013fba4..3d72a38475a 100644 --- a/3rdparty/asio/include/asio/basic_datagram_socket.hpp +++ b/3rdparty/asio/include/asio/basic_datagram_socket.hpp @@ -2,7 +2,7 @@ // basic_datagram_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,18 +19,24 @@ #include <cstddef> #include "asio/basic_socket.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/datagram_socket_service.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #include "asio/detail/push_options.hpp" namespace asio { +#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) +#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> +class basic_datagram_socket; + +#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) + /// Provides datagram-oriented socket functionality. /** * The basic_datagram_socket class template provides asynchronous and blocking @@ -39,19 +45,42 @@ namespace asio { * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. + * + * Synchronous @c send, @c send_to, @c receive, @c receive_from, @c connect, + * and @c shutdown operations are thread safe with respect to each other, if + * the underlying operating system calls are also thread safe. This means that + * it is permitted to perform concurrent calls to these synchronous operations + * on a single socket object. Other synchronous operations, such as @c open or + * @c close, are not thread safe. */ -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= datagram_socket_service<Protocol>)> +template <typename Protocol, typename Executor> class basic_datagram_socket - : public basic_socket<Protocol ASIO_SVC_TARG> + : public basic_socket<Protocol, Executor> { +private: + class initiate_async_send; + class initiate_async_send_to; + class initiate_async_receive; + class initiate_async_receive_from; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_datagram_socket<Protocol, Executor1> other; + }; + /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else - typedef typename basic_socket< - Protocol ASIO_SVC_TARG>::native_handle_type native_handle_type; + typedef typename basic_socket<Protocol, + Executor>::native_handle_type native_handle_type; #endif /// The protocol type. @@ -65,12 +94,29 @@ public: * This constructor creates a datagram socket without opening it. The open() * function must be called before data can be sent or received on the socket. * - * @param io_context The io_context object that the datagram socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_datagram_socket(const executor_type& ex) + : basic_socket<Protocol, Executor>(ex) + { + } + + /// Construct a basic_datagram_socket without opening it. + /** + * This constructor creates a datagram socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. */ - explicit basic_datagram_socket(asio::io_context& io_context) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context) + template <typename ExecutionContext> + explicit basic_datagram_socket(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context) { } @@ -78,17 +124,38 @@ public: /** * This constructor creates and opens a datagram socket. * - * @param io_context The io_context object that the datagram socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ - basic_datagram_socket(asio::io_context& io_context, - const protocol_type& protocol) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, protocol) + basic_datagram_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket<Protocol, Executor>(ex, protocol) + { + } + + /// Construct and open a basic_datagram_socket. + /** + * This constructor creates and opens a datagram socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_datagram_socket(ExecutionContext& context, + const protocol_type& protocol, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_socket<Protocol, Executor>(context, protocol) { } @@ -99,18 +166,42 @@ public: * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * - * @param io_context The io_context object that the datagram socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the datagram * socket will be bound. * * @throws asio::system_error Thrown on failure. */ - basic_datagram_socket(asio::io_context& io_context, - const endpoint_type& endpoint) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, endpoint) + basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket<Protocol, Executor>(ex, endpoint) + { + } + + /// Construct a basic_datagram_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a datagram socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the datagram + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_datagram_socket(ExecutionContext& context, + const endpoint_type& endpoint, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, endpoint) { } @@ -119,9 +210,8 @@ public: * This constructor creates a datagram socket object to hold an existing * native socket. * - * @param io_context The io_context object that the datagram socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * @@ -129,14 +219,37 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_datagram_socket(asio::io_context& io_context, + basic_datagram_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol ASIO_SVC_TARG>( - io_context, protocol, native_socket) + : basic_socket<Protocol, Executor>(ex, protocol, native_socket) + { + } + + /// Construct a basic_datagram_socket on an existing native socket. + /** + * This constructor creates a datagram socket object to hold an existing + * native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_datagram_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, protocol, native_socket) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_datagram_socket from another. /** * This constructor moves a datagram socket from one object to another. @@ -145,10 +258,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_context&) constructor. + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. */ - basic_datagram_socket(basic_datagram_socket&& other) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + basic_datagram_socket(basic_datagram_socket&& other) noexcept + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -161,11 +275,12 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_context&) constructor. + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. */ basic_datagram_socket& operator=(basic_datagram_socket&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } @@ -178,13 +293,16 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_context&) constructor. + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - basic_datagram_socket( - basic_datagram_socket<Protocol1 ASIO_SVC_TARG1>&& other, - typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + template <typename Protocol1, typename Executor1> + basic_datagram_socket(basic_datagram_socket<Protocol1, Executor1>&& other, + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value + > = 0) + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -198,17 +316,19 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_context&) constructor. + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - typename enable_if<is_convertible<Protocol1, Protocol>::value, - basic_datagram_socket>::type& operator=( - basic_datagram_socket<Protocol1 ASIO_SVC_TARG1>&& other) + template <typename Protocol1, typename Executor1> + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value, + basic_datagram_socket& + > operator=(basic_datagram_socket<Protocol1, Executor1>&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destroys the socket. /** @@ -245,8 +365,8 @@ public: std::size_t send(const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "send"); return s; } @@ -273,8 +393,8 @@ public: socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, flags, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); asio::detail::throw_error(ec, "send"); return s; } @@ -300,31 +420,37 @@ public: std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().send( - this->get_implementation(), buffers, flags, ec); + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); } /// Start an asynchronous send on a connected socket. /** * This function is used to asynchronously send data on the datagram socket. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they - * remain valid until the handler is called. + * remain valid until the completion handler is called. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected datagram @@ -338,82 +464,92 @@ public: * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, + buffers, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send(this->get_implementation(), - buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send(this->get_implementation(), - buffers, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, + buffers, socket_base::message_flags(0)); } /// Start an asynchronous send on a connected socket. /** * This function is used to asynchronously send data on the datagram socket. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they - * remain valid until the handler is called. + * remain valid until the completion handler is called. * * @param flags Flags specifying how the send call is to be made. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected datagram * socket. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, buffers, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send(this->get_implementation(), - buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send(this->get_implementation(), - buffers, flags, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, buffers, flags); } /// Send a datagram to the specified endpoint. @@ -446,8 +582,8 @@ public: const endpoint_type& destination) { asio::error_code ec; - std::size_t s = this->get_service().send_to( - this->get_implementation(), buffers, destination, 0, ec); + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, 0, ec); asio::detail::throw_error(ec, "send_to"); return s; } @@ -473,8 +609,8 @@ public: const endpoint_type& destination, socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().send_to( - this->get_implementation(), buffers, destination, flags, ec); + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, flags, ec); asio::detail::throw_error(ec, "send_to"); return s; } @@ -500,34 +636,40 @@ public: const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().send_to(this->get_implementation(), + return this->impl_.get_service().send_to(this->impl_.get_implementation(), buffers, destination, flags, ec); } /// Start an asynchronous send. /** * This function is used to asynchronously send a datagram to the specified - * remote endpoint. The function call always returns immediately. + * remote endpoint. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To send a single data buffer use the @ref buffer function as follows: @@ -540,86 +682,94 @@ public: * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send_to(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send_to>(), token, buffers, + destination, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send_to( - this->get_implementation(), buffers, destination, 0, - ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send_to( - this->get_implementation(), buffers, destination, 0, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send_to(this), token, buffers, + destination, socket_base::message_flags(0)); } /// Start an asynchronous send. /** * This function is used to asynchronously send a datagram to the specified - * remote endpoint. The function call always returns immediately. + * remote endpoint. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param flags Flags specifying how the send call is to be made. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send_to(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send_to>(), token, + buffers, destination, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send_to( - this->get_implementation(), buffers, destination, flags, - ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send_to( - this->get_implementation(), buffers, destination, flags, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send_to(this), token, + buffers, destination, flags); } /// Receive some data on a connected socket. @@ -650,8 +800,8 @@ public: std::size_t receive(const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -679,8 +829,8 @@ public: socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, flags, ec); + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -707,31 +857,37 @@ public: std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().receive( - this->get_implementation(), buffers, flags, ec); + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the datagram - * socket. The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected @@ -746,82 +902,92 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive>(), token, + buffers, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive(this->get_implementation(), - buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive(this->get_implementation(), - buffers, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive(this), token, + buffers, socket_base::message_flags(0)); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the datagram - * socket. The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param flags Flags specifying how the receive call is to be made. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected * datagram socket. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive>(), token, buffers, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive(this->get_implementation(), - buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive(this->get_implementation(), - buffers, flags, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive(this), token, buffers, flags); } /// Receive a datagram with the endpoint of the sender. @@ -855,8 +1021,8 @@ public: endpoint_type& sender_endpoint) { asio::error_code ec; - std::size_t s = this->get_service().receive_from( - this->get_implementation(), buffers, sender_endpoint, 0, ec); + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec); asio::detail::throw_error(ec, "receive_from"); return s; } @@ -882,8 +1048,8 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().receive_from( - this->get_implementation(), buffers, sender_endpoint, flags, ec); + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); asio::detail::throw_error(ec, "receive_from"); return s; } @@ -909,36 +1075,42 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().receive_from(this->get_implementation(), - buffers, sender_endpoint, flags, ec); + return this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); } /// Start an asynchronous receive. /** - * This function is used to asynchronously receive a datagram. The function - * call always returns immediately. + * This function is used to asynchronously receive a datagram. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the datagram. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the - * handler is called. + * completion handler is called. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -948,89 +1120,239 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive_from(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive_from>(), token, buffers, + &sender_endpoint, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, 0, - ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, 0, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive_from(this), token, buffers, + &sender_endpoint, socket_base::message_flags(0)); } /// Start an asynchronous receive. /** - * This function is used to asynchronously receive a datagram. The function - * call always returns immediately. + * This function is used to asynchronously receive a datagram. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the datagram. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the - * handler is called. + * completion handler is called. * * @param flags Flags specifying how the receive call is to be made. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive_from(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive_from>(), token, + buffers, &sender_endpoint, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, flags, - ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, flags, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive_from(this), token, + buffers, &sender_endpoint, flags); } + +private: + // Disallow copying and assignment. + basic_datagram_socket(const basic_datagram_socket&) = delete; + basic_datagram_socket& operator=( + const basic_datagram_socket&) = delete; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_datagram_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; + + class initiate_async_send_to + { + public: + typedef Executor executor_type; + + explicit initiate_async_send_to(basic_datagram_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_send_to( + self_->impl_.get_implementation(), buffers, destination, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_datagram_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; + + class initiate_async_receive_from + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_from(basic_datagram_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers, endpoint_type* sender_endpoint, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_receive_from( + self_->impl_.get_implementation(), buffers, *sender_endpoint, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_datagram_socket* self_; + }; }; } // namespace asio diff --git a/3rdparty/asio/include/asio/basic_deadline_timer.hpp b/3rdparty/asio/include/asio/basic_deadline_timer.hpp index 085c8ee1fe8..9343591bf8b 100644 --- a/3rdparty/asio/include/asio/basic_deadline_timer.hpp +++ b/3rdparty/asio/include/asio/basic_deadline_timer.hpp @@ -2,7 +2,7 @@ // basic_deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -21,19 +21,16 @@ || defined(GENERATING_DOCUMENTATION) #include <cstddef> -#include "asio/basic_io_object.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/detail/deadline_timer_service.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" +#include "asio/execution_context.hpp" #include "asio/time_traits.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/deadline_timer_service.hpp" -#else // defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/detail/deadline_timer_service.hpp" -# define ASIO_SVC_T detail::deadline_timer_service<TimeTraits> -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #include "asio/detail/push_options.hpp" namespace asio { @@ -57,7 +54,7 @@ namespace asio { * Performing a blocking wait: * @code * // Construct a timer without setting an expiry time. - * asio::deadline_timer timer(io_context); + * asio::deadline_timer timer(my_context); * * // Set an expiry time relative to now. * timer.expires_from_now(boost::posix_time::seconds(5)); @@ -80,7 +77,7 @@ namespace asio { * ... * * // Construct a timer with an absolute expiry time. - * asio::deadline_timer timer(io_context, + * asio::deadline_timer timer(my_context, * boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); * * // Start an asynchronous wait. @@ -127,14 +124,24 @@ namespace asio { * it contains the value asio::error::operation_aborted. */ template <typename Time, - typename TimeTraits = asio::time_traits<Time> - ASIO_SVC_TPARAM_DEF2(= deadline_timer_service<Time, TimeTraits>)> + typename TimeTraits = asio::time_traits<Time>, + typename Executor = any_io_executor> class basic_deadline_timer - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T> { +private: + class initiate_async_wait; + public: /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; + typedef Executor executor_type; + + /// Rebinds the timer type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The timer type when rebound to the specified executor. + typedef basic_deadline_timer<Time, TimeTraits, Executor1> other; + }; /// The time traits type. typedef TimeTraits traits_type; @@ -151,11 +158,30 @@ public: * expires_at() or expires_from_now() functions must be called to set an * expiry time before the timer can be waited on. * - * @param io_context The io_context object that the timer will use to dispatch - * handlers for any asynchronous operations performed on the timer. + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_deadline_timer(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_from_now() functions must be called to set an + * expiry time before the timer can be waited on. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. */ - explicit basic_deadline_timer(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) + template <typename ExecutionContext> + explicit basic_deadline_timer(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { } @@ -163,18 +189,40 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_context The io_context object that the timer will use to dispatch - * handlers for any asynchronous operations performed on the timer. + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, expressed * as an absolute time. */ - basic_deadline_timer(asio::io_context& io_context, - const time_type& expiry_time) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_deadline_timer(const executor_type& ex, const time_type& expiry_time) + : impl_(0, ex) { asio::error_code ec; - this->get_service().expires_at(this->get_implementation(), expiry_time, ec); + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + template <typename ExecutionContext> + basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_at"); } @@ -182,23 +230,47 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_context The io_context object that the timer will use to dispatch - * handlers for any asynchronous operations performed on the timer. + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, relative to * now. */ - basic_deadline_timer(asio::io_context& io_context, + basic_deadline_timer(const executor_type& ex, const duration_type& expiry_time) - : basic_io_object<ASIO_SVC_T>(io_context) + : impl_(0, ex) { asio::error_code ec; - this->get_service().expires_from_now( - this->get_implementation(), expiry_time, ec); + impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_from_now"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + template <typename ExecutionContext> + basic_deadline_timer(ExecutionContext& context, + const duration_type& expiry_time, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_from_now"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_deadline_timer from another. /** * This constructor moves a timer from one object to another. @@ -207,10 +279,11 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_deadline_timer(io_context&) constructor. + * constructed using the @c basic_deadline_timer(const executor_type&) + * constructor. */ basic_deadline_timer(basic_deadline_timer&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) + : impl_(std::move(other.impl_)) { } @@ -223,14 +296,14 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_deadline_timer(io_context&) constructor. + * constructed using the @c basic_deadline_timer(const executor_type&) + * constructor. */ basic_deadline_timer& operator=(basic_deadline_timer&& other) { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); + impl_ = std::move(other.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destroys the timer. /** @@ -241,45 +314,11 @@ public: { } -#if defined(ASIO_ENABLE_OLD_SERVICES) - // These functions are provided by basic_io_object<>. -#else // defined(ASIO_ENABLE_OLD_SERVICES) -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + const executor_type& get_executor() noexcept { - return basic_io_object<ASIO_SVC_T>::get_executor(); + return impl_.get_executor(); } -#endif // defined(ASIO_ENABLE_OLD_SERVICES) /// Cancel any asynchronous operations that are waiting on the timer. /** @@ -306,7 +345,7 @@ public: std::size_t cancel() { asio::error_code ec; - std::size_t s = this->get_service().cancel(this->get_implementation(), ec); + std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); return s; } @@ -335,7 +374,7 @@ public: */ std::size_t cancel(asio::error_code& ec) { - return this->get_service().cancel(this->get_implementation(), ec); + return impl_.get_service().cancel(impl_.get_implementation(), ec); } /// Cancels one asynchronous operation that is waiting on the timer. @@ -365,8 +404,8 @@ public: std::size_t cancel_one() { asio::error_code ec; - std::size_t s = this->get_service().cancel_one( - this->get_implementation(), ec); + std::size_t s = impl_.get_service().cancel_one( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel_one"); return s; } @@ -397,7 +436,7 @@ public: */ std::size_t cancel_one(asio::error_code& ec) { - return this->get_service().cancel_one(this->get_implementation(), ec); + return impl_.get_service().cancel_one(impl_.get_implementation(), ec); } /// Get the timer's expiry time as an absolute time. @@ -407,7 +446,7 @@ public: */ time_type expires_at() const { - return this->get_service().expires_at(this->get_implementation()); + return impl_.get_service().expires_at(impl_.get_implementation()); } /// Set the timer's expiry time as an absolute time. @@ -435,8 +474,8 @@ public: std::size_t expires_at(const time_type& expiry_time) { asio::error_code ec; - std::size_t s = this->get_service().expires_at( - this->get_implementation(), expiry_time, ec); + std::size_t s = impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_at"); return s; } @@ -466,8 +505,8 @@ public: std::size_t expires_at(const time_type& expiry_time, asio::error_code& ec) { - return this->get_service().expires_at( - this->get_implementation(), expiry_time, ec); + return impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); } /// Get the timer's expiry time relative to now. @@ -477,7 +516,7 @@ public: */ duration_type expires_from_now() const { - return this->get_service().expires_from_now(this->get_implementation()); + return impl_.get_service().expires_from_now(impl_.get_implementation()); } /// Set the timer's expiry time relative to now. @@ -505,8 +544,8 @@ public: std::size_t expires_from_now(const duration_type& expiry_time) { asio::error_code ec; - std::size_t s = this->get_service().expires_from_now( - this->get_implementation(), expiry_time, ec); + std::size_t s = impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_from_now"); return s; } @@ -536,8 +575,8 @@ public: std::size_t expires_from_now(const duration_type& expiry_time, asio::error_code& ec) { - return this->get_service().expires_from_now( - this->get_implementation(), expiry_time, ec); + return impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); } /// Perform a blocking wait on the timer. @@ -550,7 +589,7 @@ public: void wait() { asio::error_code ec; - this->get_service().wait(this->get_implementation(), ec); + impl_.get_service().wait(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "wait"); } @@ -563,65 +602,108 @@ public: */ void wait(asio::error_code& ec) { - this->get_service().wait(this->get_implementation(), ec); + impl_.get_service().wait(impl_.get_implementation(), ec); } /// Start an asynchronous wait on the timer. /** * This function may be used to initiate an asynchronous wait against the - * timer. It always returns immediately. + * timer. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * - * For each call to async_wait(), the supplied handler will be called exactly - * once. The handler will be called when: + * For each call to async_wait(), the completion handler will be called + * exactly once. The completion handler will be called when: * * @li The timer has expired. * * @li The timer was cancelled, in which case the handler is passed the error * code asio::error::operation_aborted. * - * @param handler The handler to be called when the timer expires. Copies - * will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the timer expires. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(ASIO_MOVE_ARG(WaitHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitToken = default_completion_token_t<executor_type>> + auto async_wait( + WaitToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WaitToken, void (asio::error_code)>( + declval<initiate_async_wait>(), token)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WaitHandler. - ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_wait(this->get_implementation(), - ASIO_MOVE_CAST(WaitHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_wait(this->get_implementation(), - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WaitToken, void (asio::error_code)>( + initiate_async_wait(this), token); } + +private: + // Disallow copying and assignment. + basic_deadline_timer(const basic_deadline_timer&) = delete; + basic_deadline_timer& operator=( + const basic_deadline_timer&) = delete; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_deadline_timer* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue<WaitHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_deadline_timer* self_; + }; + + detail::io_object_impl< + detail::deadline_timer_service<TimeTraits>, Executor> impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // defined(ASIO_HAS_BOOST_DATE_TIME) // || defined(GENERATING_DOCUMENTATION) diff --git a/3rdparty/asio/include/asio/basic_file.hpp b/3rdparty/asio/include/asio/basic_file.hpp new file mode 100644 index 00000000000..dbdb6d843d0 --- /dev/null +++ b/3rdparty/asio/include/asio/basic_file.hpp @@ -0,0 +1,824 @@ +// +// basic_file.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BASIC_FILE_HPP +#define ASIO_BASIC_FILE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <string> +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/cstdint.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/post.hpp" +#include "asio/file_base.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_file_service.hpp" +#elif defined(ASIO_HAS_IO_URING) +# include "asio/detail/io_uring_file_service.hpp" +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_FILE_FWD_DECL) +#define ASIO_BASIC_FILE_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Executor = any_io_executor> +class basic_file; + +#endif // !defined(ASIO_BASIC_FILE_FWD_DECL) + +/// Provides file functionality. +/** + * The basic_file class template provides functionality that is common to both + * stream-oriented and random-access files. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <typename Executor> +class basic_file + : public file_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the file type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The file type when rebound to the specified executor. + typedef basic_file<Executor1> other; + }; + + /// The native representation of a file. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef detail::win_iocp_file_service::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IO_URING) + typedef detail::io_uring_file_service::native_handle_type native_handle_type; +#endif + + /// Construct a basic_file without opening it. + /** + * This constructor initialises a file without opening it. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + */ + explicit basic_file(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a basic_file without opening it. + /** + * This constructor initialises a file without opening it. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + */ + template <typename ExecutionContext> + explicit basic_file(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct and open a basic_file. + /** + * This constructor initialises a file and opens it. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + */ + explicit basic_file(const executor_type& ex, + const char* path, file_base::flags open_flags) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_file without opening it. + /** + * This constructor initialises a file and opens it. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + */ + template <typename ExecutionContext> + explicit basic_file(ExecutionContext& context, + const char* path, file_base::flags open_flags, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_file. + /** + * This constructor initialises a file and opens it. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + */ + explicit basic_file(const executor_type& ex, + const std::string& path, file_base::flags open_flags) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), + path.c_str(), open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_file without opening it. + /** + * This constructor initialises a file and opens it. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + */ + template <typename ExecutionContext> + explicit basic_file(ExecutionContext& context, + const std::string& path, file_base::flags open_flags, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), + path.c_str(), open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_file on an existing native file handle. + /** + * This constructor initialises a file object to hold an existing native file. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param native_file A native file handle. + * + * @throws asio::system_error Thrown on failure. + */ + basic_file(const executor_type& ex, const native_handle_type& native_file) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign( + impl_.get_implementation(), native_file, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_file on an existing native file. + /** + * This constructor initialises a file object to hold an existing native file. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param native_file A native file. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_file(ExecutionContext& context, const native_handle_type& native_file, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign( + impl_.get_implementation(), native_file, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Move-construct a basic_file from another. + /** + * This constructor moves a file from one object to another. + * + * @param other The other basic_file object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_file(const executor_type&) constructor. + */ + basic_file(basic_file&& other) noexcept + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_file from another. + /** + * This assignment operator moves a file from one object to another. + * + * @param other The other basic_file object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_file(const executor_type&) constructor. + */ + basic_file& operator=(basic_file&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All files have access to each other's implementations. + template <typename Executor1> + friend class basic_file; + + /// Move-construct a basic_file from a file of another executor type. + /** + * This constructor moves a file from one object to another. + * + * @param other The other basic_file object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_file(const executor_type&) constructor. + */ + template <typename Executor1> + basic_file(basic_file<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_file from a file of another executor type. + /** + * This assignment operator moves a file from one object to another. + * + * @param other The other basic_file object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_file(const executor_type&) constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_file& + > operator=(basic_file<Executor1>&& other) + { + basic_file tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } + + /// Open the file using the specified path. + /** + * This function opens the file so that it will use the specified path. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::stream_file file(my_context); + * file.open("/path/to/my/file", asio::stream_file::read_only); + * @endcode + */ + void open(const char* path, file_base::flags open_flags) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the file using the specified path. + /** + * This function opens the file so that it will use the specified path. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::stream_file file(my_context); + * asio::error_code ec; + * file.open("/path/to/my/file", asio::stream_file::read_only, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID open(const char* path, + file_base::flags open_flags, asio::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Open the file using the specified path. + /** + * This function opens the file so that it will use the specified path. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::stream_file file(my_context); + * file.open("/path/to/my/file", asio::stream_file::read_only); + * @endcode + */ + void open(const std::string& path, file_base::flags open_flags) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), + path.c_str(), open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the file using the specified path. + /** + * This function opens the file so that it will use the specified path. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::stream_file file(my_context); + * asio::error_code ec; + * file.open("/path/to/my/file", asio::stream_file::read_only, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID open(const std::string& path, + file_base::flags open_flags, asio::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), + path.c_str(), open_flags, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assign an existing native file to the file. + /* + * This function opens the file to hold an existing native file. + * + * @param native_file A native file. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_file) + { + asio::error_code ec; + impl_.get_service().assign( + impl_.get_implementation(), native_file, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native file to the file. + /* + * This function opens the file to hold an existing native file. + * + * @param native_file A native file. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const native_handle_type& native_file, + asio::error_code& ec) + { + impl_.get_service().assign( + impl_.get_implementation(), native_file, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the file is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the file. + /** + * This function is used to close the file. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the file. + /** + * This function is used to close the file. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + * + * @par Example + * @code + * asio::stream_file file(my_context); + * ... + * asio::error_code ec; + * file.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native file. + /** + * This function causes all outstanding asynchronous read and write + * operations to finish immediately, and the handlers for cancelled + * operations will be passed the asio::error::operation_aborted error. + * Ownership of the native file is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native file. + /** + * This function causes all outstanding asynchronous read and write + * operations to finish immediately, and the handlers for cancelled + * operations will be passed the asio::error::operation_aborted error. + * Ownership of the native file is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native file representation. + /** + * This function may be used to obtain the underlying representation of the + * file. This is intended to allow access to native file functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the file. + /** + * This function causes all outstanding asynchronous read and write + * operations to finish immediately, and the handlers for cancelled + * operations will be passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls to cancel() will always fail with + * asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using the close() function to + * simultaneously cancel the outstanding operations and close the file. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the file. + /** + * This function causes all outstanding asynchronous read and write + * operations to finish immediately, and the handlers for cancelled + * operations will be passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls to cancel() will always fail with + * asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using the close() function to + * simultaneously cancel the outstanding operations and close the file. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the size of the file. + /** + * This function determines the size of the file, in bytes. + * + * @throws asio::system_error Thrown on failure. + */ + uint64_t size() const + { + asio::error_code ec; + uint64_t s = impl_.get_service().size(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "size"); + return s; + } + + /// Get the size of the file. + /** + * This function determines the size of the file, in bytes. + * + * @param ec Set to indicate what error occurred, if any. + */ + uint64_t size(asio::error_code& ec) const + { + return impl_.get_service().size(impl_.get_implementation(), ec); + } + + /// Alter the size of the file. + /** + * This function resizes the file to the specified size, in bytes. If the + * current file size exceeds @c n then any extra data is discarded. If the + * current size is less than @c n then the file is extended and filled with + * zeroes. + * + * @param n The new size for the file. + * + * @throws asio::system_error Thrown on failure. + */ + void resize(uint64_t n) + { + asio::error_code ec; + impl_.get_service().resize(impl_.get_implementation(), n, ec); + asio::detail::throw_error(ec, "resize"); + } + + /// Alter the size of the file. + /** + * This function resizes the file to the specified size, in bytes. If the + * current file size exceeds @c n then any extra data is discarded. If the + * current size is less than @c n then the file is extended and filled with + * zeroes. + * + * @param n The new size for the file. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID resize(uint64_t n, asio::error_code& ec) + { + impl_.get_service().resize(impl_.get_implementation(), n, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Synchronise the file to disk. + /** + * This function synchronises the file data and metadata to disk. Note that + * the semantics of this synchronisation vary between operation systems. + * + * @throws asio::system_error Thrown on failure. + */ + void sync_all() + { + asio::error_code ec; + impl_.get_service().sync_all(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "sync_all"); + } + + /// Synchronise the file to disk. + /** + * This function synchronises the file data and metadata to disk. Note that + * the semantics of this synchronisation vary between operation systems. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID sync_all(asio::error_code& ec) + { + impl_.get_service().sync_all(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Synchronise the file data to disk. + /** + * This function synchronises the file data to disk. Note that the semantics + * of this synchronisation vary between operation systems. + * + * @throws asio::system_error Thrown on failure. + */ + void sync_data() + { + asio::error_code ec; + impl_.get_service().sync_data(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "sync_data"); + } + + /// Synchronise the file data to disk. + /** + * This function synchronises the file data to disk. Note that the semantics + * of this synchronisation vary between operation systems. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID sync_data(asio::error_code& ec) + { + impl_.get_service().sync_data(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the file, cancelling any outstanding asynchronous + * operations associated with the file as if by calling @c cancel. + */ + ~basic_file() + { + } + +#if defined(ASIO_HAS_IOCP) + detail::io_object_impl<detail::win_iocp_file_service, Executor> impl_; +#elif defined(ASIO_HAS_IO_URING) + detail::io_object_impl<detail::io_uring_file_service, Executor> impl_; +#endif + +private: + // Disallow copying and assignment. + basic_file(const basic_file&) = delete; + basic_file& operator=(const basic_file&) = delete; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_FILE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_FILE_HPP diff --git a/3rdparty/asio/include/asio/basic_io_object.hpp b/3rdparty/asio/include/asio/basic_io_object.hpp index b0ccfcb5293..7e502206ff8 100644 --- a/3rdparty/asio/include/asio/basic_io_object.hpp +++ b/3rdparty/asio/include/asio/basic_io_object.hpp @@ -2,7 +2,7 @@ // basic_io_object.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,7 +22,6 @@ namespace asio { -#if defined(ASIO_HAS_MOVE) namespace detail { // Type trait used to determine whether a service supports move. @@ -45,14 +44,13 @@ namespace detail static_cast<implementation_type*>(0))) == 1; }; } -#endif // defined(ASIO_HAS_MOVE) /// Base class for all I/O objects. /** * @note All I/O objects are non-copyable. However, when using C++0x, certain * I/O objects do support move construction and move assignment. */ -#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +#if defined(GENERATING_DOCUMENTATION) template <typename IoObjectService> #else template <typename IoObjectService, @@ -101,7 +99,7 @@ public: typedef asio::io_context::executor_type executor_type; /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + executor_type get_executor() noexcept { return service_.get_io_context().get_executor(); } @@ -138,6 +136,11 @@ protected: * @note Available only for services that support movability, */ basic_io_object& operator=(basic_io_object&& other); + + /// Perform a converting move-construction of a basic_io_object. + template <typename IoObjectService1> + basic_io_object(IoObjectService1& other_service, + typename IoObjectService1::implementation_type& other_implementation); #endif // defined(GENERATING_DOCUMENTATION) /// Protected destructor to prevent deletion through this type. @@ -185,7 +188,6 @@ private: implementation_type implementation_; }; -#if defined(ASIO_HAS_MOVE) // Specialisation for movable objects. template <typename IoObjectService> class basic_io_object<IoObjectService, true> @@ -208,7 +210,7 @@ public: typedef asio::io_context::executor_type executor_type; - executor_type get_executor() ASIO_NOEXCEPT + executor_type get_executor() noexcept { return service_->get_io_context().get_executor(); } @@ -226,6 +228,16 @@ protected: service_->move_construct(implementation_, other.implementation_); } + template <typename IoObjectService1> + basic_io_object(IoObjectService1& other_service, + typename IoObjectService1::implementation_type& other_implementation) + : service_(&asio::use_service<IoObjectService>( + other_service.get_io_context())) + { + service_->converting_move_construct(implementation_, + other_service, other_implementation); + } + ~basic_io_object() { service_->destroy(implementation_); @@ -266,7 +278,6 @@ private: IoObjectService* service_; implementation_type implementation_; }; -#endif // defined(ASIO_HAS_MOVE) } // namespace asio diff --git a/3rdparty/asio/include/asio/basic_random_access_file.hpp b/3rdparty/asio/include/asio/basic_random_access_file.hpp new file mode 100644 index 00000000000..fe88f420560 --- /dev/null +++ b/3rdparty/asio/include/asio/basic_random_access_file.hpp @@ -0,0 +1,689 @@ +// +// basic_random_access_file.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BASIC_RANDOM_ACCESS_FILE_HPP +#define ASIO_BASIC_RANDOM_ACCESS_FILE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <cstddef> +#include "asio/async_result.hpp" +#include "asio/basic_file.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL) +#define ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Executor = any_io_executor> +class basic_random_access_file; + +#endif // !defined(ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL) + +/// Provides random-access file functionality. +/** + * The basic_random_access_file class template provides asynchronous and + * blocking random-access file functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * Synchronous @c read_some_at and @c write_some_at operations are thread safe + * with respect to each other, if the underlying operating system calls are + * also thread safe. This means that it is permitted to perform concurrent + * calls to these synchronous operations on a single file object. Other + * synchronous operations, such as @c open or @c close, are not thread safe. + */ +template <typename Executor> +class basic_random_access_file + : public basic_file<Executor> +{ +private: + class initiate_async_write_some_at; + class initiate_async_read_some_at; + +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the file type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The file type when rebound to the specified executor. + typedef basic_random_access_file<Executor1> other; + }; + + /// The native representation of a file. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_file<Executor>::native_handle_type native_handle_type; +#endif + + /// Construct a basic_random_access_file without opening it. + /** + * This constructor initialises a file without opening it. The file needs to + * be opened before data can be read from or or written to it. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + */ + explicit basic_random_access_file(const executor_type& ex) + : basic_file<Executor>(ex) + { + } + + /// Construct a basic_random_access_file without opening it. + /** + * This constructor initialises a file without opening it. The file needs to + * be opened before data can be read from or or written to it. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + */ + template <typename ExecutionContext> + explicit basic_random_access_file(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context) + { + } + + /// Construct and open a basic_random_access_file. + /** + * This constructor initialises and opens a file. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + basic_random_access_file(const executor_type& ex, + const char* path, file_base::flags open_flags) + : basic_file<Executor>(ex, path, open_flags) + { + } + + /// Construct and open a basic_random_access_file. + /** + * This constructor initialises and opens a file. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_random_access_file(ExecutionContext& context, + const char* path, file_base::flags open_flags, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context, path, open_flags) + { + } + + /// Construct and open a basic_random_access_file. + /** + * This constructor initialises and opens a file. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + basic_random_access_file(const executor_type& ex, + const std::string& path, file_base::flags open_flags) + : basic_file<Executor>(ex, path, open_flags) + { + } + + /// Construct and open a basic_random_access_file. + /** + * This constructor initialises and opens a file. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_random_access_file(ExecutionContext& context, + const std::string& path, file_base::flags open_flags, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context, path, open_flags) + { + } + + /// Construct a basic_random_access_file on an existing native file. + /** + * This constructor initialises a random-access file object to hold an + * existing native file. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param native_file The new underlying file implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_random_access_file(const executor_type& ex, + const native_handle_type& native_file) + : basic_file<Executor>(ex, native_file) + { + } + + /// Construct a basic_random_access_file on an existing native file. + /** + * This constructor initialises a random-access file object to hold an + * existing native file. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param native_file The new underlying file implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_random_access_file(ExecutionContext& context, + const native_handle_type& native_file, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context, native_file) + { + } + + /// Move-construct a basic_random_access_file from another. + /** + * This constructor moves a random-access file from one object to another. + * + * @param other The other basic_random_access_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_file(const executor_type&) + * constructor. + */ + basic_random_access_file(basic_random_access_file&& other) noexcept + : basic_file<Executor>(std::move(other)) + { + } + + /// Move-assign a basic_random_access_file from another. + /** + * This assignment operator moves a random-access file from one object to + * another. + * + * @param other The other basic_random_access_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_file(const executor_type&) + * constructor. + */ + basic_random_access_file& operator=(basic_random_access_file&& other) + { + basic_file<Executor>::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_random_access_file from a file of another executor + /// type. + /** + * This constructor moves a random-access file from one object to another. + * + * @param other The other basic_random_access_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_file(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_random_access_file(basic_random_access_file<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(std::move(other)) + { + } + + /// Move-assign a basic_random_access_file from a file of another executor + /// type. + /** + * This assignment operator moves a random-access file from one object to + * another. + * + * @param other The other basic_random_access_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_file(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_random_access_file& + > operator=(basic_random_access_file<Executor1>&& other) + { + basic_file<Executor>::operator=(std::move(other)); + return *this; + } + + /// Destroys the file. + /** + * This function destroys the file, cancelling any outstanding asynchronous + * operations associated with the file as if by calling @c cancel. + */ + ~basic_random_access_file() + { + } + + /// Write some data to the handle at the specified offset. + /** + * This function is used to write data to the random-access handle. The + * function call will block until one or more bytes of the data has been + * written successfully, or until an error occurs. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the end of the file was reached. + * + * @note The write_some_at operation may not write all of the data. Consider + * using the @ref write_at function if you need to ensure that all data is + * written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.write_some_at(42, asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence> + std::size_t write_some_at(uint64_t offset, + const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().write_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + asio::detail::throw_error(ec, "write_some_at"); + return s; + } + + /// Write some data to the handle at the specified offset. + /** + * This function is used to write data to the random-access handle. The + * function call will block until one or more bytes of the data has been + * written successfully, or until an error occurs. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not write all of the data to the + * file. Consider using the @ref write_at function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some_at(uint64_t offset, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return this->impl_.get_service().write_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + } + + /// Start an asynchronous write at the specified offset. + /** + * This function is used to asynchronously write data to the random-access + * handle. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note The write operation may not write all of the data to the file. + * Consider using the @ref async_write_at function if you need to ensure that + * all data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_write_some_at(42, asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total + */ + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_write_some_at>(), token, offset, buffers)) + { + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some_at(this), token, offset, buffers); + } + + /// Read some data from the handle at the specified offset. + /** + * This function is used to read data from the random-access handle. The + * function call will block until one or more bytes of data has been read + * successfully, or until an error occurs. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the end of the file was reached. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read_at function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.read_some_at(42, asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence> + std::size_t read_some_at(uint64_t offset, + const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().read_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + asio::detail::throw_error(ec, "read_some_at"); + return s; + } + + /// Read some data from the handle at the specified offset. + /** + * This function is used to read data from the random-access handle. The + * function call will block until one or more bytes of data has been read + * successfully, or until an error occurs. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read_at function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some_at(uint64_t offset, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return this->impl_.get_service().read_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + } + + /// Start an asynchronous read at the specified offset. + /** + * This function is used to asynchronously read data from the random-access + * handle. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read_at function if you need to ensure that + * the requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_read_some_at(42, asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total + */ + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some_at>(), token, offset, buffers)) + { + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some_at(this), token, offset, buffers); + } + +private: + // Disallow copying and assignment. + basic_random_access_file(const basic_random_access_file&) = delete; + basic_random_access_file& operator=( + const basic_random_access_file&) = delete; + + class initiate_async_write_some_at + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some_at(basic_random_access_file* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + uint64_t offset, const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_write_some_at( + self_->impl_.get_implementation(), offset, buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_random_access_file* self_; + }; + + class initiate_async_read_some_at + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some_at(basic_random_access_file* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + uint64_t offset, const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_read_some_at( + self_->impl_.get_implementation(), offset, buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_random_access_file* self_; + }; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_FILE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_RANDOM_ACCESS_FILE_HPP diff --git a/3rdparty/asio/include/asio/basic_raw_socket.hpp b/3rdparty/asio/include/asio/basic_raw_socket.hpp index 30114939359..112090900ce 100644 --- a/3rdparty/asio/include/asio/basic_raw_socket.hpp +++ b/3rdparty/asio/include/asio/basic_raw_socket.hpp @@ -2,7 +2,7 @@ // basic_raw_socket.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,18 +19,24 @@ #include <cstddef> #include "asio/basic_socket.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/raw_socket_service.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #include "asio/detail/push_options.hpp" namespace asio { +#if !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL) +#define ASIO_BASIC_RAW_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> +class basic_raw_socket; + +#endif // !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL) + /// Provides raw-oriented socket functionality. /** * The basic_raw_socket class template provides asynchronous and blocking @@ -39,19 +45,42 @@ namespace asio { * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. + * + * Synchronous @c send, @c send_to, @c receive, @c receive_from, @c connect, + * and @c shutdown operations are thread safe with respect to each other, if + * the underlying operating system calls are also thread safe. This means that + * it is permitted to perform concurrent calls to these synchronous operations + * on a single socket object. Other synchronous operations, such as @c open or + * @c close, are not thread safe. */ -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= raw_socket_service<Protocol>)> +template <typename Protocol, typename Executor> class basic_raw_socket - : public basic_socket<Protocol ASIO_SVC_TARG> + : public basic_socket<Protocol, Executor> { +private: + class initiate_async_send; + class initiate_async_send_to; + class initiate_async_receive; + class initiate_async_receive_from; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_raw_socket<Protocol, Executor1> other; + }; + /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else - typedef typename basic_socket< - Protocol ASIO_SVC_TARG>::native_handle_type native_handle_type; + typedef typename basic_socket<Protocol, + Executor>::native_handle_type native_handle_type; #endif /// The protocol type. @@ -65,12 +94,29 @@ public: * This constructor creates a raw socket without opening it. The open() * function must be called before data can be sent or received on the socket. * - * @param io_context The io_context object that the raw socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. */ - explicit basic_raw_socket(asio::io_context& io_context) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context) + explicit basic_raw_socket(const executor_type& ex) + : basic_socket<Protocol, Executor>(ex) + { + } + + /// Construct a basic_raw_socket without opening it. + /** + * This constructor creates a raw socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template <typename ExecutionContext> + explicit basic_raw_socket(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context) { } @@ -78,17 +124,37 @@ public: /** * This constructor creates and opens a raw socket. * - * @param io_context The io_context object that the raw socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ - basic_raw_socket(asio::io_context& io_context, - const protocol_type& protocol) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, protocol) + basic_raw_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket<Protocol, Executor>(ex, protocol) + { + } + + /// Construct and open a basic_raw_socket. + /** + * This constructor creates and opens a raw socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_raw_socket(ExecutionContext& context, const protocol_type& protocol, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_socket<Protocol, Executor>(context, protocol) { } @@ -99,18 +165,41 @@ public: * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * - * @param io_context The io_context object that the raw socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the raw + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_raw_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket<Protocol, Executor>(ex, endpoint) + { + } + + /// Construct a basic_raw_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a raw socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the raw * socket will be bound. * * @throws asio::system_error Thrown on failure. */ - basic_raw_socket(asio::io_context& io_context, - const endpoint_type& endpoint) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, endpoint) + template <typename ExecutionContext> + basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, endpoint) { } @@ -119,9 +208,8 @@ public: * This constructor creates a raw socket object to hold an existing * native socket. * - * @param io_context The io_context object that the raw socket will use - * to dispatch handlers for any asynchronous operations performed on the - * socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * @@ -129,14 +217,37 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_raw_socket(asio::io_context& io_context, + basic_raw_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol ASIO_SVC_TARG>( - io_context, protocol, native_socket) + : basic_socket<Protocol, Executor>(ex, protocol, native_socket) + { + } + + /// Construct a basic_raw_socket on an existing native socket. + /** + * This constructor creates a raw socket object to hold an existing + * native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_raw_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, protocol, native_socket) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_raw_socket from another. /** * This constructor moves a raw socket from one object to another. @@ -145,10 +256,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_context&) constructor. + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. */ - basic_raw_socket(basic_raw_socket&& other) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + basic_raw_socket(basic_raw_socket&& other) noexcept + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -160,28 +272,34 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_context&) constructor. + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. */ basic_raw_socket& operator=(basic_raw_socket&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } - /// Move-construct a basic_raw_socket from a socket of another protocol type. + /// Move-construct a basic_raw_socket from a socket of another protocol + /// type. /** * This constructor moves a raw socket from one object to another. * - * @param other The other basic_raw_socket object from which the move will - * occur. + * @param other The other basic_raw_socket object from which the move + * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_context&) constructor. + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - basic_raw_socket(basic_raw_socket<Protocol1 ASIO_SVC_TARG1>&& other, - typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + template <typename Protocol1, typename Executor1> + basic_raw_socket(basic_raw_socket<Protocol1, Executor1>&& other, + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value + > = 0) + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -193,17 +311,19 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_context&) constructor. + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - typename enable_if<is_convertible<Protocol1, Protocol>::value, - basic_raw_socket>::type& operator=( - basic_raw_socket<Protocol1 ASIO_SVC_TARG1>&& other) + template <typename Protocol1, typename Executor1> + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value, + basic_raw_socket& + > operator=(basic_raw_socket<Protocol1, Executor1>&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destroys the socket. /** @@ -239,8 +359,8 @@ public: std::size_t send(const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "send"); return s; } @@ -266,8 +386,8 @@ public: socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, flags, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); asio::detail::throw_error(ec, "send"); return s; } @@ -292,31 +412,37 @@ public: std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().send( - this->get_implementation(), buffers, flags, ec); + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); } /// Start an asynchronous send on a connected socket. /** - * This function is used to send data on the raw socket. The function call - * will block until the data has been sent successfully or an error occurs. + * This function is used to asynchronously send data on the raw socket. It is + * an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they - * remain valid until the handler is called. + * remain valid until the completion handler is called. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected raw @@ -330,82 +456,92 @@ public: * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, + buffers, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send(this->get_implementation(), - buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send(this->get_implementation(), - buffers, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, + buffers, socket_base::message_flags(0)); } /// Start an asynchronous send on a connected socket. /** - * This function is used to send data on the raw socket. The function call - * will block until the data has been sent successfully or an error occurs. + * This function is used to asynchronously send data on the raw socket. It is + * an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they - * remain valid until the handler is called. + * remain valid until the completion handler is called. * * @param flags Flags specifying how the send call is to be made. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected raw * socket. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, buffers, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send(this->get_implementation(), - buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send(this->get_implementation(), - buffers, flags, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, buffers, flags); } /// Send raw data to the specified endpoint. @@ -438,8 +574,8 @@ public: const endpoint_type& destination) { asio::error_code ec; - std::size_t s = this->get_service().send_to( - this->get_implementation(), buffers, destination, 0, ec); + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, 0, ec); asio::detail::throw_error(ec, "send_to"); return s; } @@ -465,8 +601,8 @@ public: const endpoint_type& destination, socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().send_to( - this->get_implementation(), buffers, destination, flags, ec); + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, flags, ec); asio::detail::throw_error(ec, "send_to"); return s; } @@ -492,34 +628,40 @@ public: const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().send_to(this->get_implementation(), + return this->impl_.get_service().send_to(this->impl_.get_implementation(), buffers, destination, flags, ec); } /// Start an asynchronous send. /** * This function is used to asynchronously send raw data to the specified - * remote endpoint. The function call always returns immediately. + * remote endpoint. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To send a single data buffer use the @ref buffer function as follows: @@ -532,84 +674,94 @@ public: * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send_to(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send_to>(), token, buffers, + destination, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send_to(this->get_implementation(), - buffers, destination, 0, ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send_to(this->get_implementation(), - buffers, destination, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send_to(this), token, buffers, + destination, socket_base::message_flags(0)); } /// Start an asynchronous send. /** * This function is used to asynchronously send raw data to the specified - * remote endpoint. The function call always returns immediately. + * remote endpoint. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param flags Flags specifying how the send call is to be made. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send_to(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send_to>(), token, + buffers, destination, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send_to( - this->get_implementation(), buffers, destination, flags, - ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send_to( - this->get_implementation(), buffers, destination, flags, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send_to(this), token, + buffers, destination, flags); } /// Receive some data on a connected socket. @@ -640,8 +792,8 @@ public: std::size_t receive(const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -669,8 +821,8 @@ public: socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, flags, ec); + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -697,31 +849,37 @@ public: std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().receive( - this->get_implementation(), buffers, flags, ec); + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the raw - * socket. The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected @@ -736,82 +894,93 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive>(), token, + buffers, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive(this->get_implementation(), - buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive(this->get_implementation(), - buffers, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive(this), token, + buffers, socket_base::message_flags(0)); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the raw - * socket. The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param flags Flags specifying how the receive call is to be made. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected * raw socket. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken + = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive>(), token, buffers, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive(this->get_implementation(), - buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive(this->get_implementation(), - buffers, flags, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive(this), token, buffers, flags); } /// Receive raw data with the endpoint of the sender. @@ -845,8 +1014,8 @@ public: endpoint_type& sender_endpoint) { asio::error_code ec; - std::size_t s = this->get_service().receive_from( - this->get_implementation(), buffers, sender_endpoint, 0, ec); + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec); asio::detail::throw_error(ec, "receive_from"); return s; } @@ -872,8 +1041,8 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().receive_from( - this->get_implementation(), buffers, sender_endpoint, flags, ec); + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); asio::detail::throw_error(ec, "receive_from"); return s; } @@ -899,36 +1068,42 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().receive_from(this->get_implementation(), - buffers, sender_endpoint, flags, ec); + return this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); } /// Start an asynchronous receive. /** - * This function is used to asynchronously receive raw data. The function - * call always returns immediately. + * This function is used to asynchronously receive raw data. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the data. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the - * handler is called. + * completion handler is called. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -938,89 +1113,240 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive_from(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token + = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive_from>(), token, buffers, + &sender_endpoint, socket_base::message_flags(0))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, 0, - ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, 0, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive_from(this), token, buffers, + &sender_endpoint, socket_base::message_flags(0)); } /// Start an asynchronous receive. /** - * This function is used to asynchronously receive raw data. The function - * call always returns immediately. + * This function is used to asynchronously receive raw data. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the data. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the - * handler is called. + * completion handler is called. * * @param flags Flags specifying how the receive call is to be made. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive_from(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken + = default_completion_token_t<executor_type>> + auto async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive_from>(), token, + buffers, &sender_endpoint, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, flags, - ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive_from( - this->get_implementation(), buffers, sender_endpoint, flags, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive_from(this), token, + buffers, &sender_endpoint, flags); } + +private: + // Disallow copying and assignment. + basic_raw_socket(const basic_raw_socket&) = delete; + basic_raw_socket& operator=(const basic_raw_socket&) = delete; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_raw_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; + + class initiate_async_send_to + { + public: + typedef Executor executor_type; + + explicit initiate_async_send_to(basic_raw_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_send_to( + self_->impl_.get_implementation(), buffers, destination, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_raw_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; + + class initiate_async_receive_from + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_from(basic_raw_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers, endpoint_type* sender_endpoint, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_receive_from( + self_->impl_.get_implementation(), buffers, *sender_endpoint, + flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_raw_socket* self_; + }; }; } // namespace asio diff --git a/3rdparty/asio/include/asio/basic_readable_pipe.hpp b/3rdparty/asio/include/asio/basic_readable_pipe.hpp new file mode 100644 index 00000000000..9a5a0653f6b --- /dev/null +++ b/3rdparty/asio/include/asio/basic_readable_pipe.hpp @@ -0,0 +1,626 @@ +// +// basic_readable_pipe.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BASIC_READABLE_PIPE_HPP +#define ASIO_BASIC_READABLE_PIPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PIPE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <string> +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_handle_service.hpp" +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_descriptor_service.hpp" +#else +# include "asio/detail/reactive_descriptor_service.hpp" +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides pipe functionality. +/** + * The basic_readable_pipe class provides a wrapper over pipe + * functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <typename Executor = any_io_executor> +class basic_readable_pipe +{ +private: + class initiate_async_read_some; + +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the pipe type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The pipe type when rebound to the specified executor. + typedef basic_readable_pipe<Executor1> other; + }; + + /// The native representation of a pipe. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef detail::win_iocp_handle_service::native_handle_type + native_handle_type; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef detail::io_uring_descriptor_service::native_handle_type + native_handle_type; +#else + typedef detail::reactive_descriptor_service::native_handle_type + native_handle_type; +#endif + + /// A basic_readable_pipe is always the lowest layer. + typedef basic_readable_pipe lowest_layer_type; + + /// Construct a basic_readable_pipe without opening it. + /** + * This constructor creates a pipe without opening it. + * + * @param ex The I/O executor that the pipe will use, by default, to dispatch + * handlers for any asynchronous operations performed on the pipe. + */ + explicit basic_readable_pipe(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a basic_readable_pipe without opening it. + /** + * This constructor creates a pipe without opening it. + * + * @param context An execution context which provides the I/O executor that + * the pipe will use, by default, to dispatch handlers for any asynchronous + * operations performed on the pipe. + */ + template <typename ExecutionContext> + explicit basic_readable_pipe(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct a basic_readable_pipe on an existing native pipe. + /** + * This constructor creates a pipe object to hold an existing native + * pipe. + * + * @param ex The I/O executor that the pipe will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * pipe. + * + * @param native_pipe A native pipe. + * + * @throws asio::system_error Thrown on failure. + */ + basic_readable_pipe(const executor_type& ex, + const native_handle_type& native_pipe) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_pipe, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_readable_pipe on an existing native pipe. + /** + * This constructor creates a pipe object to hold an existing native + * pipe. + * + * @param context An execution context which provides the I/O executor that + * the pipe will use, by default, to dispatch handlers for any + * asynchronous operations performed on the pipe. + * + * @param native_pipe A native pipe. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_readable_pipe(ExecutionContext& context, + const native_handle_type& native_pipe, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_pipe, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Move-construct a basic_readable_pipe from another. + /** + * This constructor moves a pipe from one object to another. + * + * @param other The other basic_readable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_readable_pipe(const executor_type&) + * constructor. + */ + basic_readable_pipe(basic_readable_pipe&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_readable_pipe from another. + /** + * This assignment operator moves a pipe from one object to another. + * + * @param other The other basic_readable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_readable_pipe(const executor_type&) + * constructor. + */ + basic_readable_pipe& operator=(basic_readable_pipe&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All pipes have access to each other's implementations. + template <typename Executor1> + friend class basic_readable_pipe; + + /// Move-construct a basic_readable_pipe from a pipe of another executor type. + /** + * This constructor moves a pipe from one object to another. + * + * @param other The other basic_readable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_readable_pipe(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_readable_pipe(basic_readable_pipe<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_readable_pipe from a pipe of another executor type. + /** + * This assignment operator moves a pipe from one object to another. + * + * @param other The other basic_readable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_readable_pipe(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_readable_pipe& + > operator=(basic_readable_pipe<Executor1>&& other) + { + basic_readable_pipe tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } + + /// Destroys the pipe. + /** + * This function destroys the pipe, cancelling any outstanding + * asynchronous wait operations associated with the pipe as if by + * calling @c cancel. + */ + ~basic_readable_pipe() + { + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_readable_pipe cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_readable_pipe cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native pipe to the pipe. + /* + * This function opens the pipe to hold an existing native pipe. + * + * @param native_pipe A native pipe. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_pipe) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native pipe to the pipe. + /* + * This function opens the pipe to hold an existing native pipe. + * + * @param native_pipe A native pipe. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe, + asio::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the pipe is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the pipe. + /** + * This function is used to close the pipe. Any asynchronous read operations + * will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the pipe. + /** + * This function is used to close the pipe. Any asynchronous read operations + * will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native pipe. + /** + * This function causes all outstanding asynchronous read operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native pipe is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native pipe. + /** + * This function causes all outstanding asynchronous read operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native pipe is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native pipe representation. + /** + * This function may be used to obtain the underlying representation of the + * pipe. This is intended to allow access to native pipe + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the pipe. + /** + * This function causes all outstanding asynchronous read operations to finish + * immediately, and the handlers for cancelled operations will be passed the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the pipe. + /** + * This function causes all outstanding asynchronous read operations to finish + * immediately, and the handlers for cancelled operations will be passed the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Read some data from the pipe. + /** + * This function is used to read data from the pipe. The function call will + * block until one or more bytes of data has been read successfully, or until + * an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * basic_readable_pipe.read_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the pipe. + /** + * This function is used to read data from the pipe. The function call will + * block until one or more bytes of data has been read successfully, or until + * an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the pipe. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * basic_readable_pipe.async_read_some( + * asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some>(), token, buffers)) + { + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some(this), token, buffers); + } + +private: + // Disallow copying and assignment. + basic_readable_pipe(const basic_readable_pipe&) = delete; + basic_readable_pipe& operator=(const basic_readable_pipe&) = delete; + + class initiate_async_read_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_readable_pipe* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_readable_pipe* self_; + }; + +#if defined(ASIO_HAS_IOCP) + detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_; +#else + detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_; +#endif +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PIPE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_READABLE_PIPE_HPP diff --git a/3rdparty/asio/include/asio/basic_seq_packet_socket.hpp b/3rdparty/asio/include/asio/basic_seq_packet_socket.hpp index ca992eceeee..cf2a4b6ad71 100644 --- a/3rdparty/asio/include/asio/basic_seq_packet_socket.hpp +++ b/3rdparty/asio/include/asio/basic_seq_packet_socket.hpp @@ -2,7 +2,7 @@ // basic_seq_packet_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,14 +22,19 @@ #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/seq_packet_socket_service.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #include "asio/detail/push_options.hpp" namespace asio { +#if !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL) +#define ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> +class basic_seq_packet_socket; + +#endif // !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL) + /// Provides sequenced packet socket functionality. /** * The basic_seq_packet_socket class template provides asynchronous and blocking @@ -38,19 +43,40 @@ namespace asio { * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. + * + * Synchronous @c send, @c receive, @c connect, and @c shutdown operations are + * thread safe with respect to each other, if the underlying operating system + * calls are also thread safe. This means that it is permitted to perform + * concurrent calls to these synchronous operations on a single socket object. + * Other synchronous operations, such as @c open or @c close, are not thread + * safe. */ -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= seq_packet_socket_service<Protocol>)> +template <typename Protocol, typename Executor> class basic_seq_packet_socket - : public basic_socket<Protocol ASIO_SVC_TARG> + : public basic_socket<Protocol, Executor> { +private: + class initiate_async_send; + class initiate_async_receive_with_flags; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_seq_packet_socket<Protocol, Executor1> other; + }; + /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else - typedef typename basic_socket< - Protocol ASIO_SVC_TARG>::native_handle_type native_handle_type; + typedef typename basic_socket<Protocol, + Executor>::native_handle_type native_handle_type; #endif /// The protocol type. @@ -65,12 +91,30 @@ public: * socket needs to be opened and then connected or accepted before data can * be sent or received on it. * - * @param io_context The io_context object that the sequenced packet socket - * will use to dispatch handlers for any asynchronous operations performed on - * the socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. */ - explicit basic_seq_packet_socket(asio::io_context& io_context) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context) + explicit basic_seq_packet_socket(const executor_type& ex) + : basic_socket<Protocol, Executor>(ex) + { + } + + /// Construct a basic_seq_packet_socket without opening it. + /** + * This constructor creates a sequenced packet socket without opening it. The + * socket needs to be opened and then connected or accepted before data can + * be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template <typename ExecutionContext> + explicit basic_seq_packet_socket(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context) { } @@ -80,17 +124,41 @@ public: * needs to be connected or accepted before data can be sent or received on * it. * - * @param io_context The io_context object that the sequenced packet socket - * will use to dispatch handlers for any asynchronous operations performed on - * the socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ - basic_seq_packet_socket(asio::io_context& io_context, + basic_seq_packet_socket(const executor_type& ex, const protocol_type& protocol) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, protocol) + : basic_socket<Protocol, Executor>(ex, protocol) + { + } + + /// Construct and open a basic_seq_packet_socket. + /** + * This constructor creates and opens a sequenced_packet socket. The socket + * needs to be connected or accepted before data can be sent or received on + * it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_seq_packet_socket(ExecutionContext& context, + const protocol_type& protocol, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_socket<Protocol, Executor>(context, protocol) { } @@ -101,18 +169,43 @@ public: * it bound to the specified endpoint on the local machine. The protocol used * is the protocol associated with the given endpoint. * - * @param io_context The io_context object that the sequenced packet socket - * will use to dispatch handlers for any asynchronous operations performed on - * the socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the sequenced * packet socket will be bound. * * @throws asio::system_error Thrown on failure. */ - basic_seq_packet_socket(asio::io_context& io_context, + basic_seq_packet_socket(const executor_type& ex, const endpoint_type& endpoint) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, endpoint) + : basic_socket<Protocol, Executor>(ex, endpoint) + { + } + + /// Construct a basic_seq_packet_socket, opening it and binding it to the + /// given local endpoint. + /** + * This constructor creates a sequenced packet socket and automatically opens + * it bound to the specified endpoint on the local machine. The protocol used + * is the protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the sequenced + * packet socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_seq_packet_socket(ExecutionContext& context, + const endpoint_type& endpoint, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, endpoint) { } @@ -121,9 +214,8 @@ public: * This constructor creates a sequenced packet socket object to hold an * existing native socket. * - * @param io_context The io_context object that the sequenced packet socket - * will use to dispatch handlers for any asynchronous operations performed on - * the socket. + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * @@ -131,14 +223,37 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_seq_packet_socket(asio::io_context& io_context, + basic_seq_packet_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol ASIO_SVC_TARG>( - io_context, protocol, native_socket) + : basic_socket<Protocol, Executor>(ex, protocol, native_socket) + { + } + + /// Construct a basic_seq_packet_socket on an existing native socket. + /** + * This constructor creates a sequenced packet socket object to hold an + * existing native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_seq_packet_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, protocol, native_socket) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_seq_packet_socket from another. /** * This constructor moves a sequenced packet socket from one object to @@ -148,10 +263,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_context&) constructor. + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. */ - basic_seq_packet_socket(basic_seq_packet_socket&& other) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + basic_seq_packet_socket(basic_seq_packet_socket&& other) noexcept + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -164,11 +280,12 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_context&) constructor. + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. */ basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } @@ -182,13 +299,16 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_context&) constructor. + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - basic_seq_packet_socket( - basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1>&& other, - typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + template <typename Protocol1, typename Executor1> + basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other, + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value + > = 0) + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -202,17 +322,19 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_context&) constructor. + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - typename enable_if<is_convertible<Protocol1, Protocol>::value, - basic_seq_packet_socket>::type& operator=( - basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1>&& other) + template <typename Protocol1, typename Executor1> + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value, + basic_seq_packet_socket& + > operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destroys the socket. /** @@ -251,8 +373,8 @@ public: socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, flags, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); asio::detail::throw_error(ec, "send"); return s; } @@ -279,33 +401,39 @@ public: std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().send( - this->get_implementation(), buffers, flags, ec); + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); } /// Start an asynchronous send. /** * This function is used to asynchronously send data on the sequenced packet - * socket. The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they - * remain valid until the handler is called. + * remain valid until the completion handler is called. * * @param flags Flags specifying how the send call is to be made. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To send a single data buffer use the @ref buffer function as follows: @@ -315,30 +443,33 @@ public: * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken + = default_completion_token_t<executor_type>> + auto async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token + = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, buffers, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send(this->get_implementation(), - buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send(this->get_implementation(), - buffers, flags, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, buffers, flags); } /// Receive some data on the socket. @@ -375,13 +506,8 @@ public: socket_base::message_flags& out_flags) { asio::error_code ec; -#if defined(ASIO_ENABLE_OLD_SERVICES) - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, 0, out_flags, ec); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - std::size_t s = this->get_service().receive_with_flags( - this->get_implementation(), buffers, 0, out_flags, ec); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + std::size_t s = this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, 0, out_flags, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -427,13 +553,8 @@ public: socket_base::message_flags& out_flags) { asio::error_code ec; -#if defined(ASIO_ENABLE_OLD_SERVICES) - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, in_flags, out_flags, ec); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - std::size_t s = this->get_service().receive_with_flags( - this->get_implementation(), buffers, in_flags, out_flags, ec); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + std::size_t s = this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, in_flags, out_flags, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -466,42 +587,43 @@ public: socket_base::message_flags in_flags, socket_base::message_flags& out_flags, asio::error_code& ec) { -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().receive(this->get_implementation(), - buffers, in_flags, out_flags, ec); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().receive_with_flags(this->get_implementation(), - buffers, in_flags, out_flags, ec); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, in_flags, out_flags, ec); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive data from the sequenced - * packet socket. The function call always returns immediately. + * packet socket. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param out_flags Once the asynchronous operation completes, contains flags * associated with the received data. For example, if the * socket_base::message_end_of_record bit is set then the received data marks * the end of a record. The caller must guarantee that the referenced - * variable remains valid until the handler is called. + * variable remains valid until the completion handler is called. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -512,43 +634,45 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, socket_base::message_flags& out_flags, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive_with_flags>(), token, + buffers, socket_base::message_flags(0), &out_flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive( - this->get_implementation(), buffers, 0, out_flags, - ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive_with_flags( - this->get_implementation(), buffers, 0, out_flags, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive_with_flags(this), token, + buffers, socket_base::message_flags(0), &out_flags); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive data from the sequenced - * data socket. The function call always returns immediately. + * data socket. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param in_flags Flags specifying how the receive call is to be made. * @@ -556,19 +680,24 @@ public: * associated with the received data. For example, if the * socket_base::message_end_of_record bit is set then the received data marks * the end of a record. The caller must guarantee that the referenced - * variable remains valid until the handler is called. + * variable remains valid until the completion handler is called. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -581,34 +710,110 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, socket_base::message_flags in_flags, socket_base::message_flags& out_flags, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive_with_flags>(), + token, buffers, in_flags, &out_flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive( - this->get_implementation(), buffers, in_flags, out_flags, - ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive_with_flags( - this->get_implementation(), buffers, in_flags, out_flags, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive_with_flags(this), + token, buffers, in_flags, &out_flags); } + +private: + // Disallow copying and assignment. + basic_seq_packet_socket(const basic_seq_packet_socket&) = delete; + basic_seq_packet_socket& operator=( + const basic_seq_packet_socket&) = delete; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_seq_packet_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_seq_packet_socket* self_; + }; + + class initiate_async_receive_with_flags + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags* out_flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_receive_with_flags( + self_->impl_.get_implementation(), buffers, in_flags, + *out_flags, handler2.value, self_->impl_.get_executor()); + } + + private: + basic_seq_packet_socket* self_; + }; }; } // namespace asio diff --git a/3rdparty/asio/include/asio/basic_serial_port.hpp b/3rdparty/asio/include/asio/basic_serial_port.hpp index b6ac51ebb99..8fa66c0b0d7 100644 --- a/3rdparty/asio/include/asio/basic_serial_port.hpp +++ b/3rdparty/asio/include/asio/basic_serial_port.hpp @@ -2,7 +2,7 @@ // basic_serial_port.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -18,18 +18,26 @@ #include "asio/detail/config.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) - #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #include <string> -#include "asio/basic_io_object.hpp" +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" #include "asio/error.hpp" +#include "asio/execution_context.hpp" #include "asio/serial_port_base.hpp" -#include "asio/serial_port_service.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_serial_port_service.hpp" +#else +# include "asio/detail/posix_serial_port_service.hpp" +#endif #include "asio/detail/push_options.hpp" @@ -37,34 +45,75 @@ namespace asio { /// Provides serial port functionality. /** - * The basic_serial_port class template provides functionality that is common - * to all serial ports. + * The basic_serial_port class provides a wrapper over serial port + * functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename SerialPortService = serial_port_service> +template <typename Executor = any_io_executor> class basic_serial_port - : public basic_io_object<SerialPortService>, - public serial_port_base + : public serial_port_base { +private: + class initiate_async_write_some; + class initiate_async_read_some; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the serial port type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The serial port type when rebound to the specified executor. + typedef basic_serial_port<Executor1> other; + }; + /// The native representation of a serial port. - typedef typename SerialPortService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef detail::win_iocp_serial_port_service::native_handle_type + native_handle_type; +#else + typedef detail::posix_serial_port_service::native_handle_type + native_handle_type; +#endif + + /// A basic_basic_serial_port is always the lowest layer. + typedef basic_serial_port lowest_layer_type; - /// A basic_serial_port is always the lowest layer. - typedef basic_serial_port<SerialPortService> lowest_layer_type; + /// Construct a basic_serial_port without opening it. + /** + * This constructor creates a serial port without opening it. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + */ + explicit basic_serial_port(const executor_type& ex) + : impl_(0, ex) + { + } /// Construct a basic_serial_port without opening it. /** * This constructor creates a serial port without opening it. * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. */ - explicit basic_serial_port(asio::io_context& io_context) - : basic_io_object<SerialPortService>(io_context) + template <typename ExecutionContext> + explicit basic_serial_port(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) { } @@ -73,18 +122,18 @@ public: * This constructor creates and opens a serial port for the specified device * name. * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. * * @param device The platform-specific device name for this serial * port. */ - explicit basic_serial_port(asio::io_context& io_context, - const char* device) - : basic_io_object<SerialPortService>(io_context) + basic_serial_port(const executor_type& ex, const char* device) + : impl_(0, ex) { asio::error_code ec; - this->get_service().open(this->get_implementation(), device, ec); + impl_.get_service().open(impl_.get_implementation(), device, ec); asio::detail::throw_error(ec, "open"); } @@ -93,18 +142,66 @@ public: * This constructor creates and opens a serial port for the specified device * name. * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. * * @param device The platform-specific device name for this serial * port. */ - explicit basic_serial_port(asio::io_context& io_context, - const std::string& device) - : basic_io_object<SerialPortService>(io_context) + template <typename ExecutionContext> + basic_serial_port(ExecutionContext& context, const char* device, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().open(this->get_implementation(), device, ec); + impl_.get_service().open(impl_.get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + basic_serial_port(const executor_type& ex, const std::string& device) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + template <typename ExecutionContext> + basic_serial_port(ExecutionContext& context, const std::string& device, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); asio::detail::throw_error(ec, "open"); } @@ -113,24 +210,51 @@ public: * This constructor creates a serial port object to hold an existing native * serial port. * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. * * @param native_serial_port A native serial port. * * @throws asio::system_error Thrown on failure. */ - basic_serial_port(asio::io_context& io_context, + basic_serial_port(const executor_type& ex, const native_handle_type& native_serial_port) - : basic_io_object<SerialPortService>(io_context) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_serial_port on an existing native serial port. + /** + * This constructor creates a serial port object to hold an existing native + * serial port. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param native_serial_port A native serial port. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_serial_port(ExecutionContext& context, + const native_handle_type& native_serial_port, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), native_serial_port, ec); asio::detail::throw_error(ec, "assign"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_serial_port from another. /** * This constructor moves a serial port from one object to another. @@ -139,11 +263,11 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_serial_port(io_context&) constructor. + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. */ basic_serial_port(basic_serial_port&& other) - : basic_io_object<SerialPortService>( - ASIO_MOVE_CAST(basic_serial_port)(other)) + : impl_(std::move(other.impl_)) { } @@ -155,15 +279,79 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_serial_port(io_context&) constructor. + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. */ basic_serial_port& operator=(basic_serial_port&& other) { - basic_io_object<SerialPortService>::operator=( - ASIO_MOVE_CAST(basic_serial_port)(other)); + impl_ = std::move(other.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + // All serial ports have access to each other's implementations. + template <typename Executor1> + friend class basic_serial_port; + + /// Move-construct a basic_serial_port from a serial port of another executor + /// type. + /** + * This constructor moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_serial_port(basic_serial_port<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_serial_port from a serial port of another executor + /// type. + /** + * This assignment operator moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_serial_port& + > operator=(basic_serial_port<Executor1>&& other) + { + basic_serial_port tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } + + /// Destroys the serial port. + /** + * This function destroys the serial port, cancelling any outstanding + * asynchronous wait operations associated with the serial port as if by + * calling @c cancel. + */ + ~basic_serial_port() + { + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } /// Get a reference to the lowest layer. /** @@ -204,7 +392,7 @@ public: void open(const std::string& device) { asio::error_code ec; - this->get_service().open(this->get_implementation(), device, ec); + impl_.get_service().open(impl_.get_implementation(), device, ec); asio::detail::throw_error(ec, "open"); } @@ -220,7 +408,7 @@ public: ASIO_SYNC_OP_VOID open(const std::string& device, asio::error_code& ec) { - this->get_service().open(this->get_implementation(), device, ec); + impl_.get_service().open(impl_.get_implementation(), device, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -235,7 +423,7 @@ public: void assign(const native_handle_type& native_serial_port) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), native_serial_port, ec); asio::detail::throw_error(ec, "assign"); } @@ -251,7 +439,7 @@ public: ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, asio::error_code& ec) { - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), native_serial_port, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -259,7 +447,7 @@ public: /// Determine whether the serial port is open. bool is_open() const { - return this->get_service().is_open(this->get_implementation()); + return impl_.get_service().is_open(impl_.get_implementation()); } /// Close the serial port. @@ -273,7 +461,7 @@ public: void close() { asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "close"); } @@ -287,7 +475,7 @@ public: */ ASIO_SYNC_OP_VOID close(asio::error_code& ec) { - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -299,7 +487,7 @@ public: */ native_handle_type native_handle() { - return this->get_service().native_handle(this->get_implementation()); + return impl_.get_service().native_handle(impl_.get_implementation()); } /// Cancel all asynchronous operations associated with the serial port. @@ -313,7 +501,7 @@ public: void cancel() { asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); } @@ -327,7 +515,7 @@ public: */ ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) { - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -341,7 +529,7 @@ public: void send_break() { asio::error_code ec; - this->get_service().send_break(this->get_implementation(), ec); + impl_.get_service().send_break(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "send_break"); } @@ -354,7 +542,7 @@ public: */ ASIO_SYNC_OP_VOID send_break(asio::error_code& ec) { - this->get_service().send_break(this->get_implementation(), ec); + impl_.get_service().send_break(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -377,7 +565,7 @@ public: void set_option(const SettableSerialPortOption& option) { asio::error_code ec; - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "set_option"); } @@ -400,7 +588,7 @@ public: ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, asio::error_code& ec) { - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -421,10 +609,10 @@ public: * asio::serial_port_base::character_size */ template <typename GettableSerialPortOption> - void get_option(GettableSerialPortOption& option) + void get_option(GettableSerialPortOption& option) const { asio::error_code ec; - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "get_option"); } @@ -446,9 +634,9 @@ public: */ template <typename GettableSerialPortOption> ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, - asio::error_code& ec) + asio::error_code& ec) const { - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -473,7 +661,7 @@ public: * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code - * serial_port.write_some(asio::buffer(data, size)); + * basic_serial_port.write_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or @@ -483,8 +671,8 @@ public: std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().write_some( - this->get_implementation(), buffers, ec); + std::size_t s = impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); asio::detail::throw_error(ec, "write_some"); return s; } @@ -509,31 +697,37 @@ public: std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().write_some( - this->get_implementation(), buffers, ec); + return impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the serial port. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be written to the serial port. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -542,24 +736,36 @@ public: * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code - * serial_port.async_write_some(asio::buffer(data, size), handler); + * basic_serial_port.async_write_some( + * asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_write_some>(), token, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - return this->get_service().async_write_some(this->get_implementation(), - buffers, ASIO_MOVE_CAST(WriteHandler)(handler)); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some(this), token, buffers); } /// Read some data from the serial port. @@ -584,7 +790,7 @@ public: * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code - * serial_port.read_some(asio::buffer(data, size)); + * basic_serial_port.read_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or @@ -594,8 +800,8 @@ public: std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().read_some( - this->get_implementation(), buffers, ec); + std::size_t s = impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); asio::detail::throw_error(ec, "read_some"); return s; } @@ -621,31 +827,37 @@ public: std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().read_some( - this->get_implementation(), buffers, ec); + return impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the serial port. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -655,25 +867,114 @@ public: * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code - * serial_port.async_read_some(asio::buffer(data, size), handler); + * basic_serial_port.async_read_some( + * asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some>(), token, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - return this->get_service().async_read_some(this->get_implementation(), - buffers, ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some(this), token, buffers); } + +private: + // Disallow copying and assignment. + basic_serial_port(const basic_serial_port&) = delete; + basic_serial_port& operator=(const basic_serial_port&) = delete; + + class initiate_async_write_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_serial_port* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_serial_port* self_; + }; + + class initiate_async_read_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_serial_port* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_serial_port* self_; + }; + +#if defined(ASIO_HAS_IOCP) + detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_; +#else + detail::io_object_impl<detail::posix_serial_port_service, Executor> impl_; +#endif }; } // namespace asio @@ -683,6 +984,4 @@ public: #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_BASIC_SERIAL_PORT_HPP diff --git a/3rdparty/asio/include/asio/basic_signal_set.hpp b/3rdparty/asio/include/asio/basic_signal_set.hpp index 6f1d07ed796..bf74c39b3a8 100644 --- a/3rdparty/asio/include/asio/basic_signal_set.hpp +++ b/3rdparty/asio/include/asio/basic_signal_set.hpp @@ -2,7 +2,7 @@ // basic_signal_set.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,13 +17,17 @@ #include "asio/detail/config.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include "asio/basic_io_object.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/signal_set_service.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" #include "asio/error.hpp" -#include "asio/signal_set_service.hpp" +#include "asio/execution_context.hpp" +#include "asio/signal_set_base.hpp" #include "asio/detail/push_options.hpp" @@ -31,10 +35,8 @@ namespace asio { /// Provides signal functionality. /** - * The basic_signal_set class template provides the ability to perform an - * asynchronous wait for one or more signals to occur. - * - * Most applications will use the asio::signal_set typedef. + * The basic_signal_set class provides the ability to perform an asynchronous + * wait for one or more signals to occur. * * @par Thread Safety * @e Distinct @e objects: Safe.@n @@ -56,7 +58,7 @@ namespace asio { * ... * * // Construct a signal set registered for process termination. - * asio::signal_set signals(io_context, SIGINT, SIGTERM); + * asio::signal_set signals(my_context, SIGINT, SIGTERM); * * // Start an asynchronous wait for one of the signals to occur. * signals.async_wait(handler); @@ -91,41 +93,101 @@ namespace asio { * that any signals registered using signal_set objects are unblocked in at * least one thread. */ -template <typename SignalSetService = signal_set_service> -class basic_signal_set - : public basic_io_object<SignalSetService> +template <typename Executor = any_io_executor> +class basic_signal_set : public signal_set_base { +private: + class initiate_async_wait; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the signal set type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The signal set type when rebound to the specified executor. + typedef basic_signal_set<Executor1> other; + }; + + /// Construct a signal set without adding any signals. + /** + * This constructor creates a signal set without registering for any signals. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + */ + explicit basic_signal_set(const executor_type& ex) + : impl_(0, ex) + { + } + /// Construct a signal set without adding any signals. /** * This constructor creates a signal set without registering for any signals. * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + */ + template <typename ExecutionContext> + explicit basic_signal_set(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct a signal set and add one signal. + /** + * This constructor creates a signal set and registers for one signal. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + * + * @param signal_number_1 The signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(ex); + * signals.add(signal_number_1); @endcode */ - explicit basic_signal_set(asio::io_context& io_context) - : basic_io_object<SignalSetService>(io_context) + basic_signal_set(const executor_type& ex, int signal_number_1) + : impl_(0, ex) { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); } /// Construct a signal set and add one signal. /** * This constructor creates a signal set and registers for one signal. * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. * * @param signal_number_1 The signal number to be added. * * @note This constructor is equivalent to performing: - * @code asio::signal_set signals(io_context); + * @code asio::signal_set signals(context); * signals.add(signal_number_1); @endcode */ - basic_signal_set(asio::io_context& io_context, int signal_number_1) - : basic_io_object<SignalSetService>(io_context) + template <typename ExecutionContext> + basic_signal_set(ExecutionContext& context, int signal_number_1, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number_1, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); asio::detail::throw_error(ec, "add"); } @@ -133,26 +195,60 @@ public: /** * This constructor creates a signal set and registers for two signals. * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. * * @param signal_number_1 The first signal number to be added. * * @param signal_number_2 The second signal number to be added. * * @note This constructor is equivalent to performing: - * @code asio::signal_set signals(io_context); + * @code asio::signal_set signals(ex); * signals.add(signal_number_1); * signals.add(signal_number_2); @endcode */ - basic_signal_set(asio::io_context& io_context, int signal_number_1, + basic_signal_set(const executor_type& ex, int signal_number_1, int signal_number_2) - : basic_io_object<SignalSetService>(io_context) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add two signals. + /** + * This constructor creates a signal set and registers for two signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); @endcode + */ + template <typename ExecutionContext> + basic_signal_set(ExecutionContext& context, int signal_number_1, + int signal_number_2, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number_1, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); asio::detail::throw_error(ec, "add"); - this->get_service().add(this->get_implementation(), signal_number_2, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); asio::detail::throw_error(ec, "add"); } @@ -160,8 +256,9 @@ public: /** * This constructor creates a signal set and registers for three signals. * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. * * @param signal_number_1 The first signal number to be added. * @@ -170,24 +267,78 @@ public: * @param signal_number_3 The third signal number to be added. * * @note This constructor is equivalent to performing: - * @code asio::signal_set signals(io_context); + * @code asio::signal_set signals(ex); * signals.add(signal_number_1); * signals.add(signal_number_2); * signals.add(signal_number_3); @endcode */ - basic_signal_set(asio::io_context& io_context, int signal_number_1, + basic_signal_set(const executor_type& ex, int signal_number_1, int signal_number_2, int signal_number_3) - : basic_io_object<SignalSetService>(io_context) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add three signals. + /** + * This constructor creates a signal set and registers for three signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @param signal_number_3 The third signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); + * signals.add(signal_number_3); @endcode + */ + template <typename ExecutionContext> + basic_signal_set(ExecutionContext& context, int signal_number_1, + int signal_number_2, int signal_number_3, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number_1, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); asio::detail::throw_error(ec, "add"); - this->get_service().add(this->get_implementation(), signal_number_2, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); asio::detail::throw_error(ec, "add"); - this->get_service().add(this->get_implementation(), signal_number_3, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); asio::detail::throw_error(ec, "add"); } + /// Destroys the signal set. + /** + * This function destroys the signal set, cancelling any outstanding + * asynchronous wait operations associated with the signal set as if by + * calling @c cancel. + */ + ~basic_signal_set() + { + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } + /// Add a signal to a signal_set. /** * This function adds the specified signal to the set. It has no effect if the @@ -200,7 +351,7 @@ public: void add(int signal_number) { asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number, ec); asio::detail::throw_error(ec, "add"); } @@ -213,9 +364,62 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - ASIO_SYNC_OP_VOID add(int signal_number, asio::error_code& ec) + ASIO_SYNC_OP_VOID add(int signal_number, + asio::error_code& ec) + { + impl_.get_service().add(impl_.get_implementation(), signal_number, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Add a signal to a signal_set with the specified flags. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * Flags other than flags::dont_care require OS support for the @c sigaction + * call, and this function will fail with @c error::operation_not_supported if + * this is unavailable. + * + * The specified flags will conflict with a prior, active registration of the + * same signal, if either specified a flags value other than flags::dont_care. + * In this case, the @c add will fail with @c error::invalid_argument. + * + * @param signal_number The signal to be added to the set. + * + * @param f Flags to modify the behaviour of the specified signal. + * + * @throws asio::system_error Thrown on failure. + */ + void add(int signal_number, flags_t f) + { + asio::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Add a signal to a signal_set with the specified flags. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * Flags other than flags::dont_care require OS support for the @c sigaction + * call, and this function will fail with @c error::operation_not_supported if + * this is unavailable. + * + * The specified flags will conflict with a prior, active registration of the + * same signal, if either specified a flags value other than flags::dont_care. + * In this case, the @c add will fail with @c error::invalid_argument. + * + * @param signal_number The signal to be added to the set. + * + * @param f Flags to modify the behaviour of the specified signal. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID add(int signal_number, flags_t f, + asio::error_code& ec) { - this->get_service().add(this->get_implementation(), signal_number, ec); + impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -234,7 +438,7 @@ public: void remove(int signal_number) { asio::error_code ec; - this->get_service().remove(this->get_implementation(), signal_number, ec); + impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); asio::detail::throw_error(ec, "remove"); } @@ -253,7 +457,7 @@ public: ASIO_SYNC_OP_VOID remove(int signal_number, asio::error_code& ec) { - this->get_service().remove(this->get_implementation(), signal_number, ec); + impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -269,7 +473,7 @@ public: void clear() { asio::error_code ec; - this->get_service().clear(this->get_implementation(), ec); + impl_.get_service().clear(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "clear"); } @@ -284,7 +488,7 @@ public: */ ASIO_SYNC_OP_VOID clear(asio::error_code& ec) { - this->get_service().clear(this->get_implementation(), ec); + impl_.get_service().clear(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -312,7 +516,7 @@ public: void cancel() { asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); } @@ -339,53 +543,106 @@ public: */ ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) { - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous operation to wait for a signal to be delivered. /** * This function may be used to initiate an asynchronous wait against the - * signal set. It always returns immediately. + * signal set. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * - * For each call to async_wait(), the supplied handler will be called exactly - * once. The handler will be called when: + * For each call to async_wait(), the completion handler will be called + * exactly once. The completion handler will be called when: * * @li One of the registered signals in the signal set occurs; or * * @li The signal set was cancelled, in which case the handler is passed the * error code asio::error::operation_aborted. * - * @param handler The handler to be called when the signal occurs. Copies - * will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the wait completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * int signal_number // Indicates which signal occurred. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, int) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename SignalHandler> - ASIO_INITFN_RESULT_TYPE(SignalHandler, - void (asio::error_code, int)) - async_wait(ASIO_MOVE_ARG(SignalHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, int)) + SignalToken = default_completion_token_t<executor_type>> + auto async_wait( + SignalToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<SignalToken, void (asio::error_code, int)>( + declval<initiate_async_wait>(), token)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a SignalHandler. - ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; - - return this->get_service().async_wait(this->get_implementation(), - ASIO_MOVE_CAST(SignalHandler)(handler)); + return async_initiate<SignalToken, void (asio::error_code, int)>( + initiate_async_wait(this), token); } + +private: + // Disallow copying and assignment. + basic_signal_set(const basic_signal_set&) = delete; + basic_signal_set& operator=(const basic_signal_set&) = delete; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_signal_set* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename SignalHandler> + void operator()(SignalHandler&& handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a SignalHandler. + ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; + + detail::non_const_lvalue<SignalHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_signal_set* self_; + }; + + detail::io_object_impl<detail::signal_set_service, Executor> impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_BASIC_SIGNAL_SET_HPP diff --git a/3rdparty/asio/include/asio/basic_socket.hpp b/3rdparty/asio/include/asio/basic_socket.hpp index a1e7b81c3f8..88c4b03fe18 100644 --- a/3rdparty/asio/include/asio/basic_socket.hpp +++ b/3rdparty/asio/include/asio/basic_socket.hpp @@ -2,7 +2,7 @@ // basic_socket.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,37 +15,43 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <utility> +#include "asio/any_io_executor.hpp" #include "asio/detail/config.hpp" #include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" +#include "asio/execution_context.hpp" #include "asio/post.hpp" #include "asio/socket_base.hpp" -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/winrt_ssocket_service.hpp" -# define ASIO_SVC_T detail::winrt_ssocket_service<Protocol> -# elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -# define ASIO_SVC_T detail::win_iocp_socket_service<Protocol> -# else -# include "asio/detail/reactive_socket_service.hpp" -# define ASIO_SVC_T detail::reactive_socket_service<Protocol> -# endif -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_socket_service.hpp" +#elif defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_socket_service.hpp" +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_socket_service.hpp" +#else +# include "asio/detail/reactive_socket_service.hpp" +#endif #include "asio/detail/push_options.hpp" namespace asio { +#if !defined(ASIO_BASIC_SOCKET_FWD_DECL) +#define ASIO_BASIC_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> +class basic_socket; + +#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL) + /// Provides socket functionality. /** * The basic_socket class template provides functionality that is common to both @@ -55,20 +61,41 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename Protocol ASIO_SVC_TPARAM> +template <typename Protocol, typename Executor> class basic_socket - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>, - public socket_base + : public socket_base { +private: + class initiate_async_connect; + class initiate_async_wait; + public: /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_socket<Protocol, Executor1> other; + }; /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; +#elif defined(ASIO_WINDOWS_RUNTIME) + typedef typename detail::null_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef typename detail::win_iocp_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef typename detail::io_uring_socket_service< + Protocol>::native_handle_type native_handle_type; #else - typedef typename ASIO_SVC_T::native_handle_type native_handle_type; + typedef typename detail::reactive_socket_service< + Protocol>::native_handle_type native_handle_type; #endif /// The protocol type. @@ -79,18 +106,35 @@ public: #if !defined(ASIO_NO_EXTENSIONS) /// A basic_socket is always the lowest layer. - typedef basic_socket<Protocol ASIO_SVC_TARG> lowest_layer_type; + typedef basic_socket<Protocol, Executor> lowest_layer_type; #endif // !defined(ASIO_NO_EXTENSIONS) /// Construct a basic_socket without opening it. /** * This constructor creates a socket without opening it. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. */ - explicit basic_socket(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) + explicit basic_socket(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template <typename ExecutionContext> + explicit basic_socket(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { } @@ -98,19 +142,43 @@ public: /** * This constructor creates and opens a socket. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ - basic_socket(asio::io_context& io_context, - const protocol_type& protocol) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_socket(const executor_type& ex, const protocol_type& protocol) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket(ExecutionContext& context, const protocol_type& protocol, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); } @@ -121,7 +189,7 @@ public: * specified endpoint on the local machine. The protocol used is the protocol * associated with the given endpoint. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the socket will @@ -129,15 +197,45 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_socket(asio::io_context& io_context, - const endpoint_type& endpoint) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_socket(const executor_type& ex, const endpoint_type& endpoint) + : impl_(0, ex) { asio::error_code ec; const protocol_type protocol = endpoint.protocol(); - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a socket and automatically opens it bound to the + * specified endpoint on the local machine. The protocol used is the protocol + * associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket(ExecutionContext& context, const endpoint_type& endpoint, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); asio::detail::throw_error(ec, "bind"); } @@ -145,7 +243,7 @@ public: /** * This constructor creates a socket object to hold an existing native socket. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. @@ -154,17 +252,44 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_socket(asio::io_context& io_context, - const protocol_type& protocol, const native_handle_type& native_socket) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_socket(const executor_type& ex, const protocol_type& protocol, + const native_handle_type& native_socket) + : impl_(0, ex) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket(ExecutionContext& context, const protocol_type& protocol, + const native_handle_type& native_socket, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), protocol, native_socket, ec); asio::detail::throw_error(ec, "assign"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_socket from another. /** * This constructor moves a socket from one object to another. @@ -173,10 +298,10 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ - basic_socket(basic_socket&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) + basic_socket(basic_socket&& other) noexcept + : impl_(std::move(other.impl_)) { } @@ -188,16 +313,16 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ basic_socket& operator=(basic_socket&& other) { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); + impl_ = std::move(other.impl_); return *this; } // All sockets have access to each other's implementations. - template <typename Protocol1 ASIO_SVC_TPARAM1> + template <typename Protocol1, typename Executor1> friend class basic_socket; /// Move-construct a basic_socket from a socket of another protocol type. @@ -208,15 +333,16 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - basic_socket(basic_socket<Protocol1 ASIO_SVC_TARG1>&& other, - typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_io_object<ASIO_SVC_T>(other.get_service().get_io_context()) + template <typename Protocol1, typename Executor1> + basic_socket(basic_socket<Protocol1, Executor1>&& other, + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value + > = 0) + : impl_(std::move(other.impl_)) { - this->get_service().template converting_move_construct<Protocol1>( - this->get_implementation(), other.get_implementation()); } /// Move-assign a basic_socket from a socket of another protocol type. @@ -227,58 +353,25 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - typename enable_if<is_convertible<Protocol1, Protocol>::value, - basic_socket>::type& operator=( - basic_socket<Protocol1 ASIO_SVC_TARG1>&& other) + template <typename Protocol1, typename Executor1> + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value, + basic_socket& + > operator=(basic_socket<Protocol1, Executor1>&& other) { basic_socket tmp(std::move(other)); - basic_io_object<ASIO_SVC_T>::operator=(std::move(tmp)); + impl_ = std::move(tmp.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - -#if defined(ASIO_ENABLE_OLD_SERVICES) - // These functions are provided by basic_io_object<>. -#else // defined(ASIO_ENABLE_OLD_SERVICES) -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + const executor_type& get_executor() noexcept { - return basic_io_object<ASIO_SVC_T>::get_executor(); + return impl_.get_executor(); } -#endif // defined(ASIO_ENABLE_OLD_SERVICES) #if !defined(ASIO_NO_EXTENSIONS) /// Get a reference to the lowest layer. @@ -320,14 +413,14 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * socket.open(asio::ip::tcp::v4()); * @endcode */ void open(const protocol_type& protocol = protocol_type()) { asio::error_code ec; - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); } @@ -341,7 +434,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::error_code ec; * socket.open(asio::ip::tcp::v4(), ec); * if (ec) @@ -353,7 +446,7 @@ public: ASIO_SYNC_OP_VOID open(const protocol_type& protocol, asio::error_code& ec) { - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -371,7 +464,7 @@ public: const native_handle_type& native_socket) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), protocol, native_socket, ec); asio::detail::throw_error(ec, "assign"); } @@ -389,7 +482,7 @@ public: ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, const native_handle_type& native_socket, asio::error_code& ec) { - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), protocol, native_socket, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -397,7 +490,7 @@ public: /// Determine whether the socket is open. bool is_open() const { - return this->get_service().is_open(this->get_implementation()); + return impl_.get_service().is_open(impl_.get_implementation()); } /// Close the socket. @@ -415,7 +508,7 @@ public: void close() { asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "close"); } @@ -430,7 +523,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * socket.close(ec); @@ -445,10 +538,62 @@ public: */ ASIO_SYNC_OP_VOID close(asio::error_code& ec) { - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } + /// Release ownership of the underlying native socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + /// Get the native socket representation. /** * This function may be used to obtain the underlying representation of the @@ -457,7 +602,7 @@ public: */ native_handle_type native_handle() { - return this->get_service().native_handle(this->get_implementation()); + return impl_.get_service().native_handle(impl_.get_implementation()); } /// Cancel all asynchronous operations associated with the socket. @@ -504,7 +649,7 @@ public: void cancel() { asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); } @@ -551,7 +696,7 @@ public: #endif ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) { - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -568,7 +713,7 @@ public: bool at_mark() const { asio::error_code ec; - bool b = this->get_service().at_mark(this->get_implementation(), ec); + bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "at_mark"); return b; } @@ -585,7 +730,7 @@ public: */ bool at_mark(asio::error_code& ec) const { - return this->get_service().at_mark(this->get_implementation(), ec); + return impl_.get_service().at_mark(impl_.get_implementation(), ec); } /// Determine the number of bytes available for reading. @@ -601,8 +746,8 @@ public: std::size_t available() const { asio::error_code ec; - std::size_t s = this->get_service().available( - this->get_implementation(), ec); + std::size_t s = impl_.get_service().available( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "available"); return s; } @@ -619,7 +764,7 @@ public: */ std::size_t available(asio::error_code& ec) const { - return this->get_service().available(this->get_implementation(), ec); + return impl_.get_service().available(impl_.get_implementation(), ec); } /// Bind the socket to the given local endpoint. @@ -634,7 +779,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * socket.open(asio::ip::tcp::v4()); * socket.bind(asio::ip::tcp::endpoint( * asio::ip::tcp::v4(), 12345)); @@ -643,7 +788,7 @@ public: void bind(const endpoint_type& endpoint) { asio::error_code ec; - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); asio::detail::throw_error(ec, "bind"); } @@ -659,7 +804,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * socket.open(asio::ip::tcp::v4()); * asio::error_code ec; * socket.bind(asio::ip::tcp::endpoint( @@ -673,7 +818,7 @@ public: ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, asio::error_code& ec) { - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -694,7 +839,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.connect(endpoint); @@ -705,11 +850,11 @@ public: asio::error_code ec; if (!is_open()) { - this->get_service().open(this->get_implementation(), + impl_.get_service().open(impl_.get_implementation(), peer_endpoint.protocol(), ec); asio::detail::throw_error(ec, "connect"); } - this->get_service().connect(this->get_implementation(), peer_endpoint, ec); + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); asio::detail::throw_error(ec, "connect"); } @@ -730,7 +875,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * asio::error_code ec; @@ -746,7 +891,7 @@ public: { if (!is_open()) { - this->get_service().open(this->get_implementation(), + impl_.get_service().open(impl_.get_implementation(), peer_endpoint.protocol(), ec); if (ec) { @@ -754,14 +899,15 @@ public: } } - this->get_service().connect(this->get_implementation(), peer_endpoint, ec); + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous connect. /** * This function is used to asynchronously connect a socket to the specified - * remote endpoint. The function call always returns immediately. + * remote endpoint. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * The socket is automatically opened if it is not already open. If the * connect fails, and the socket was automatically opened, the socket is @@ -770,16 +916,21 @@ public: * @param peer_endpoint The remote endpoint to which the socket will be * connected. Copies will be made of the endpoint object as required. * - * @param handler The handler to be called when the connection operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode * * @par Example * @code @@ -793,54 +944,41 @@ public: * * ... * - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.async_connect(endpoint, connect_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConnectHandler> - ASIO_INITFN_RESULT_TYPE(ConnectHandler, - void (asio::error_code)) - async_connect(const endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(ConnectHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + ConnectToken = default_completion_token_t<executor_type>> + auto async_connect(const endpoint_type& peer_endpoint, + ConnectToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ConnectToken, void (asio::error_code)>( + declval<initiate_async_connect>(), token, + peer_endpoint, declval<asio::error_code&>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ConnectHandler. - ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check; - + asio::error_code open_ec; if (!is_open()) { - asio::error_code ec; const protocol_type protocol = peer_endpoint.protocol(); - this->get_service().open(this->get_implementation(), protocol, ec); - if (ec) - { - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - asio::post(this->get_executor(), - asio::detail::bind_handler( - ASIO_MOVE_CAST(ASIO_HANDLER_TYPE( - ConnectHandler, void (asio::error_code)))( - init.completion_handler), ec)); - - return init.result.get(); - } + impl_.get_service().open(impl_.get_implementation(), protocol, open_ec); } -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_connect(this->get_implementation(), - peer_endpoint, ASIO_MOVE_CAST(ConnectHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_connect( - this->get_implementation(), peer_endpoint, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ConnectToken, void (asio::error_code)>( + initiate_async_connect(this), token, peer_endpoint, open_ec); } /// Set an option on the socket. @@ -871,7 +1009,7 @@ public: * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::no_delay option(true); * socket.set_option(option); @@ -881,7 +1019,7 @@ public: void set_option(const SettableSocketOption& option) { asio::error_code ec; - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "set_option"); } @@ -913,7 +1051,7 @@ public: * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::no_delay option(true); * asio::error_code ec; @@ -928,7 +1066,7 @@ public: ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, asio::error_code& ec) { - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -960,7 +1098,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::keep_alive option; * socket.get_option(option); @@ -971,7 +1109,7 @@ public: void get_option(GettableSocketOption& option) const { asio::error_code ec; - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "get_option"); } @@ -1003,7 +1141,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::keep_alive option; * asio::error_code ec; @@ -1019,7 +1157,7 @@ public: ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, asio::error_code& ec) const { - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1038,7 +1176,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::bytes_readable command; * socket.io_control(command); @@ -1049,7 +1187,7 @@ public: void io_control(IoControlCommand& command) { asio::error_code ec; - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); asio::detail::throw_error(ec, "io_control"); } @@ -1068,7 +1206,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::bytes_readable command; * asio::error_code ec; @@ -1084,7 +1222,7 @@ public: ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, asio::error_code& ec) { - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1101,7 +1239,7 @@ public: */ bool non_blocking() const { - return this->get_service().non_blocking(this->get_implementation()); + return impl_.get_service().non_blocking(impl_.get_implementation()); } /// Sets the non-blocking mode of the socket. @@ -1120,7 +1258,7 @@ public: void non_blocking(bool mode) { asio::error_code ec; - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "non_blocking"); } @@ -1140,7 +1278,7 @@ public: ASIO_SYNC_OP_VOID non_blocking( bool mode, asio::error_code& ec) { - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1230,7 +1368,7 @@ public: */ bool native_non_blocking() const { - return this->get_service().native_non_blocking(this->get_implementation()); + return impl_.get_service().native_non_blocking(impl_.get_implementation()); } /// Sets the non-blocking mode of the native socket implementation. @@ -1321,8 +1459,8 @@ public: void native_non_blocking(bool mode) { asio::error_code ec; - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "native_non_blocking"); } @@ -1414,8 +1552,8 @@ public: ASIO_SYNC_OP_VOID native_non_blocking( bool mode, asio::error_code& ec) { - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1429,7 +1567,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); * @endcode @@ -1437,8 +1575,8 @@ public: endpoint_type local_endpoint() const { asio::error_code ec; - endpoint_type ep = this->get_service().local_endpoint( - this->get_implementation(), ec); + endpoint_type ep = impl_.get_service().local_endpoint( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "local_endpoint"); return ep; } @@ -1454,7 +1592,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); @@ -1466,7 +1604,7 @@ public: */ endpoint_type local_endpoint(asio::error_code& ec) const { - return this->get_service().local_endpoint(this->get_implementation(), ec); + return impl_.get_service().local_endpoint(impl_.get_implementation(), ec); } /// Get the remote endpoint of the socket. @@ -1479,7 +1617,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); * @endcode @@ -1487,8 +1625,8 @@ public: endpoint_type remote_endpoint() const { asio::error_code ec; - endpoint_type ep = this->get_service().remote_endpoint( - this->get_implementation(), ec); + endpoint_type ep = impl_.get_service().remote_endpoint( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "remote_endpoint"); return ep; } @@ -1504,7 +1642,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); @@ -1516,7 +1654,7 @@ public: */ endpoint_type remote_endpoint(asio::error_code& ec) const { - return this->get_service().remote_endpoint(this->get_implementation(), ec); + return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec); } /// Disable sends or receives on the socket. @@ -1531,7 +1669,7 @@ public: * @par Example * Shutting down the send side of the socket: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * socket.shutdown(asio::ip::tcp::socket::shutdown_send); * @endcode @@ -1539,7 +1677,7 @@ public: void shutdown(shutdown_type what) { asio::error_code ec; - this->get_service().shutdown(this->get_implementation(), what, ec); + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); asio::detail::throw_error(ec, "shutdown"); } @@ -1555,7 +1693,7 @@ public: * @par Example * Shutting down the send side of the socket: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec); @@ -1568,7 +1706,7 @@ public: ASIO_SYNC_OP_VOID shutdown(shutdown_type what, asio::error_code& ec) { - this->get_service().shutdown(this->get_implementation(), what, ec); + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1583,7 +1721,7 @@ public: * @par Example * Waiting for a socket to become readable. * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * socket.wait(asio::ip::tcp::socket::wait_read); * @endcode @@ -1591,7 +1729,7 @@ public: void wait(wait_type w) { asio::error_code ec; - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); asio::detail::throw_error(ec, "wait"); } @@ -1608,7 +1746,7 @@ public: * @par Example * Waiting for a socket to become readable. * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * socket.wait(asio::ip::tcp::socket::wait_read, ec); @@ -1616,7 +1754,7 @@ public: */ ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) { - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1624,20 +1762,27 @@ public: /// write, or to have pending error conditions. /** * This function is used to perform an asynchronous wait for a socket to enter - * a ready to read, write or error condition state. + * a ready to read, write or error condition state. It is an initiating + * function for an @ref asynchronous_operation, and always returns + * immediately. * * @param w Specifies the desired socket state. * - * @param handler The handler to be called when the wait operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the wait completes. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode * * @par Example * @code @@ -1651,32 +1796,32 @@ public: * * ... * - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * socket.async_wait(asio::ip::tcp::socket::wait_read, wait_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitToken = default_completion_token_t<executor_type>> + auto async_wait(wait_type w, + WaitToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WaitToken, void (asio::error_code)>( + declval<initiate_async_wait>(), token, w)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WaitHandler. - ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_wait(this->get_implementation(), - w, ASIO_MOVE_CAST(WaitHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_wait(this->get_implementation(), - w, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WaitToken, void (asio::error_code)>( + initiate_async_wait(this), token, w); } protected: @@ -1689,18 +1834,103 @@ protected: { } +#if defined(ASIO_WINDOWS_RUNTIME) + detail::io_object_impl< + detail::null_socket_service<Protocol>, Executor> impl_; +#elif defined(ASIO_HAS_IOCP) + detail::io_object_impl< + detail::win_iocp_socket_service<Protocol>, Executor> impl_; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + detail::io_object_impl< + detail::io_uring_socket_service<Protocol>, Executor> impl_; +#else + detail::io_object_impl< + detail::reactive_socket_service<Protocol>, Executor> impl_; +#endif + private: // Disallow copying and assignment. - basic_socket(const basic_socket&) ASIO_DELETED; - basic_socket& operator=(const basic_socket&) ASIO_DELETED; + basic_socket(const basic_socket&) = delete; + basic_socket& operator=(const basic_socket&) = delete; + + class initiate_async_connect + { + public: + typedef Executor executor_type; + + explicit initiate_async_connect(basic_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ConnectHandler> + void operator()(ConnectHandler&& handler, + const endpoint_type& peer_endpoint, + const asio::error_code& open_ec) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ConnectHandler. + ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check; + + if (open_ec) + { + asio::post(self_->impl_.get_executor(), + asio::detail::bind_handler( + static_cast<ConnectHandler&&>(handler), open_ec)); + } + else + { + detail::non_const_lvalue<ConnectHandler> handler2(handler); + self_->impl_.get_service().async_connect( + self_->impl_.get_implementation(), peer_endpoint, + handler2.value, self_->impl_.get_executor()); + } + } + + private: + basic_socket* self_; + }; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue<WaitHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket* self_; + }; }; } // namespace asio #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_BASIC_SOCKET_HPP diff --git a/3rdparty/asio/include/asio/basic_socket_acceptor.hpp b/3rdparty/asio/include/asio/basic_socket_acceptor.hpp index 9554bb9ed30..059d33ead53 100644 --- a/3rdparty/asio/include/asio/basic_socket_acceptor.hpp +++ b/3rdparty/asio/include/asio/basic_socket_acceptor.hpp @@ -2,7 +2,7 @@ // basic_socket_acceptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,38 +15,42 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <utility> #include "asio/detail/config.hpp" -#include "asio/basic_io_object.hpp" +#include "asio/any_io_executor.hpp" #include "asio/basic_socket.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" +#include "asio/execution_context.hpp" #include "asio/socket_base.hpp" -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/socket_acceptor_service.hpp" -#else // defined(ASIO_ENABLE_OLD_SERVICES) -# if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/null_socket_service.hpp" -# define ASIO_SVC_T detail::null_socket_service<Protocol> -# elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -# define ASIO_SVC_T detail::win_iocp_socket_service<Protocol> -# else -# include "asio/detail/reactive_socket_service.hpp" -# define ASIO_SVC_T detail::reactive_socket_service<Protocol> -# endif -#endif // defined(ASIO_ENABLE_OLD_SERVICES) +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_socket_service.hpp" +#elif defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_socket_service.hpp" +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_socket_service.hpp" +#else +# include "asio/detail/reactive_socket_service.hpp" +#endif #include "asio/detail/push_options.hpp" namespace asio { +#if !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) +#define ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> +class basic_socket_acceptor; + +#endif // !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) + /// Provides the ability to accept new connections. /** * The basic_socket_acceptor class template is used for accepting new socket @@ -56,10 +60,16 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * + * Synchronous @c accept operations are thread safe, if the underlying + * operating system calls are also thread safe. This means that it is permitted + * to perform concurrent calls to synchronous @c accept operations on a single + * socket object. Other synchronous operations, such as @c open or @c close, are + * not thread safe. + * * @par Example * Opening a socket acceptor with the SO_REUSEADDR option enabled: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port); * acceptor.open(endpoint.protocol()); * acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true)); @@ -67,21 +77,42 @@ namespace asio { * acceptor.listen(); * @endcode */ -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= socket_acceptor_service<Protocol>)> +template <typename Protocol, typename Executor> class basic_socket_acceptor - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>, - public socket_base + : public socket_base { +private: + class initiate_async_wait; + class initiate_async_accept; + class initiate_async_move_accept; + public: /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; + typedef Executor executor_type; + + /// Rebinds the acceptor type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_socket_acceptor<Protocol, Executor1> other; + }; /// The native representation of an acceptor. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; +#elif defined(ASIO_WINDOWS_RUNTIME) + typedef typename detail::null_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef typename detail::win_iocp_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef typename detail::io_uring_socket_service< + Protocol>::native_handle_type native_handle_type; #else - typedef typename ASIO_SVC_T::native_handle_type native_handle_type; + typedef typename detail::reactive_socket_service< + Protocol>::native_handle_type native_handle_type; #endif /// The protocol type. @@ -96,12 +127,31 @@ public: * connections. The open() function must be called before the acceptor can * accept new socket connections. * - * @param io_context The io_context object that the acceptor will use to + * @param ex The I/O executor that the acceptor will use, by default, to * dispatch handlers for any asynchronous operations performed on the * acceptor. */ - explicit basic_socket_acceptor(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) + explicit basic_socket_acceptor(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct an acceptor without opening it. + /** + * This constructor creates an acceptor without opening it to listen for new + * connections. The open() function must be called before the acceptor can + * accept new socket connections. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + */ + template <typename ExecutionContext> + explicit basic_socket_acceptor(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { } @@ -109,7 +159,7 @@ public: /** * This constructor creates an acceptor and automatically opens it. * - * @param io_context The io_context object that the acceptor will use to + * @param ex The I/O executor that the acceptor will use, by default, to * dispatch handlers for any asynchronous operations performed on the * acceptor. * @@ -117,12 +167,37 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_socket_acceptor(asio::io_context& io_context, - const protocol_type& protocol) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct an open acceptor. + /** + * This constructor creates an acceptor and automatically opens it. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket_acceptor(ExecutionContext& context, + const protocol_type& protocol, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); } @@ -131,7 +206,7 @@ public: * This constructor creates an acceptor and automatically opens it to listen * for new connections on the specified endpoint. * - * @param io_context The io_context object that the acceptor will use to + * @param ex The I/O executor that the acceptor will use, by default, to * dispatch handlers for any asynchronous operations performed on the * acceptor. * @@ -145,31 +220,83 @@ public: * * @note This constructor is equivalent to the following code: * @code - * basic_socket_acceptor<Protocol> acceptor(io_context); + * basic_socket_acceptor<Protocol> acceptor(my_context); * acceptor.open(endpoint.protocol()); * if (reuse_addr) * acceptor.set_option(socket_base::reuse_address(true)); * acceptor.bind(endpoint); - * acceptor.listen(listen_backlog); + * acceptor.listen(); * @endcode */ - basic_socket_acceptor(asio::io_context& io_context, + basic_socket_acceptor(const executor_type& ex, const endpoint_type& endpoint, bool reuse_addr = true) - : basic_io_object<ASIO_SVC_T>(io_context) + : impl_(0, ex) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + if (reuse_addr) + { + impl_.get_service().set_option(impl_.get_implementation(), + socket_base::reuse_address(true), ec); + asio::detail::throw_error(ec, "set_option"); + } + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + impl_.get_service().listen(impl_.get_implementation(), + socket_base::max_listen_connections, ec); + asio::detail::throw_error(ec, "listen"); + } + + /// Construct an acceptor opened on the given endpoint. + /** + * This constructor creates an acceptor and automatically opens it to listen + * for new connections on the specified endpoint. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param endpoint An endpoint on the local machine on which the acceptor + * will listen for new connections. + * + * @param reuse_addr Whether the constructor should set the socket option + * socket_base::reuse_address. + * + * @throws asio::system_error Thrown on failure. + * + * @note This constructor is equivalent to the following code: + * @code + * basic_socket_acceptor<Protocol> acceptor(my_context); + * acceptor.open(endpoint.protocol()); + * if (reuse_addr) + * acceptor.set_option(socket_base::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ + template <typename ExecutionContext> + basic_socket_acceptor(ExecutionContext& context, + const endpoint_type& endpoint, bool reuse_addr = true, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { asio::error_code ec; const protocol_type protocol = endpoint.protocol(); - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); if (reuse_addr) { - this->get_service().set_option(this->get_implementation(), + impl_.get_service().set_option(impl_.get_implementation(), socket_base::reuse_address(true), ec); asio::detail::throw_error(ec, "set_option"); } - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); asio::detail::throw_error(ec, "bind"); - this->get_service().listen(this->get_implementation(), + impl_.get_service().listen(impl_.get_implementation(), socket_base::max_listen_connections, ec); asio::detail::throw_error(ec, "listen"); } @@ -179,7 +306,7 @@ public: * This constructor creates an acceptor object to hold an existing native * acceptor. * - * @param io_context The io_context object that the acceptor will use to + * @param ex The I/O executor that the acceptor will use, by default, to * dispatch handlers for any asynchronous operations performed on the * acceptor. * @@ -189,17 +316,45 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_socket_acceptor(asio::io_context& io_context, + basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_acceptor) - : basic_io_object<ASIO_SVC_T>(io_context) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_socket_acceptor on an existing native acceptor. + /** + * This constructor creates an acceptor object to hold an existing native + * acceptor. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket_acceptor(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_acceptor, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), protocol, native_acceptor, ec); asio::detail::throw_error(ec, "assign"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_socket_acceptor from another. /** * This constructor moves an acceptor from one object to another. @@ -208,10 +363,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket_acceptor(io_context&) constructor. + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. */ - basic_socket_acceptor(basic_socket_acceptor&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) + basic_socket_acceptor(basic_socket_acceptor&& other) noexcept + : impl_(std::move(other.impl_)) { } @@ -223,16 +379,17 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket_acceptor(io_context&) constructor. + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. */ basic_socket_acceptor& operator=(basic_socket_acceptor&& other) { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); + impl_ = std::move(other.impl_); return *this; } // All socket acceptors have access to each other's implementations. - template <typename Protocol1 ASIO_SVC_TPARAM1> + template <typename Protocol1, typename Executor1> friend class basic_socket_acceptor; /// Move-construct a basic_socket_acceptor from an acceptor of another @@ -244,17 +401,17 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - basic_socket_acceptor( - basic_socket_acceptor<Protocol1 ASIO_SVC_TARG1>&& other, - typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_io_object<ASIO_SVC_T>( - other.get_service().get_io_context()) + template <typename Protocol1, typename Executor1> + basic_socket_acceptor(basic_socket_acceptor<Protocol1, Executor1>&& other, + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value + > = 0) + : impl_(std::move(other.impl_)) { - this->get_service().template converting_move_construct<Protocol1>( - this->get_implementation(), other.get_implementation()); } /// Move-assign a basic_socket_acceptor from an acceptor of another protocol @@ -266,18 +423,20 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - typename enable_if<is_convertible<Protocol1, Protocol>::value, - basic_socket_acceptor>::type& operator=( - basic_socket_acceptor<Protocol1 ASIO_SVC_TARG1>&& other) + template <typename Protocol1, typename Executor1> + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value, + basic_socket_acceptor& + > operator=(basic_socket_acceptor<Protocol1, Executor1>&& other) { basic_socket_acceptor tmp(std::move(other)); - basic_io_object<ASIO_SVC_T>::operator=(std::move(tmp)); + impl_ = std::move(tmp.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destroys the acceptor. /** @@ -289,45 +448,11 @@ public: { } -#if defined(ASIO_ENABLE_OLD_SERVICES) - // These functions are provided by basic_io_object<>. -#else // defined(ASIO_ENABLE_OLD_SERVICES) -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + const executor_type& get_executor() noexcept { - return basic_io_object<ASIO_SVC_T>::get_executor(); + return impl_.get_executor(); } -#endif // defined(ASIO_ENABLE_OLD_SERVICES) /// Open the acceptor using the specified protocol. /** @@ -340,14 +465,14 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * acceptor.open(asio::ip::tcp::v4()); * @endcode */ void open(const protocol_type& protocol = protocol_type()) { asio::error_code ec; - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); } @@ -362,7 +487,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * asio::error_code ec; * acceptor.open(asio::ip::tcp::v4(), ec); * if (ec) @@ -374,7 +499,7 @@ public: ASIO_SYNC_OP_VOID open(const protocol_type& protocol, asio::error_code& ec) { - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -392,7 +517,7 @@ public: const native_handle_type& native_acceptor) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), protocol, native_acceptor, ec); asio::detail::throw_error(ec, "assign"); } @@ -410,7 +535,7 @@ public: ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, const native_handle_type& native_acceptor, asio::error_code& ec) { - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), protocol, native_acceptor, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -418,7 +543,7 @@ public: /// Determine whether the acceptor is open. bool is_open() const { - return this->get_service().is_open(this->get_implementation()); + return impl_.get_service().is_open(impl_.get_implementation()); } /// Bind the acceptor to the given local endpoint. @@ -433,7 +558,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345); * acceptor.open(endpoint.protocol()); * acceptor.bind(endpoint); @@ -442,7 +567,7 @@ public: void bind(const endpoint_type& endpoint) { asio::error_code ec; - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); asio::detail::throw_error(ec, "bind"); } @@ -458,7 +583,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345); * acceptor.open(endpoint.protocol()); * asio::error_code ec; @@ -472,7 +597,7 @@ public: ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, asio::error_code& ec) { - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -489,7 +614,7 @@ public: void listen(int backlog = socket_base::max_listen_connections) { asio::error_code ec; - this->get_service().listen(this->get_implementation(), backlog, ec); + impl_.get_service().listen(impl_.get_implementation(), backlog, ec); asio::detail::throw_error(ec, "listen"); } @@ -505,7 +630,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::error_code ec; * acceptor.listen(asio::socket_base::max_listen_connections, ec); @@ -517,7 +642,7 @@ public: */ ASIO_SYNC_OP_VOID listen(int backlog, asio::error_code& ec) { - this->get_service().listen(this->get_implementation(), backlog, ec); + impl_.get_service().listen(impl_.get_implementation(), backlog, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -534,7 +659,7 @@ public: void close() { asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "close"); } @@ -550,7 +675,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::error_code ec; * acceptor.close(ec); @@ -562,10 +687,62 @@ public: */ ASIO_SYNC_OP_VOID close(asio::error_code& ec) { - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } + /// Release ownership of the underlying native acceptor. + /** + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native acceptor. + /** + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + /// Get the native acceptor representation. /** * This function may be used to obtain the underlying representation of the @@ -574,7 +751,7 @@ public: */ native_handle_type native_handle() { - return this->get_service().native_handle(this->get_implementation()); + return impl_.get_service().native_handle(impl_.get_implementation()); } /// Cancel all asynchronous operations associated with the acceptor. @@ -588,7 +765,7 @@ public: void cancel() { asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); } @@ -602,7 +779,7 @@ public: */ ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) { - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -621,7 +798,7 @@ public: * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::acceptor::reuse_address option(true); * acceptor.set_option(option); @@ -631,7 +808,7 @@ public: void set_option(const SettableSocketOption& option) { asio::error_code ec; - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "set_option"); } @@ -650,7 +827,7 @@ public: * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::acceptor::reuse_address option(true); * asio::error_code ec; @@ -665,7 +842,7 @@ public: ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, asio::error_code& ec) { - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -684,7 +861,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::acceptor::reuse_address option; * acceptor.get_option(option); @@ -692,10 +869,10 @@ public: * @endcode */ template <typename GettableSocketOption> - void get_option(GettableSocketOption& option) + void get_option(GettableSocketOption& option) const { asio::error_code ec; - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "get_option"); } @@ -714,7 +891,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::acceptor::reuse_address option; * asio::error_code ec; @@ -728,9 +905,9 @@ public: */ template <typename GettableSocketOption> ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, - asio::error_code& ec) + asio::error_code& ec) const { - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -748,7 +925,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::acceptor::non_blocking_io command(true); * socket.io_control(command); @@ -758,7 +935,7 @@ public: void io_control(IoControlCommand& command) { asio::error_code ec; - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); asio::detail::throw_error(ec, "io_control"); } @@ -776,7 +953,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::acceptor::non_blocking_io command(true); * asio::error_code ec; @@ -791,7 +968,7 @@ public: ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, asio::error_code& ec) { - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -808,7 +985,7 @@ public: */ bool non_blocking() const { - return this->get_service().non_blocking(this->get_implementation()); + return impl_.get_service().non_blocking(impl_.get_implementation()); } /// Sets the non-blocking mode of the acceptor. @@ -827,7 +1004,7 @@ public: void non_blocking(bool mode) { asio::error_code ec; - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "non_blocking"); } @@ -847,7 +1024,7 @@ public: ASIO_SYNC_OP_VOID non_blocking( bool mode, asio::error_code& ec) { - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -867,7 +1044,7 @@ public: */ bool native_non_blocking() const { - return this->get_service().native_non_blocking(this->get_implementation()); + return impl_.get_service().native_non_blocking(impl_.get_implementation()); } /// Sets the non-blocking mode of the native acceptor implementation. @@ -888,8 +1065,8 @@ public: void native_non_blocking(bool mode) { asio::error_code ec; - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "native_non_blocking"); } @@ -911,8 +1088,8 @@ public: ASIO_SYNC_OP_VOID native_non_blocking( bool mode, asio::error_code& ec) { - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -926,7 +1103,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(); * @endcode @@ -934,8 +1111,8 @@ public: endpoint_type local_endpoint() const { asio::error_code ec; - endpoint_type ep = this->get_service().local_endpoint( - this->get_implementation(), ec); + endpoint_type ep = impl_.get_service().local_endpoint( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "local_endpoint"); return ep; } @@ -952,7 +1129,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); @@ -964,7 +1141,7 @@ public: */ endpoint_type local_endpoint(asio::error_code& ec) const { - return this->get_service().local_endpoint(this->get_implementation(), ec); + return impl_.get_service().local_endpoint(impl_.get_implementation(), ec); } /// Wait for the acceptor to become ready to read, ready to write, or to have @@ -978,7 +1155,7 @@ public: * @par Example * Waiting for an acceptor to become readable. * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * acceptor.wait(asio::ip::tcp::acceptor::wait_read); * @endcode @@ -986,7 +1163,7 @@ public: void wait(wait_type w) { asio::error_code ec; - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); asio::detail::throw_error(ec, "wait"); } @@ -1003,7 +1180,7 @@ public: * @par Example * Waiting for an acceptor to become readable. * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::error_code ec; * acceptor.wait(asio::ip::tcp::acceptor::wait_read, ec); @@ -1011,7 +1188,7 @@ public: */ ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) { - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1019,20 +1196,27 @@ public: /// write, or to have pending error conditions. /** * This function is used to perform an asynchronous wait for an acceptor to - * enter a ready to read, write or error condition state. + * enter a ready to read, write or error condition state. It is an initiating + * function for an @ref asynchronous_operation, and always returns + * immediately. * * @param w Specifies the desired acceptor state. * - * @param handler The handler to be called when the wait operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the wait completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode * * @par Example * @code @@ -1046,34 +1230,34 @@ public: * * ... * - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * acceptor.async_wait( * asio::ip::tcp::acceptor::wait_read, * wait_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitToken = default_completion_token_t<executor_type>> + auto async_wait(wait_type w, + WaitToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WaitToken, void (asio::error_code)>( + declval<initiate_async_wait>(), token, w)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WaitHandler. - ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_wait(this->get_implementation(), - w, ASIO_MOVE_CAST(WaitHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_wait(this->get_implementation(), - w, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WaitToken, void (asio::error_code)>( + initiate_async_wait(this), token, w); } #if !defined(ASIO_NO_EXTENSIONS) @@ -1089,24 +1273,20 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * acceptor.accept(socket); * @endcode */ -#if defined(ASIO_ENABLE_OLD_SERVICES) - template <typename Protocol1, typename SocketService> - void accept(basic_socket<Protocol1, SocketService>& peer, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) -#else // defined(ASIO_ENABLE_OLD_SERVICES) - template <typename Protocol1> - void accept(basic_socket<Protocol1>& peer, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + template <typename Protocol1, typename Executor1> + void accept(basic_socket<Protocol1, Executor1>& peer, + constraint_t< + is_convertible<Protocol, Protocol1>::value + > = 0) { asio::error_code ec; - this->get_service().accept(this->get_implementation(), + impl_.get_service().accept(impl_.get_implementation(), peer, static_cast<endpoint_type*>(0), ec); asio::detail::throw_error(ec, "accept"); } @@ -1123,9 +1303,9 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::error_code ec; * acceptor.accept(socket, ec); * if (ec) @@ -1134,20 +1314,14 @@ public: * } * @endcode */ -#if defined(ASIO_ENABLE_OLD_SERVICES) - template <typename Protocol1, typename SocketService> - ASIO_SYNC_OP_VOID accept( - basic_socket<Protocol1, SocketService>& peer, - asio::error_code& ec, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) -#else // defined(ASIO_ENABLE_OLD_SERVICES) - template <typename Protocol1> + template <typename Protocol1, typename Executor1> ASIO_SYNC_OP_VOID accept( - basic_socket<Protocol1>& peer, asio::error_code& ec, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + basic_socket<Protocol1, Executor1>& peer, asio::error_code& ec, + constraint_t< + is_convertible<Protocol, Protocol1>::value + > = 0) { - this->get_service().accept(this->get_implementation(), + impl_.get_service().accept(impl_.get_implementation(), peer, static_cast<endpoint_type*>(0), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1155,22 +1329,29 @@ public: /// Start an asynchronous accept. /** * This function is used to asynchronously accept a new connection into a - * socket. The function call always returns immediately. + * socket, and additionally obtain the endpoint of the remote peer. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * @param peer The socket into which the new connection will be accepted. * Ownership of the peer object is retained by the caller, which must - * guarantee that it is valid until the handler is called. + * guarantee that it is valid until the completion handler is called. * - * @param handler The handler to be called when the accept operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode * * @par Example * @code @@ -1184,45 +1365,38 @@ public: * * ... * - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * acceptor.async_accept(socket, accept_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ -#if defined(ASIO_ENABLE_OLD_SERVICES) - template <typename Protocol1, typename SocketService, typename AcceptHandler> - ASIO_INITFN_RESULT_TYPE(AcceptHandler, - void (asio::error_code)) - async_accept(basic_socket<Protocol1, SocketService>& peer, - ASIO_MOVE_ARG(AcceptHandler) handler, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) -#else // defined(ASIO_ENABLE_OLD_SERVICES) - template <typename Protocol1, typename AcceptHandler> - ASIO_INITFN_RESULT_TYPE(AcceptHandler, - void (asio::error_code)) - async_accept(basic_socket<Protocol1>& peer, - ASIO_MOVE_ARG(AcceptHandler) handler, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a AcceptHandler. - ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_accept(this->get_implementation(), - peer, static_cast<endpoint_type*>(0), - ASIO_MOVE_CAST(AcceptHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<AcceptHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_accept(this->get_implementation(), - peer, static_cast<endpoint_type*>(0), init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + template <typename Protocol1, typename Executor1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + AcceptToken = default_completion_token_t<executor_type>> + auto async_accept(basic_socket<Protocol1, Executor1>& peer, + AcceptToken&& token = default_completion_token_t<executor_type>(), + constraint_t< + is_convertible<Protocol, Protocol1>::value + > = 0) + -> decltype( + async_initiate<AcceptToken, void (asio::error_code)>( + declval<initiate_async_accept>(), token, + &peer, static_cast<endpoint_type*>(0))) + { + return async_initiate<AcceptToken, void (asio::error_code)>( + initiate_async_accept(this), token, + &peer, static_cast<endpoint_type*>(0)); } /// Accept a new connection and obtain the endpoint of the peer @@ -1241,23 +1415,19 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint; * acceptor.accept(socket, endpoint); * @endcode */ -#if defined(ASIO_ENABLE_OLD_SERVICES) - template <typename SocketService> - void accept(basic_socket<protocol_type, SocketService>& peer, + template <typename Executor1> + void accept(basic_socket<protocol_type, Executor1>& peer, endpoint_type& peer_endpoint) -#else // defined(ASIO_ENABLE_OLD_SERVICES) - void accept(basic_socket<protocol_type>& peer, endpoint_type& peer_endpoint) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) { asio::error_code ec; - this->get_service().accept(this->get_implementation(), + impl_.get_service().accept(impl_.get_implementation(), peer, &peer_endpoint, ec); asio::detail::throw_error(ec, "accept"); } @@ -1278,9 +1448,9 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint; * asio::error_code ec; * acceptor.accept(socket, endpoint, ec); @@ -1290,81 +1460,72 @@ public: * } * @endcode */ -#if defined(ASIO_ENABLE_OLD_SERVICES) - template <typename SocketService> - ASIO_SYNC_OP_VOID accept( - basic_socket<protocol_type, SocketService>& peer, - endpoint_type& peer_endpoint, asio::error_code& ec) -#else // defined(ASIO_ENABLE_OLD_SERVICES) - ASIO_SYNC_OP_VOID accept(basic_socket<protocol_type>& peer, + template <typename Executor1> + ASIO_SYNC_OP_VOID accept(basic_socket<protocol_type, Executor1>& peer, endpoint_type& peer_endpoint, asio::error_code& ec) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) { - this->get_service().accept( - this->get_implementation(), peer, &peer_endpoint, ec); + impl_.get_service().accept( + impl_.get_implementation(), peer, &peer_endpoint, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous accept. /** * This function is used to asynchronously accept a new connection into a - * socket, and additionally obtain the endpoint of the remote peer. The - * function call always returns immediately. + * socket, and additionally obtain the endpoint of the remote peer. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * @param peer The socket into which the new connection will be accepted. * Ownership of the peer object is retained by the caller, which must - * guarantee that it is valid until the handler is called. + * guarantee that it is valid until the completion handler is called. * * @param peer_endpoint An endpoint object into which the endpoint of the * remote peer will be written. Ownership of the peer_endpoint object is * retained by the caller, which must guarantee that it is valid until the * handler is called. * - * @param handler The handler to be called when the accept operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - */ -#if defined(ASIO_ENABLE_OLD_SERVICES) - template <typename SocketService, typename AcceptHandler> - ASIO_INITFN_RESULT_TYPE(AcceptHandler, - void (asio::error_code)) - async_accept(basic_socket<protocol_type, SocketService>& peer, - endpoint_type& peer_endpoint, ASIO_MOVE_ARG(AcceptHandler) handler) -#else // defined(ASIO_ENABLE_OLD_SERVICES) - template <typename AcceptHandler> - ASIO_INITFN_RESULT_TYPE(AcceptHandler, - void (asio::error_code)) - async_accept(basic_socket<protocol_type>& peer, - endpoint_type& peer_endpoint, ASIO_MOVE_ARG(AcceptHandler) handler) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a AcceptHandler. - ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_accept(this->get_implementation(), peer, - &peer_endpoint, ASIO_MOVE_CAST(AcceptHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<AcceptHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_accept(this->get_implementation(), - peer, &peer_endpoint, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total + */ + template <typename Executor1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + AcceptToken = default_completion_token_t<executor_type>> + auto async_accept(basic_socket<protocol_type, Executor1>& peer, + endpoint_type& peer_endpoint, + AcceptToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<AcceptToken, void (asio::error_code)>( + declval<initiate_async_accept>(), token, &peer, &peer_endpoint)) + { + return async_initiate<AcceptToken, void (asio::error_code)>( + initiate_async_accept(this), token, &peer, &peer_endpoint); } #endif // !defined(ASIO_NO_EXTENSIONS) -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Accept a new connection. /** * This function is used to accept a new connection from a peer. The function @@ -1380,17 +1541,18 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::socket socket(acceptor.accept()); * @endcode */ - typename Protocol::socket accept() + typename Protocol::socket::template rebind_executor<executor_type>::other + accept() { asio::error_code ec; - typename Protocol::socket peer( - this->get_service().accept( - this->get_implementation(), 0, 0, ec)); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); asio::detail::throw_error(ec, "accept"); return peer; } @@ -1411,7 +1573,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::socket socket(acceptor.accept(ec)); * if (ec) @@ -1420,30 +1582,46 @@ public: * } * @endcode */ - typename Protocol::socket accept(asio::error_code& ec) + typename Protocol::socket::template rebind_executor<executor_type>::other + accept(asio::error_code& ec) { - return this->get_service().accept(this->get_implementation(), 0, 0, ec); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; } /// Start an asynchronous accept. /** - * This function is used to asynchronously accept a new connection. The - * function call always returns immediately. + * This function is used to asynchronously accept a new connection. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. * - * @param handler The handler to be called when the accept operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. - * typename Protocol::socket peer // On success, the newly accepted socket. + * // Result of operation. + * const asio::error_code& error, + * + * // On success, the newly accepted socket. + * typename Protocol::socket::template + * rebind_executor<executor_type>::other peer * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, + * typename Protocol::socket::template + * rebind_executor<executor_type>::other)) @endcode * * @par Example * @code @@ -1458,37 +1636,83 @@ public: * * ... * - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * acceptor.async_accept(accept_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MoveAcceptHandler> - ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, - void (asio::error_code, typename Protocol::socket)) - async_accept(ASIO_MOVE_ARG(MoveAcceptHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a MoveAcceptHandler. - ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, - handler, typename Protocol::socket) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_accept( - this->get_implementation(), static_cast<asio::io_context*>(0), - static_cast<endpoint_type*>(0), - ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<MoveAcceptHandler, - void (asio::error_code, - typename Protocol::socket)> init(handler); - - this->get_service().async_accept( - this->get_implementation(), static_cast<asio::io_context*>(0), - static_cast<endpoint_type*>(0), init.completion_handler); + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + executor_type>::other)) MoveAcceptToken + = default_completion_token_t<executor_type>> + auto async_accept( + MoveAcceptToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<MoveAcceptToken, + void (asio::error_code, typename Protocol::socket::template + rebind_executor<executor_type>::other)>( + declval<initiate_async_move_accept>(), token, + declval<const executor_type&>(), static_cast<endpoint_type*>(0), + static_cast<typename Protocol::socket::template + rebind_executor<executor_type>::other*>(0))) + { + return async_initiate<MoveAcceptToken, + void (asio::error_code, typename Protocol::socket::template + rebind_executor<executor_type>::other)>( + initiate_async_move_accept(this), token, + impl_.get_executor(), static_cast<endpoint_type*>(0), + static_cast<typename Protocol::socket::template + rebind_executor<executor_type>::other*>(0)); + } - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly + * accepted socket. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + template <typename Executor1> + typename Protocol::socket::template rebind_executor<Executor1>::other + accept(const Executor1& ex, + constraint_t< + is_executor<Executor1>::value + || execution::is_executor<Executor1>::value + > = 0) + { + asio::error_code ec; + typename Protocol::socket::template + rebind_executor<Executor1>::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + asio::detail::throw_error(ec, "accept"); + return peer; } /// Accept a new connection. @@ -1500,8 +1724,8 @@ public: * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. * - * @param io_context The io_context object to be used for the newly accepted - * socket. + * @param context The I/O execution context object to be used for the newly + * accepted socket. * * @returns A socket object representing the newly accepted connection. * @@ -1509,17 +1733,23 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::socket socket(acceptor.accept()); * @endcode */ - typename Protocol::socket accept(asio::io_context& io_context) + template <typename ExecutionContext> + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) { asio::error_code ec; - typename Protocol::socket peer( - this->get_service().accept(this->get_implementation(), - &io_context, static_cast<endpoint_type*>(0), ec)); + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); asio::detail::throw_error(ec, "accept"); return peer; } @@ -1533,7 +1763,7 @@ public: * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. * - * @param io_context The io_context object to be used for the newly accepted + * @param ex The I/O executor object to be used for the newly accepted * socket. * * @param ec Set to indicate what error occurred, if any. @@ -1543,44 +1773,105 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... - * asio::ip::tcp::socket socket(acceptor.accept(io_context2, ec)); + * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec)); * if (ec) * { * // An error occurred. * } * @endcode */ - typename Protocol::socket accept( - asio::io_context& io_context, asio::error_code& ec) + template <typename Executor1> + typename Protocol::socket::template rebind_executor<Executor1>::other + accept(const Executor1& ex, asio::error_code& ec, + constraint_t< + is_executor<Executor1>::value + || execution::is_executor<Executor1>::value + > = 0) { - return this->get_service().accept(this->get_implementation(), - &io_context, static_cast<endpoint_type*>(0), ec); + typename Protocol::socket::template + rebind_executor<Executor1>::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template <typename ExecutionContext> + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, asio::error_code& ec, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + { + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; } /// Start an asynchronous accept. /** - * This function is used to asynchronously accept a new connection. The - * function call always returns immediately. + * This function is used to asynchronously accept a new connection. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. * - * @param io_context The io_context object to be used for the newly accepted + * @param ex The I/O executor object to be used for the newly accepted * socket. * - * @param handler The handler to be called when the accept operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. - * typename Protocol::socket peer // On success, the newly accepted socket. + * // Result of operation. + * const asio::error_code& error, + * + * // On success, the newly accepted socket. + * typename Protocol::socket::template rebind_executor< + * Executor1>::other peer * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, + * typename Protocol::socket::template rebind_executor< + * Executor1>::other)) @endcode * * @par Example * @code @@ -1595,36 +1886,145 @@ public: * * ... * - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... - * acceptor.async_accept(io_context2, accept_handler); + * acceptor.async_accept(my_context2, accept_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MoveAcceptHandler> - ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, - void (asio::error_code, typename Protocol::socket)) - async_accept(asio::io_context& io_context, - ASIO_MOVE_ARG(MoveAcceptHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a MoveAcceptHandler. - ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, - handler, typename Protocol::socket) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_accept(this->get_implementation(), - &io_context, static_cast<endpoint_type*>(0), - ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<MoveAcceptHandler, + template <typename Executor1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + constraint_t<is_executor<Executor1>::value + || execution::is_executor<Executor1>::value, + Executor1>>::other)) MoveAcceptToken + = default_completion_token_t<executor_type>> + auto async_accept(const Executor1& ex, + MoveAcceptToken&& token = default_completion_token_t<executor_type>(), + constraint_t< + is_executor<Executor1>::value + || execution::is_executor<Executor1>::value + > = 0) + -> decltype( + async_initiate<MoveAcceptToken, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + Executor1>::other)>( + declval<initiate_async_move_accept>(), token, + ex, static_cast<endpoint_type*>(0), + static_cast<typename Protocol::socket::template + rebind_executor<Executor1>::other*>(0))) + { + return async_initiate<MoveAcceptToken, void (asio::error_code, - typename Protocol::socket)> init(handler); - - this->get_service().async_accept(this->get_implementation(), - &io_context, static_cast<endpoint_type*>(0), init.completion_handler); + typename Protocol::socket::template rebind_executor< + Executor1>::other)>( + initiate_async_move_accept(this), token, + ex, static_cast<endpoint_type*>(0), + static_cast<typename Protocol::socket::template + rebind_executor<Executor1>::other*>(0)); + } - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // On success, the newly accepted socket. + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other peer + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other)) @endcode + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_accept(my_context2, accept_handler); + * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total + */ + template <typename ExecutionContext, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)) MoveAcceptToken + = default_completion_token_t<executor_type>> + auto async_accept(ExecutionContext& context, + MoveAcceptToken&& token = default_completion_token_t<executor_type>(), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + -> decltype( + async_initiate<MoveAcceptToken, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)>( + declval<initiate_async_move_accept>(), token, + context.get_executor(), static_cast<endpoint_type*>(0), + static_cast<typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other*>(0))) + { + return async_initiate<MoveAcceptToken, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)>( + initiate_async_move_accept(this), token, + context.get_executor(), static_cast<endpoint_type*>(0), + static_cast<typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other*>(0)); } /// Accept a new connection. @@ -1645,18 +2045,20 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::endpoint endpoint; * asio::ip::tcp::socket socket(acceptor.accept(endpoint)); * @endcode */ - typename Protocol::socket accept(endpoint_type& peer_endpoint) + typename Protocol::socket::template rebind_executor<executor_type>::other + accept(endpoint_type& peer_endpoint) { asio::error_code ec; - typename Protocol::socket peer( - this->get_service().accept(this->get_implementation(), - static_cast<asio::io_context*>(0), &peer_endpoint, ec)); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); asio::detail::throw_error(ec, "accept"); return peer; } @@ -1680,7 +2082,7 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::endpoint endpoint; * asio::ip::tcp::socket socket(acceptor.accept(endpoint, ec)); @@ -1690,17 +2092,21 @@ public: * } * @endcode */ - typename Protocol::socket accept( - endpoint_type& peer_endpoint, asio::error_code& ec) + typename Protocol::socket::template rebind_executor<executor_type>::other + accept(endpoint_type& peer_endpoint, asio::error_code& ec) { - return this->get_service().accept(this->get_implementation(), - static_cast<asio::io_context*>(0), &peer_endpoint, ec); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; } /// Start an asynchronous accept. /** - * This function is used to asynchronously accept a new connection. The - * function call always returns immediately. + * This function is used to asynchronously accept a new connection. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. @@ -1708,19 +2114,30 @@ public: * @param peer_endpoint An endpoint object into which the endpoint of the * remote peer will be written. Ownership of the peer_endpoint object is * retained by the caller, which must guarantee that it is valid until the - * handler is called. + * completion handler is called. * - * @param handler The handler to be called when the accept operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. - * typename Protocol::socket peer // On success, the newly accepted socket. + * // Result of operation. + * const asio::error_code& error, + * + * // On success, the newly accepted socket. + * typename Protocol::socket::template + * rebind_executor<executor_type>::other peer * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, + * typename Protocol::socket::template + * rebind_executor<executor_type>::other)) @endcode * * @par Example * @code @@ -1735,38 +2152,45 @@ public: * * ... * - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::endpoint endpoint; * acceptor.async_accept(endpoint, accept_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MoveAcceptHandler> - ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, - void (asio::error_code, typename Protocol::socket)) - async_accept(endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(MoveAcceptHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a MoveAcceptHandler. - ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, - handler, typename Protocol::socket) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_accept(this->get_implementation(), - static_cast<asio::io_context*>(0), &peer_endpoint, - ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<MoveAcceptHandler, - void (asio::error_code, - typename Protocol::socket)> init(handler); - - this->get_service().async_accept(this->get_implementation(), - static_cast<asio::io_context*>(0), &peer_endpoint, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + executor_type>::other)) MoveAcceptToken + = default_completion_token_t<executor_type>> + auto async_accept(endpoint_type& peer_endpoint, + MoveAcceptToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<MoveAcceptToken, + void (asio::error_code, typename Protocol::socket::template + rebind_executor<executor_type>::other)>( + declval<initiate_async_move_accept>(), token, + declval<const executor_type&>(), &peer_endpoint, + static_cast<typename Protocol::socket::template + rebind_executor<executor_type>::other*>(0))) + { + return async_initiate<MoveAcceptToken, + void (asio::error_code, typename Protocol::socket::template + rebind_executor<executor_type>::other)>( + initiate_async_move_accept(this), token, + impl_.get_executor(), &peer_endpoint, + static_cast<typename Protocol::socket::template + rebind_executor<executor_type>::other*>(0)); } /// Accept a new connection. @@ -1778,7 +2202,7 @@ public: * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. * - * @param io_context The io_context object to be used for the newly accepted + * @param ex The I/O executor object to be used for the newly accepted * socket. * * @param peer_endpoint An endpoint object into which the endpoint of the @@ -1790,20 +2214,26 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::endpoint endpoint; * asio::ip::tcp::socket socket( - * acceptor.accept(io_context2, endpoint)); + * acceptor.accept(my_context2, endpoint)); * @endcode */ - typename Protocol::socket accept( - asio::io_context& io_context, endpoint_type& peer_endpoint) + template <typename Executor1> + typename Protocol::socket::template rebind_executor<Executor1>::other + accept(const Executor1& ex, endpoint_type& peer_endpoint, + constraint_t< + is_executor<Executor1>::value + || execution::is_executor<Executor1>::value + > = 0) { asio::error_code ec; - typename Protocol::socket peer( - this->get_service().accept(this->get_implementation(), - &io_context, &peer_endpoint, ec)); + typename Protocol::socket::template + rebind_executor<Executor1>::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); asio::detail::throw_error(ec, "accept"); return peer; } @@ -1817,7 +2247,52 @@ public: * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. * - * @param io_context The io_context object to be used for the newly accepted + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint)); + * @endcode + */ + template <typename ExecutionContext> + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, endpoint_type& peer_endpoint, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + { + asio::error_code ec; + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted * socket. * * @param peer_endpoint An endpoint object into which the endpoint of the @@ -1830,51 +2305,121 @@ public: * * @par Example * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::endpoint endpoint; * asio::ip::tcp::socket socket( - * acceptor.accept(io_context2, endpoint, ec)); + * acceptor.accept(my_context2, endpoint, ec)); * if (ec) * { * // An error occurred. * } * @endcode */ - typename Protocol::socket accept(asio::io_context& io_context, - endpoint_type& peer_endpoint, asio::error_code& ec) + template <typename Executor1> + typename Protocol::socket::template rebind_executor<Executor1>::other + accept(const executor_type& ex, + endpoint_type& peer_endpoint, asio::error_code& ec, + constraint_t< + is_executor<Executor1>::value + || execution::is_executor<Executor1>::value + > = 0) + { + typename Protocol::socket::template + rebind_executor<Executor1>::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template <typename ExecutionContext> + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, + endpoint_type& peer_endpoint, asio::error_code& ec, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) { - return this->get_service().accept(this->get_implementation(), - &io_context, &peer_endpoint, ec); + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; } /// Start an asynchronous accept. /** - * This function is used to asynchronously accept a new connection. The - * function call always returns immediately. + * This function is used to asynchronously accept a new connection. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. * * This overload requires that the Protocol template parameter satisfy the * AcceptableProtocol type requirements. * - * @param io_context The io_context object to be used for the newly accepted + * @param ex The I/O executor object to be used for the newly accepted * socket. * * @param peer_endpoint An endpoint object into which the endpoint of the * remote peer will be written. Ownership of the peer_endpoint object is * retained by the caller, which must guarantee that it is valid until the - * handler is called. + * completion handler is called. * - * @param handler The handler to be called when the accept operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. - * typename Protocol::socket peer // On success, the newly accepted socket. + * // Result of operation. + * const asio::error_code& error, + * + * // On success, the newly accepted socket. + * typename Protocol::socket::template rebind_executor< + * Executor1>::other peer * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, + * typename Protocol::socket::template rebind_executor< + * Executor1>::other)) @endcode * * @par Example * @code @@ -1889,48 +2434,275 @@ public: * * ... * - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::ip::tcp::endpoint endpoint; - * acceptor.async_accept(io_context2, endpoint, accept_handler); + * acceptor.async_accept(my_context2, endpoint, accept_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MoveAcceptHandler> - ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, - void (asio::error_code, typename Protocol::socket)) - async_accept(asio::io_context& io_context, - endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(MoveAcceptHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a MoveAcceptHandler. - ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, - handler, typename Protocol::socket) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_accept( - this->get_implementation(), &io_context, &peer_endpoint, - ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<MoveAcceptHandler, + template <typename Executor1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + constraint_t<is_executor<Executor1>::value + || execution::is_executor<Executor1>::value, + Executor1>>::other)) MoveAcceptToken + = default_completion_token_t<executor_type>> + auto async_accept(const Executor1& ex, endpoint_type& peer_endpoint, + MoveAcceptToken&& token = default_completion_token_t<executor_type>(), + constraint_t< + is_executor<Executor1>::value + || execution::is_executor<Executor1>::value + > = 0) + -> decltype( + async_initiate<MoveAcceptToken, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + Executor1>::other)>( + declval<initiate_async_move_accept>(), token, ex, &peer_endpoint, + static_cast<typename Protocol::socket::template + rebind_executor<Executor1>::other*>(0))) + { + return async_initiate<MoveAcceptToken, void (asio::error_code, - typename Protocol::socket)> init(handler); - - this->get_service().async_accept(this->get_implementation(), - &io_context, &peer_endpoint, init.completion_handler); + typename Protocol::socket::template rebind_executor< + Executor1>::other)>( + initiate_async_move_accept(this), token, ex, &peer_endpoint, + static_cast<typename Protocol::socket::template + rebind_executor<Executor1>::other*>(0)); + } - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the accept completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // On success, the newly accepted socket. + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other peer + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other)) @endcode + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(my_context); + * ... + * asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(my_context2, endpoint, accept_handler); + * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total + */ + template <typename ExecutionContext, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)) MoveAcceptToken + = default_completion_token_t<executor_type>> + auto async_accept(ExecutionContext& context, endpoint_type& peer_endpoint, + MoveAcceptToken&& token = default_completion_token_t<executor_type>(), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + -> decltype( + async_initiate<MoveAcceptToken, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)>( + declval<initiate_async_move_accept>(), token, + context.get_executor(), &peer_endpoint, + static_cast<typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other*>(0))) + { + return async_initiate<MoveAcceptToken, + void (asio::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)>( + initiate_async_move_accept(this), token, + context.get_executor(), &peer_endpoint, + static_cast<typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other*>(0)); } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +private: + // Disallow copying and assignment. + basic_socket_acceptor(const basic_socket_acceptor&) = delete; + basic_socket_acceptor& operator=( + const basic_socket_acceptor&) = delete; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_socket_acceptor* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue<WaitHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket_acceptor* self_; + }; + + class initiate_async_accept + { + public: + typedef Executor executor_type; + + explicit initiate_async_accept(basic_socket_acceptor* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename AcceptHandler, typename Protocol1, typename Executor1> + void operator()(AcceptHandler&& handler, + basic_socket<Protocol1, Executor1>* peer, + endpoint_type* peer_endpoint) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a AcceptHandler. + ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; + + detail::non_const_lvalue<AcceptHandler> handler2(handler); + self_->impl_.get_service().async_accept( + self_->impl_.get_implementation(), *peer, peer_endpoint, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket_acceptor* self_; + }; + + class initiate_async_move_accept + { + public: + typedef Executor executor_type; + + explicit initiate_async_move_accept(basic_socket_acceptor* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename MoveAcceptHandler, typename Executor1, typename Socket> + void operator()(MoveAcceptHandler&& handler, + const Executor1& peer_ex, endpoint_type* peer_endpoint, Socket*) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a MoveAcceptHandler. + ASIO_MOVE_ACCEPT_HANDLER_CHECK( + MoveAcceptHandler, handler, Socket) type_check; + + detail::non_const_lvalue<MoveAcceptHandler> handler2(handler); + self_->impl_.get_service().async_move_accept( + self_->impl_.get_implementation(), peer_ex, peer_endpoint, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket_acceptor* self_; + }; + +#if defined(ASIO_WINDOWS_RUNTIME) + detail::io_object_impl< + detail::null_socket_service<Protocol>, Executor> impl_; +#elif defined(ASIO_HAS_IOCP) + detail::io_object_impl< + detail::win_iocp_socket_service<Protocol>, Executor> impl_; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + detail::io_object_impl< + detail::io_uring_socket_service<Protocol>, Executor> impl_; +#else + detail::io_object_impl< + detail::reactive_socket_service<Protocol>, Executor> impl_; +#endif }; } // namespace asio #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP diff --git a/3rdparty/asio/include/asio/basic_socket_iostream.hpp b/3rdparty/asio/include/asio/basic_socket_iostream.hpp index ad4759bec29..902898d9502 100644 --- a/3rdparty/asio/include/asio/basic_socket_iostream.hpp +++ b/3rdparty/asio/include/asio/basic_socket_iostream.hpp @@ -2,7 +2,7 @@ // basic_socket_iostream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,61 +23,6 @@ #include <ostream> #include "asio/basic_socket_streambuf.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/stream_socket_service.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) - -# include "asio/detail/variadic_templates.hpp" - -// A macro that should expand to: -// template <typename T1, ..., typename Tn> -// explicit basic_socket_iostream(T1 x1, ..., Tn xn) -// : std::basic_iostream<char>( -// &this->detail::socket_iostream_base< -// Protocol ASIO_SVC_TARG, Clock, -// WaitTraits ASIO_SVC_TARG1>::streambuf_) -// { -// if (rdbuf()->connect(x1, ..., xn) == 0) -// this->setstate(std::ios_base::failbit); -// } -// This macro should only persist within this file. - -# define ASIO_PRIVATE_CTR_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - explicit basic_socket_iostream(ASIO_VARIADIC_BYVAL_PARAMS(n)) \ - : std::basic_iostream<char>( \ - &this->detail::socket_iostream_base< \ - Protocol ASIO_SVC_TARG, Clock, \ - WaitTraits ASIO_SVC_TARG1>::streambuf_) \ - { \ - this->setf(std::ios_base::unitbuf); \ - if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ - this->setstate(std::ios_base::failbit); \ - } \ - /**/ - -// A macro that should expand to: -// template <typename T1, ..., typename Tn> -// void connect(T1 x1, ..., Tn xn) -// { -// if (rdbuf()->connect(x1, ..., xn) == 0) -// this->setstate(std::ios_base::failbit); -// } -// This macro should only persist within this file. - -# define ASIO_PRIVATE_CONNECT_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - void connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \ - { \ - if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ - this->setstate(std::ios_base::failbit); \ - } \ - /**/ - -#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) - #include "asio/detail/push_options.hpp" namespace asio { @@ -85,8 +30,7 @@ namespace detail { // A separate base class is used to ensure that the streambuf is initialised // prior to the basic_socket_iostream's basic_iostream base class. -template <typename Protocol ASIO_SVC_TPARAM, - typename Clock, typename WaitTraits ASIO_SVC_TPARAM1> +template <typename Protocol, typename Clock, typename WaitTraits> class socket_iostream_base { protected: @@ -94,7 +38,6 @@ protected: { } -#if defined(ASIO_HAS_MOVE) socket_iostream_base(socket_iostream_base&& other) : streambuf_(std::move(other.streambuf_)) { @@ -110,10 +53,8 @@ protected: streambuf_ = std::move(other.streambuf_); return *this; } -#endif // defined(ASIO_HAS_MOVE) - basic_socket_streambuf<Protocol ASIO_SVC_TARG, - Clock, WaitTraits ASIO_SVC_TARG1> streambuf_; + basic_socket_streambuf<Protocol, Clock, WaitTraits> streambuf_; }; } // namespace detail @@ -122,17 +63,17 @@ protected: #define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL // Forward declaration with defaulted arguments. -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), -#if defined(ASIO_HAS_BOOST_DATE_TIME) +template <typename Protocol, +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typename Clock = boost::posix_time::ptime, - typename WaitTraits = time_traits<Clock> - ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> -#else + typename WaitTraits = time_traits<Clock>> +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typename Clock = chrono::steady_clock, - typename WaitTraits = wait_traits<Clock> - ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> -#endif + typename WaitTraits = wait_traits<Clock>> +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) class basic_socket_iostream; #endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) @@ -141,24 +82,25 @@ class basic_socket_iostream; #if defined(GENERATING_DOCUMENTATION) template <typename Protocol, typename Clock = chrono::steady_clock, - typename WaitTraits = wait_traits<Clock> > + typename WaitTraits = wait_traits<Clock>> #else // defined(GENERATING_DOCUMENTATION) -template <typename Protocol ASIO_SVC_TPARAM, - typename Clock, typename WaitTraits ASIO_SVC_TPARAM1> +template <typename Protocol, typename Clock, typename WaitTraits> #endif // defined(GENERATING_DOCUMENTATION) class basic_socket_iostream - : private detail::socket_iostream_base<Protocol - ASIO_SVC_TARG, Clock, WaitTraits ASIO_SVC_TARG1>, + : private detail::socket_iostream_base<Protocol, Clock, WaitTraits>, public std::basic_iostream<char> { private: // These typedefs are intended keep this class's implementation independent // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. -#if defined(ASIO_HAS_BOOST_DATE_TIME) +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typedef WaitTraits traits_helper; -#else +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper; -#endif +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) public: /// The protocol type. @@ -195,22 +137,18 @@ public: basic_socket_iostream() : std::basic_iostream<char>( &this->detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>::streambuf_) + Protocol, Clock, WaitTraits>::streambuf_) { this->setf(std::ios_base::unitbuf); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Construct a basic_socket_iostream from the supplied socket. explicit basic_socket_iostream(basic_stream_socket<protocol_type> s) : detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>(std::move(s)), + Protocol, Clock, WaitTraits>(std::move(s)), std::basic_iostream<char>( &this->detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>::streambuf_) + Protocol, Clock, WaitTraits>::streambuf_) { this->setf(std::ios_base::unitbuf); } @@ -218,13 +156,11 @@ public: /// Move-construct a basic_socket_iostream from another. basic_socket_iostream(basic_socket_iostream&& other) : detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>(std::move(other)), + Protocol, Clock, WaitTraits>(std::move(other)), std::basic_iostream<char>(std::move(other)) { this->set_rdbuf(&this->detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>::streambuf_); + Protocol, Clock, WaitTraits>::streambuf_); } /// Move-assign a basic_socket_iostream from another. @@ -232,56 +168,39 @@ public: { std::basic_iostream<char>::operator=(std::move(other)); detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>::operator=(std::move(other)); + Protocol, Clock, WaitTraits>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) -#if defined(GENERATING_DOCUMENTATION) /// Establish a connection to an endpoint corresponding to a resolver query. /** * This constructor automatically establishes a connection based on the * supplied resolver query parameters. The arguments are used to construct * a resolver query object. */ - template <typename T1, ..., typename TN> - explicit basic_socket_iostream(T1 t1, ..., TN tn); -#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) template <typename... T> explicit basic_socket_iostream(T... x) : std::basic_iostream<char>( &this->detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>::streambuf_) + Protocol, Clock, WaitTraits>::streambuf_) { this->setf(std::ios_base::unitbuf); if (rdbuf()->connect(x...) == 0) this->setstate(std::ios_base::failbit); } -#else - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CTR_DEF) -#endif -#if defined(GENERATING_DOCUMENTATION) /// Establish a connection to an endpoint corresponding to a resolver query. /** * This function automatically establishes a connection based on the supplied * resolver query parameters. The arguments are used to construct a resolver * query object. */ - template <typename T1, ..., typename TN> - void connect(T1 t1, ..., TN tn); -#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) template <typename... T> void connect(T... x) { if (rdbuf()->connect(x...) == 0) this->setstate(std::ios_base::failbit); } -#else - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF) -#endif /// Close the connection. void close() @@ -291,18 +210,15 @@ public: } /// Return a pointer to the underlying streambuf. - basic_socket_streambuf<Protocol ASIO_SVC_TARG, - Clock, WaitTraits ASIO_SVC_TARG1>* rdbuf() const + basic_socket_streambuf<Protocol, Clock, WaitTraits>* rdbuf() const { - return const_cast<basic_socket_streambuf<Protocol ASIO_SVC_TARG, - Clock, WaitTraits ASIO_SVC_TARG1>*>( + return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>( &this->detail::socket_iostream_base< - Protocol ASIO_SVC_TARG, Clock, - WaitTraits ASIO_SVC_TARG1>::streambuf_); + Protocol, Clock, WaitTraits>::streambuf_); } /// Get a reference to the underlying socket. - basic_socket<Protocol ASIO_SVC_TARG>& socket() + basic_socket<Protocol>& socket() { return rdbuf()->socket(); } @@ -401,20 +317,15 @@ public: private: // Disallow copying and assignment. - basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED; + basic_socket_iostream(const basic_socket_iostream&) = delete; basic_socket_iostream& operator=( - const basic_socket_iostream&) ASIO_DELETED; + const basic_socket_iostream&) = delete; }; } // namespace asio #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) -# undef ASIO_PRIVATE_CTR_DEF -# undef ASIO_PRIVATE_CONNECT_DEF -#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) - #endif // !defined(ASIO_NO_IOSTREAM) #endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP diff --git a/3rdparty/asio/include/asio/basic_socket_streambuf.hpp b/3rdparty/asio/include/asio/basic_socket_streambuf.hpp index 42fb3cacd75..e3a5f836382 100644 --- a/3rdparty/asio/include/asio/basic_socket_streambuf.hpp +++ b/3rdparty/asio/include/asio/basic_socket_streambuf.hpp @@ -2,7 +2,7 @@ // basic_socket_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -28,55 +28,14 @@ #include "asio/detail/throw_error.hpp" #include "asio/io_context.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/stream_socket_service.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_BOOST_DATE_TIME) -# if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/deadline_timer_service.hpp" -# else // defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/detail/deadline_timer_service.hpp" -# endif // defined(ASIO_ENABLE_OLD_SERVICES) -#else +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +# include "asio/detail/deadline_timer_service.hpp" +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) # include "asio/steady_timer.hpp" -#endif - -#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) - -# include "asio/detail/variadic_templates.hpp" - -// A macro that should expand to: -// template <typename T1, ..., typename Tn> -// basic_socket_streambuf* connect(T1 x1, ..., Tn xn) -// { -// init_buffers(); -// typedef typename Protocol::resolver resolver_type; -// resolver_type resolver(socket().get_executor().context()); -// connect_to_endpoints( -// resolver.resolve(x1, ..., xn, ec_)); -// return !ec_ ? this : 0; -// } -// This macro should only persist within this file. - -# define ASIO_PRIVATE_CONNECT_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - basic_socket_streambuf* connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \ - { \ - init_buffers(); \ - typedef typename Protocol::resolver resolver_type; \ - resolver_type resolver(socket().get_executor().context()); \ - connect_to_endpoints( \ - resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \ - return !ec_ ? this : 0; \ - } \ - /**/ - -#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) - -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# define ASIO_SVC_T1 detail::deadline_timer_service<traits_helper> -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) #include "asio/detail/push_options.hpp" @@ -121,17 +80,17 @@ protected: #define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL // Forward declaration with defaulted arguments. -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), -#if defined(ASIO_HAS_BOOST_DATE_TIME) +template <typename Protocol, +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typename Clock = boost::posix_time::ptime, - typename WaitTraits = time_traits<Clock> - ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> -#else + typename WaitTraits = time_traits<Clock>> +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typename Clock = chrono::steady_clock, - typename WaitTraits = wait_traits<Clock> - ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> -#endif + typename WaitTraits = wait_traits<Clock>> +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) class basic_socket_streambuf; #endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) @@ -140,29 +99,31 @@ class basic_socket_streambuf; #if defined(GENERATING_DOCUMENTATION) template <typename Protocol, typename Clock = chrono::steady_clock, - typename WaitTraits = wait_traits<Clock> > + typename WaitTraits = wait_traits<Clock>> #else // defined(GENERATING_DOCUMENTATION) -template <typename Protocol ASIO_SVC_TPARAM, - typename Clock, typename WaitTraits ASIO_SVC_TPARAM1> +template <typename Protocol, typename Clock, typename WaitTraits> #endif // defined(GENERATING_DOCUMENTATION) class basic_socket_streambuf : public std::streambuf, private detail::socket_streambuf_io_context, private detail::socket_streambuf_buffers, #if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - private basic_socket<Protocol ASIO_SVC_TARG> + private basic_socket<Protocol> #else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) - public basic_socket<Protocol ASIO_SVC_TARG> + public basic_socket<Protocol> #endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) { private: // These typedefs are intended keep this class's implementation independent // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. -#if defined(ASIO_HAS_BOOST_DATE_TIME) +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typedef WaitTraits traits_helper; -#else +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper; -#endif +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) public: /// The protocol type. @@ -198,17 +159,16 @@ public: /// Construct a basic_socket_streambuf without establishing a connection. basic_socket_streambuf() : detail::socket_streambuf_io_context(new io_context), - basic_socket<Protocol ASIO_SVC_TARG>(*default_io_context_), + basic_socket<Protocol>(*default_io_context_), expiry_time_(max_expiry_time()) { init_buffers(); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Construct a basic_socket_streambuf from the supplied socket. explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s) : detail::socket_streambuf_io_context(0), - basic_socket<Protocol ASIO_SVC_TARG>(std::move(s)), + basic_socket<Protocol>(std::move(s)), expiry_time_(max_expiry_time()) { init_buffers(); @@ -217,7 +177,7 @@ public: /// Move-construct a basic_socket_streambuf from another. basic_socket_streambuf(basic_socket_streambuf&& other) : detail::socket_streambuf_io_context(other), - basic_socket<Protocol ASIO_SVC_TARG>(std::move(other.socket())), + basic_socket<Protocol>(std::move(other.socket())), ec_(other.ec_), expiry_time_(other.expiry_time_) { @@ -248,7 +208,6 @@ public: other.init_buffers(); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor flushes buffered data. virtual ~basic_socket_streambuf() @@ -272,7 +231,6 @@ public: return !ec_ ? this : 0; } -#if defined(GENERATING_DOCUMENTATION) /// Establish a connection. /** * This function automatically establishes a connection based on the supplied @@ -282,21 +240,15 @@ public: * @return \c this if a connection was successfully established, a null * pointer otherwise. */ - template <typename T1, ..., typename TN> - basic_socket_streambuf* connect(T1 t1, ..., TN tn); -#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) template <typename... T> basic_socket_streambuf* connect(T... x) { init_buffers(); typedef typename Protocol::resolver resolver_type; - resolver_type resolver(socket().get_executor().context()); + resolver_type resolver(socket().get_executor()); connect_to_endpoints(resolver.resolve(x..., ec_)); return !ec_ ? this : 0; } -#else - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF) -#endif /// Close the connection. /** @@ -313,7 +265,7 @@ public: } /// Get a reference to the underlying socket. - basic_socket<Protocol ASIO_SVC_TARG>& socket() + basic_socket<Protocol>& socket() { return *this; } @@ -566,9 +518,9 @@ protected: private: // Disallow copying and assignment. - basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED; + basic_socket_streambuf(const basic_socket_streambuf&) = delete; basic_socket_streambuf& operator=( - const basic_socket_streambuf&) ASIO_DELETED; + const basic_socket_streambuf&) = delete; void init_buffers() { @@ -666,11 +618,14 @@ private: // Helper function to get the maximum expiry time. static time_point max_expiry_time() { -#if defined(ASIO_HAS_BOOST_DATE_TIME) +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) return boost::posix_time::pos_infin; #else // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) return (time_point::max)(); #endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) } enum { putback_max = 8 }; @@ -682,14 +637,6 @@ private: #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T1 -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - -#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) -# undef ASIO_PRIVATE_CONNECT_DEF -#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) - #endif // !defined(ASIO_NO_IOSTREAM) #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP diff --git a/3rdparty/asio/include/asio/basic_stream_file.hpp b/3rdparty/asio/include/asio/basic_stream_file.hpp new file mode 100644 index 00000000000..4b2ca8775e5 --- /dev/null +++ b/3rdparty/asio/include/asio/basic_stream_file.hpp @@ -0,0 +1,744 @@ +// +// basic_stream_file.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BASIC_STREAM_FILE_HPP +#define ASIO_BASIC_STREAM_FILE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <cstddef> +#include "asio/async_result.hpp" +#include "asio/basic_file.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(ASIO_BASIC_STREAM_FILE_FWD_DECL) +#define ASIO_BASIC_STREAM_FILE_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Executor = any_io_executor> +class basic_stream_file; + +#endif // !defined(ASIO_BASIC_STREAM_FILE_FWD_DECL) + +/// Provides stream-oriented file functionality. +/** + * The basic_stream_file class template provides asynchronous and blocking + * stream-oriented file functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template <typename Executor> +class basic_stream_file + : public basic_file<Executor> +{ +private: + class initiate_async_write_some; + class initiate_async_read_some; + +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the file type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The file type when rebound to the specified executor. + typedef basic_stream_file<Executor1> other; + }; + + /// The native representation of a file. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_file<Executor>::native_handle_type native_handle_type; +#endif + + /// Construct a basic_stream_file without opening it. + /** + * This constructor initialises a file without opening it. The file needs to + * be opened before data can be read from or or written to it. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + */ + explicit basic_stream_file(const executor_type& ex) + : basic_file<Executor>(ex) + { + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + } + + /// Construct a basic_stream_file without opening it. + /** + * This constructor initialises a file without opening it. The file needs to + * be opened before data can be read from or or written to it. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + */ + template <typename ExecutionContext> + explicit basic_stream_file(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context) + { + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + } + + /// Construct and open a basic_stream_file. + /** + * This constructor initialises and opens a file. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + basic_stream_file(const executor_type& ex, + const char* path, file_base::flags open_flags) + : basic_file<Executor>(ex) + { + asio::error_code ec; + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + this->impl_.get_service().open( + this->impl_.get_implementation(), + path, open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_stream_file. + /** + * This constructor initialises and opens a file. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_stream_file(ExecutionContext& context, + const char* path, file_base::flags open_flags, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context) + { + asio::error_code ec; + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + this->impl_.get_service().open( + this->impl_.get_implementation(), + path, open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_stream_file. + /** + * This constructor initialises and opens a file. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + basic_stream_file(const executor_type& ex, + const std::string& path, file_base::flags open_flags) + : basic_file<Executor>(ex) + { + asio::error_code ec; + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + this->impl_.get_service().open( + this->impl_.get_implementation(), + path.c_str(), open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_stream_file. + /** + * This constructor initialises and opens a file. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param path The path name identifying the file to be opened. + * + * @param open_flags A set of flags that determine how the file should be + * opened. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_stream_file(ExecutionContext& context, + const std::string& path, file_base::flags open_flags, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context) + { + asio::error_code ec; + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + this->impl_.get_service().open( + this->impl_.get_implementation(), + path.c_str(), open_flags, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_stream_file on an existing native file. + /** + * This constructor initialises a stream file object to hold an existing + * native file. + * + * @param ex The I/O executor that the file will use, by default, to + * dispatch handlers for any asynchronous operations performed on the file. + * + * @param native_file The new underlying file implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_stream_file(const executor_type& ex, + const native_handle_type& native_file) + : basic_file<Executor>(ex, native_file) + { + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + } + + /// Construct a basic_stream_file on an existing native file. + /** + * This constructor initialises a stream file object to hold an existing + * native file. + * + * @param context An execution context which provides the I/O executor that + * the file will use, by default, to dispatch handlers for any asynchronous + * operations performed on the file. + * + * @param native_file The new underlying file implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_stream_file(ExecutionContext& context, + const native_handle_type& native_file, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(context, native_file) + { + this->impl_.get_service().set_is_stream( + this->impl_.get_implementation(), true); + } + + /// Move-construct a basic_stream_file from another. + /** + * This constructor moves a stream file from one object to another. + * + * @param other The other basic_stream_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_file(const executor_type&) + * constructor. + */ + basic_stream_file(basic_stream_file&& other) noexcept + : basic_file<Executor>(std::move(other)) + { + } + + /// Move-assign a basic_stream_file from another. + /** + * This assignment operator moves a stream file from one object to another. + * + * @param other The other basic_stream_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_file(const executor_type&) + * constructor. + */ + basic_stream_file& operator=(basic_stream_file&& other) + { + basic_file<Executor>::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_stream_file from a file of another executor + /// type. + /** + * This constructor moves a stream file from one object to another. + * + * @param other The other basic_stream_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_file(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_stream_file(basic_stream_file<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_file<Executor>(std::move(other)) + { + } + + /// Move-assign a basic_stream_file from a file of another executor type. + /** + * This assignment operator moves a stream file from one object to another. + * + * @param other The other basic_stream_file object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_file(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_stream_file& + > operator=(basic_stream_file<Executor1>&& other) + { + basic_file<Executor>::operator=(std::move(other)); + return *this; + } + + /// Destroys the file. + /** + * This function destroys the file, cancelling any outstanding asynchronous + * operations associated with the file as if by calling @c cancel. + */ + ~basic_stream_file() + { + } + + /// Seek to a position in the file. + /** + * This function updates the current position in the file. + * + * @param offset The requested position in the file, relative to @c whence. + * + * @param whence One of @c seek_set, @c seek_cur or @c seek_end. + * + * @returns The new position relative to the beginning of the file. + * + * @throws asio::system_error Thrown on failure. + */ + uint64_t seek(int64_t offset, file_base::seek_basis whence) + { + asio::error_code ec; + uint64_t n = this->impl_.get_service().seek( + this->impl_.get_implementation(), offset, whence, ec); + asio::detail::throw_error(ec, "seek"); + return n; + } + + /// Seek to a position in the file. + /** + * This function updates the current position in the file. + * + * @param offset The requested position in the file, relative to @c whence. + * + * @param whence One of @c seek_set, @c seek_cur or @c seek_end. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The new position relative to the beginning of the file. + */ + uint64_t seek(int64_t offset, file_base::seek_basis whence, + asio::error_code& ec) + { + return this->impl_.get_service().seek( + this->impl_.get_implementation(), offset, whence, ec); + } + + /// Write some data to the file. + /** + * This function is used to write data to the stream file. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the file. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the end of the file was reached. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * file.write_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the file. + /** + * This function is used to write data to the stream file. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the file. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream file. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. + * + * @param buffers One or more data buffers to be written to the file. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * file.async_write_some(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total + */ + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_write_some>(), token, buffers)) + { + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some(this), token, buffers); + } + + /// Read some data from the file. + /** + * This function is used to read data from the stream file. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the end of the file was reached. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * file.read_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the file. + /** + * This function is used to read data from the stream file. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream file. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * file.async_read_some(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total + */ + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some>(), token, buffers)) + { + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some(this), token, buffers); + } + +private: + // Disallow copying and assignment. + basic_stream_file(const basic_stream_file&) = delete; + basic_stream_file& operator=(const basic_stream_file&) = delete; + + class initiate_async_write_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_stream_file* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_file* self_; + }; + + class initiate_async_read_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_stream_file* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_file* self_; + }; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_FILE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_STREAM_FILE_HPP diff --git a/3rdparty/asio/include/asio/basic_stream_socket.hpp b/3rdparty/asio/include/asio/basic_stream_socket.hpp index 31e685098a5..e3a79450037 100644 --- a/3rdparty/asio/include/asio/basic_stream_socket.hpp +++ b/3rdparty/asio/include/asio/basic_stream_socket.hpp @@ -2,7 +2,7 @@ // basic_stream_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,17 +20,23 @@ #include "asio/async_result.hpp" #include "asio/basic_socket.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/stream_socket_service.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #include "asio/detail/push_options.hpp" namespace asio { +#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL) +#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> +class basic_stream_socket; + +#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL) + /// Provides stream-oriented socket functionality. /** * The basic_stream_socket class template provides asynchronous and blocking @@ -40,21 +46,42 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * + * Synchronous @c send, @c receive, @c connect, and @c shutdown operations are + * thread safe with respect to each other, if the underlying operating system + * calls are also thread safe. This means that it is permitted to perform + * concurrent calls to these synchronous operations on a single socket object. + * Other synchronous operations, such as @c open or @c close, are not thread + * safe. + * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>)> +template <typename Protocol, typename Executor> class basic_stream_socket - : public basic_socket<Protocol ASIO_SVC_TARG> + : public basic_socket<Protocol, Executor> { +private: + class initiate_async_send; + class initiate_async_receive; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_stream_socket<Protocol, Executor1> other; + }; + /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else - typedef typename basic_socket< - Protocol ASIO_SVC_TARG>::native_handle_type native_handle_type; + typedef typename basic_socket<Protocol, + Executor>::native_handle_type native_handle_type; #endif /// The protocol type. @@ -69,11 +96,30 @@ public: * needs to be opened and then connected or accepted before data can be sent * or received on it. * - * @param io_context The io_context object that the stream socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. */ - explicit basic_stream_socket(asio::io_context& io_context) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context) + explicit basic_stream_socket(const executor_type& ex) + : basic_socket<Protocol, Executor>(ex) + { + } + + /// Construct a basic_stream_socket without opening it. + /** + * This constructor creates a stream socket without opening it. The socket + * needs to be opened and then connected or accepted before data can be sent + * or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template <typename ExecutionContext> + explicit basic_stream_socket(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context) { } @@ -82,16 +128,38 @@ public: * This constructor creates and opens a stream socket. The socket needs to be * connected or accepted before data can be sent or received on it. * - * @param io_context The io_context object that the stream socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ - basic_stream_socket(asio::io_context& io_context, - const protocol_type& protocol) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, protocol) + basic_stream_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket<Protocol, Executor>(ex, protocol) + { + } + + /// Construct and open a basic_stream_socket. + /** + * This constructor creates and opens a stream socket. The socket needs to be + * connected or accepted before data can be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_stream_socket(ExecutionContext& context, const protocol_type& protocol, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_socket<Protocol, Executor>(context, protocol) { } @@ -102,7 +170,7 @@ public: * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * - * @param io_context The io_context object that the stream socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the stream @@ -110,9 +178,33 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_stream_socket(asio::io_context& io_context, - const endpoint_type& endpoint) - : basic_socket<Protocol ASIO_SVC_TARG>(io_context, endpoint) + basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket<Protocol, Executor>(ex, endpoint) + { + } + + /// Construct a basic_stream_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a stream socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the stream + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, endpoint) { } @@ -121,7 +213,7 @@ public: * This constructor creates a stream socket object to hold an existing native * socket. * - * @param io_context The io_context object that the stream socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. @@ -130,14 +222,37 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_stream_socket(asio::io_context& io_context, + basic_stream_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol ASIO_SVC_TARG>( - io_context, protocol, native_socket) + : basic_socket<Protocol, Executor>(ex, protocol, native_socket) + { + } + + /// Construct a basic_stream_socket on an existing native socket. + /** + * This constructor creates a stream socket object to hold an existing native + * socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_stream_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_socket<Protocol, Executor>(context, protocol, native_socket) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_stream_socket from another. /** * This constructor moves a stream socket from one object to another. @@ -146,10 +261,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_context&) constructor. + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. */ - basic_stream_socket(basic_stream_socket&& other) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + basic_stream_socket(basic_stream_socket&& other) noexcept + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -161,11 +277,12 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_context&) constructor. + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. */ basic_stream_socket& operator=(basic_stream_socket&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } @@ -178,13 +295,16 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_context&) constructor. + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - basic_stream_socket( - basic_stream_socket<Protocol1 ASIO_SVC_TARG1>&& other, - typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) + template <typename Protocol1, typename Executor1> + basic_stream_socket(basic_stream_socket<Protocol1, Executor1>&& other, + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value + > = 0) + : basic_socket<Protocol, Executor>(std::move(other)) { } @@ -196,17 +316,19 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_context&) constructor. + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - typename enable_if<is_convertible<Protocol1, Protocol>::value, - basic_stream_socket>::type& operator=( - basic_stream_socket<Protocol1 ASIO_SVC_TARG1>&& other) + template <typename Protocol1, typename Executor1> + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value, + basic_stream_socket& + > operator=(basic_stream_socket<Protocol1, Executor1>&& other) { - basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); + basic_socket<Protocol, Executor>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destroys the socket. /** @@ -246,8 +368,8 @@ public: std::size_t send(const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "send"); return s; } @@ -284,8 +406,8 @@ public: socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, flags, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); asio::detail::throw_error(ec, "send"); return s; } @@ -312,31 +434,37 @@ public: std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().send( - this->get_implementation(), buffers, flags, ec); + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); } /// Start an asynchronous send. /** * This function is used to asynchronously send data on the stream socket. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they - * remain valid until the handler is called. + * remain valid until the completion handler is called. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -350,56 +478,63 @@ public: * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send( - this->get_implementation(), buffers, 0, - ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send( - this->get_implementation(), buffers, 0, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, + buffers, socket_base::message_flags(0))) + { + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, + buffers, socket_base::message_flags(0)); } /// Start an asynchronous send. /** * This function is used to asynchronously send data on the stream socket. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they - * remain valid until the handler is called. + * remain valid until the completion handler is called. * * @param flags Flags specifying how the send call is to be made. * - * @param handler The handler to be called when the send operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the send completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -413,32 +548,31 @@ public: * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(const ConstBufferSequence& buffers, + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send( - this->get_implementation(), buffers, flags, - ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send( - this->get_implementation(), buffers, flags, - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, buffers, flags)) + { + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, buffers, flags); } /// Receive some data on the socket. @@ -473,8 +607,8 @@ public: std::size_t receive(const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -514,8 +648,8 @@ public: socket_base::message_flags flags) { asio::error_code ec; - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, flags, ec); + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); asio::detail::throw_error(ec, "receive"); return s; } @@ -542,31 +676,37 @@ public: std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - return this->get_service().receive( - this->get_implementation(), buffers, flags, ec); + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive data from the stream - * socket. The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref async_read function if you need to ensure @@ -582,54 +722,63 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive(this->get_implementation(), - buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive(this->get_implementation(), - buffers, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive>(), token, + buffers, socket_base::message_flags(0))) + { + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive(this), token, + buffers, socket_base::message_flags(0)); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive data from the stream - * socket. The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param flags Flags specifying how the receive call is to be made. * - * @param handler The handler to be called when the receive operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the receive completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref async_read function if you need to ensure @@ -645,30 +794,31 @@ public: * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(const MutableBufferSequence& buffers, + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive>(), token, buffers, flags)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive(this->get_implementation(), - buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive(this->get_implementation(), - buffers, flags, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive(this), token, buffers, flags); } /// Write some data to the socket. @@ -702,8 +852,8 @@ public: std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().send( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "write_some"); return s; } @@ -728,30 +878,37 @@ public: std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().send(this->get_implementation(), buffers, 0, ec); + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the stream socket. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be written to the socket. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -765,29 +922,32 @@ public: * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_send(this->get_implementation(), - buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_send(this->get_implementation(), - buffers, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_send>(), token, + buffers, socket_base::message_flags(0))) + { + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_send(this), token, + buffers, socket_base::message_flags(0)); } /// Read some data from the socket. @@ -822,8 +982,8 @@ public: std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().receive( - this->get_implementation(), buffers, 0, ec); + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); asio::detail::throw_error(ec, "read_some"); return s; } @@ -849,31 +1009,37 @@ public: std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().receive( - this->get_implementation(), buffers, 0, ec); + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the stream socket. - * The function call always returns immediately. + * socket. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -888,30 +1054,106 @@ public: * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_receive(this->get_implementation(), - buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_receive(this->get_implementation(), - buffers, 0, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_receive>(), token, + buffers, socket_base::message_flags(0))) + { + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_receive(this), token, + buffers, socket_base::message_flags(0)); } + +private: + // Disallow copying and assignment. + basic_stream_socket(const basic_stream_socket&) = delete; + basic_stream_socket& operator=(const basic_stream_socket&) = delete; + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_stream_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_socket* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_stream_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_socket* self_; + }; }; } // namespace asio diff --git a/3rdparty/asio/include/asio/basic_streambuf.hpp b/3rdparty/asio/include/asio/basic_streambuf.hpp index 0f060321788..0450811dca1 100644 --- a/3rdparty/asio/include/asio/basic_streambuf.hpp +++ b/3rdparty/asio/include/asio/basic_streambuf.hpp @@ -2,7 +2,7 @@ // basic_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -103,7 +103,7 @@ namespace asio { * @endcode */ #if defined(GENERATING_DOCUMENTATION) -template <typename Allocator = std::allocator<char> > +template <typename Allocator = std::allocator<char>> #else template <typename Allocator> #endif @@ -155,7 +155,7 @@ public: * } * @endcode */ - std::size_t size() const ASIO_NOEXCEPT + std::size_t size() const noexcept { return pptr() - gptr(); } @@ -165,7 +165,7 @@ public: * @returns The allowed maximum of the sum of the sizes of the input sequence * and output sequence. */ - std::size_t max_size() const ASIO_NOEXCEPT + std::size_t max_size() const noexcept { return max_size_; } @@ -175,7 +175,7 @@ public: * @returns The current total capacity of the streambuf, i.e. for both the * input sequence and output sequence. */ - std::size_t capacity() const ASIO_NOEXCEPT + std::size_t capacity() const noexcept { return buffer_.capacity(); } @@ -189,7 +189,7 @@ public: * @note The returned object is invalidated by any @c basic_streambuf member * function that modifies the input sequence or output sequence. */ - const_buffers_type data() const ASIO_NOEXCEPT + const_buffers_type data() const noexcept { return asio::buffer(asio::const_buffer(gptr(), (pptr() - gptr()) * sizeof(char_type))); @@ -232,8 +232,7 @@ public: */ void commit(std::size_t n) { - if (pptr() + n > epptr()) - n = epptr() - pptr(); + n = std::min<std::size_t>(n, epptr() - pptr()); pbump(static_cast<int>(n)); setg(eback(), gptr(), pptr()); } @@ -362,7 +361,7 @@ private: /// Adapts basic_streambuf to the dynamic buffer sequence type requirements. #if defined(GENERATING_DOCUMENTATION) -template <typename Allocator = std::allocator<char> > +template <typename Allocator = std::allocator<char>> #else template <typename Allocator> #endif @@ -384,39 +383,37 @@ public: } /// Copy construct a basic_streambuf_ref. - basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT + basic_streambuf_ref(const basic_streambuf_ref& other) noexcept : sb_(other.sb_) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move construct a basic_streambuf_ref. - basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT + basic_streambuf_ref(basic_streambuf_ref&& other) noexcept : sb_(other.sb_) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Get the size of the input sequence. - std::size_t size() const ASIO_NOEXCEPT + std::size_t size() const noexcept { return sb_.size(); } /// Get the maximum size of the dynamic buffer. - std::size_t max_size() const ASIO_NOEXCEPT + std::size_t max_size() const noexcept { return sb_.max_size(); } /// Get the current capacity of the dynamic buffer. - std::size_t capacity() const ASIO_NOEXCEPT + std::size_t capacity() const noexcept { return sb_.capacity(); } /// Get a list of buffers that represents the input sequence. - const_buffers_type data() const ASIO_NOEXCEPT + const_buffers_type data() const noexcept { return sb_.data(); } diff --git a/3rdparty/asio/include/asio/basic_streambuf_fwd.hpp b/3rdparty/asio/include/asio/basic_streambuf_fwd.hpp index 361997b779f..1ff320d4637 100644 --- a/3rdparty/asio/include/asio/basic_streambuf_fwd.hpp +++ b/3rdparty/asio/include/asio/basic_streambuf_fwd.hpp @@ -2,7 +2,7 @@ // basic_streambuf_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,10 +23,10 @@ namespace asio { -template <typename Allocator = std::allocator<char> > +template <typename Allocator = std::allocator<char>> class basic_streambuf; -template <typename Allocator = std::allocator<char> > +template <typename Allocator = std::allocator<char>> class basic_streambuf_ref; } // namespace asio diff --git a/3rdparty/asio/include/asio/basic_waitable_timer.hpp b/3rdparty/asio/include/asio/basic_waitable_timer.hpp index 6e9a3e18585..5e9df3ef4f8 100644 --- a/3rdparty/asio/include/asio/basic_waitable_timer.hpp +++ b/3rdparty/asio/include/asio/basic_waitable_timer.hpp @@ -2,7 +2,7 @@ // basic_waitable_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,26 +17,17 @@ #include "asio/detail/config.hpp" #include <cstddef> -#include "asio/basic_io_object.hpp" +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/detail/chrono_time_traits.hpp" +#include "asio/detail/deadline_timer_service.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/wait_traits.hpp" -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/waitable_timer_service.hpp" -#else // defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/detail/chrono_time_traits.hpp" -# include "asio/detail/deadline_timer_service.hpp" -# define ASIO_SVC_T \ - detail::deadline_timer_service< \ - detail::chrono_time_traits<Clock, WaitTraits> > -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #include "asio/detail/push_options.hpp" namespace asio { @@ -46,8 +37,8 @@ namespace asio { // Forward declaration with defaulted arguments. template <typename Clock, - typename WaitTraits = asio::wait_traits<Clock> - ASIO_SVC_TPARAM_DEF2(= waitable_timer_service<Clock, WaitTraits>)> + typename WaitTraits = asio::wait_traits<Clock>, + typename Executor = any_io_executor> class basic_waitable_timer; #endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) @@ -75,7 +66,7 @@ class basic_waitable_timer; * Performing a blocking wait (C++11): * @code * // Construct a timer without setting an expiry time. - * asio::steady_timer timer(io_context); + * asio::steady_timer timer(my_context); * * // Set an expiry time relative to now. * timer.expires_after(std::chrono::seconds(5)); @@ -98,7 +89,7 @@ class basic_waitable_timer; * ... * * // Construct a timer with an absolute expiry time. - * asio::steady_timer timer(io_context, + * asio::steady_timer timer(my_context, * std::chrono::steady_clock::now() + std::chrono::seconds(60)); * * // Start an asynchronous wait. @@ -144,13 +135,23 @@ class basic_waitable_timer; * @li If a wait handler is cancelled, the asio::error_code passed to * it contains the value asio::error::operation_aborted. */ -template <typename Clock, typename WaitTraits ASIO_SVC_TPARAM> +template <typename Clock, typename WaitTraits, typename Executor> class basic_waitable_timer - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T> { +private: + class initiate_async_wait; + public: /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; + typedef Executor executor_type; + + /// Rebinds the timer type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The timer type when rebound to the specified executor. + typedef basic_waitable_timer<Clock, WaitTraits, Executor1> other; + }; /// The clock type. typedef Clock clock_type; @@ -170,11 +171,30 @@ public: * expires_at() or expires_after() functions must be called to set an expiry * time before the timer can be waited on. * - * @param io_context The io_context object that the timer will use to dispatch - * handlers for any asynchronous operations performed on the timer. + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_waitable_timer(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_after() functions must be called to set an expiry + * time before the timer can be waited on. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. */ - explicit basic_waitable_timer(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) + template <typename ExecutionContext> + explicit basic_waitable_timer(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { } @@ -182,18 +202,41 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_context The io_context object that the timer will use to dispatch - * handlers for any asynchronous operations performed on the timer. + * @param ex The I/O executor object that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, expressed * as an absolute time. */ - basic_waitable_timer(asio::io_context& io_context, - const time_point& expiry_time) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_waitable_timer(const executor_type& ex, const time_point& expiry_time) + : impl_(0, ex) { asio::error_code ec; - this->get_service().expires_at(this->get_implementation(), expiry_time, ec); + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + template <typename ExecutionContext> + explicit basic_waitable_timer(ExecutionContext& context, + const time_point& expiry_time, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_at"); } @@ -201,23 +244,46 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_context The io_context object that the timer will use to dispatch - * handlers for any asynchronous operations performed on the timer. + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, relative to * now. */ - basic_waitable_timer(asio::io_context& io_context, - const duration& expiry_time) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_waitable_timer(const executor_type& ex, const duration& expiry_time) + : impl_(0, ex) { asio::error_code ec; - this->get_service().expires_after( - this->get_implementation(), expiry_time, ec); + impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_after"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + template <typename ExecutionContext> + explicit basic_waitable_timer(ExecutionContext& context, + const duration& expiry_time, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_after"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_waitable_timer from another. /** * This constructor moves a timer from one object to another. @@ -226,10 +292,11 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_waitable_timer(io_context&) constructor. + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. */ basic_waitable_timer(basic_waitable_timer&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) + : impl_(std::move(other.impl_)) { } @@ -242,63 +309,77 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_waitable_timer(io_context&) constructor. + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. */ basic_waitable_timer& operator=(basic_waitable_timer&& other) { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); + impl_ = std::move(other.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Destroys the timer. + // All timers have access to each other's implementations. + template <typename Clock1, typename WaitTraits1, typename Executor1> + friend class basic_waitable_timer; + + /// Move-construct a basic_waitable_timer from another. /** - * This function destroys the timer, cancelling any outstanding asynchronous - * wait operations associated with the timer as if by calling @c cancel. + * This constructor moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. */ - ~basic_waitable_timer() + template <typename Executor1> + basic_waitable_timer( + basic_waitable_timer<Clock, WaitTraits, Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value + > = 0) + : impl_(std::move(other.impl_)) { } -#if defined(ASIO_ENABLE_OLD_SERVICES) - // These functions are provided by basic_io_object<>. -#else // defined(ASIO_ENABLE_OLD_SERVICES) -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. + /// Move-assign a basic_waitable_timer from another. /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. */ - asio::io_context& get_io_context() + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_waitable_timer& + > operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other) { - return basic_io_object<ASIO_SVC_T>::get_io_context(); + basic_waitable_timer tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; } - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. + /// Destroys the timer. /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. + * This function destroys the timer, cancelling any outstanding asynchronous + * wait operations associated with the timer as if by calling @c cancel. */ - asio::io_context& get_io_service() + ~basic_waitable_timer() { - return basic_io_object<ASIO_SVC_T>::get_io_service(); } -#endif // !defined(ASIO_NO_DEPRECATED) /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + const executor_type& get_executor() noexcept { - return basic_io_object<ASIO_SVC_T>::get_executor(); + return impl_.get_executor(); } -#endif // defined(ASIO_ENABLE_OLD_SERVICES) /// Cancel any asynchronous operations that are waiting on the timer. /** @@ -325,7 +406,7 @@ public: std::size_t cancel() { asio::error_code ec; - std::size_t s = this->get_service().cancel(this->get_implementation(), ec); + std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); return s; } @@ -356,7 +437,7 @@ public: */ std::size_t cancel(asio::error_code& ec) { - return this->get_service().cancel(this->get_implementation(), ec); + return impl_.get_service().cancel(impl_.get_implementation(), ec); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -387,8 +468,8 @@ public: std::size_t cancel_one() { asio::error_code ec; - std::size_t s = this->get_service().cancel_one( - this->get_implementation(), ec); + std::size_t s = impl_.get_service().cancel_one( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel_one"); return s; } @@ -421,7 +502,7 @@ public: */ std::size_t cancel_one(asio::error_code& ec) { - return this->get_service().cancel_one(this->get_implementation(), ec); + return impl_.get_service().cancel_one(impl_.get_implementation(), ec); } /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute @@ -432,7 +513,7 @@ public: */ time_point expires_at() const { - return this->get_service().expires_at(this->get_implementation()); + return impl_.get_service().expires_at(impl_.get_implementation()); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -443,7 +524,7 @@ public: */ time_point expiry() const { - return this->get_service().expiry(this->get_implementation()); + return impl_.get_service().expiry(impl_.get_implementation()); } /// Set the timer's expiry time as an absolute time. @@ -471,8 +552,8 @@ public: std::size_t expires_at(const time_point& expiry_time) { asio::error_code ec; - std::size_t s = this->get_service().expires_at( - this->get_implementation(), expiry_time, ec); + std::size_t s = impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_at"); return s; } @@ -504,8 +585,8 @@ public: std::size_t expires_at(const time_point& expiry_time, asio::error_code& ec) { - return this->get_service().expires_at( - this->get_implementation(), expiry_time, ec); + return impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -534,8 +615,8 @@ public: std::size_t expires_after(const duration& expiry_time) { asio::error_code ec; - std::size_t s = this->get_service().expires_after( - this->get_implementation(), expiry_time, ec); + std::size_t s = impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_after"); return s; } @@ -548,7 +629,7 @@ public: */ duration expires_from_now() const { - return this->get_service().expires_from_now(this->get_implementation()); + return impl_.get_service().expires_from_now(impl_.get_implementation()); } /// (Deprecated: Use expires_after().) Set the timer's expiry time relative @@ -577,8 +658,8 @@ public: std::size_t expires_from_now(const duration& expiry_time) { asio::error_code ec; - std::size_t s = this->get_service().expires_from_now( - this->get_implementation(), expiry_time, ec); + std::size_t s = impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_from_now"); return s; } @@ -609,8 +690,8 @@ public: std::size_t expires_from_now(const duration& expiry_time, asio::error_code& ec) { - return this->get_service().expires_from_now( - this->get_implementation(), expiry_time, ec); + return impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -624,7 +705,7 @@ public: void wait() { asio::error_code ec; - this->get_service().wait(this->get_implementation(), ec); + impl_.get_service().wait(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "wait"); } @@ -637,69 +718,107 @@ public: */ void wait(asio::error_code& ec) { - this->get_service().wait(this->get_implementation(), ec); + impl_.get_service().wait(impl_.get_implementation(), ec); } /// Start an asynchronous wait on the timer. /** * This function may be used to initiate an asynchronous wait against the - * timer. It always returns immediately. + * timer. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * - * For each call to async_wait(), the supplied handler will be called exactly - * once. The handler will be called when: + * For each call to async_wait(), the completion handler will be called + * exactly once. The completion handler will be called when: * * @li The timer has expired. * * @li The timer was cancelled, in which case the handler is passed the error * code asio::error::operation_aborted. * - * @param handler The handler to be called when the timer expires. Copies - * will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the timer expires. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(ASIO_MOVE_ARG(WaitHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitToken = default_completion_token_t<executor_type>> + auto async_wait( + WaitToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WaitToken, void (asio::error_code)>( + declval<initiate_async_wait>(), token)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WaitHandler. - ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_wait(this->get_implementation(), - ASIO_MOVE_CAST(WaitHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_wait(this->get_implementation(), - init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WaitToken, void (asio::error_code)>( + initiate_async_wait(this), token); } private: // Disallow copying and assignment. - basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED; - basic_waitable_timer& operator=( - const basic_waitable_timer&) ASIO_DELETED; + basic_waitable_timer(const basic_waitable_timer&) = delete; + basic_waitable_timer& operator=(const basic_waitable_timer&) = delete; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_waitable_timer* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue<WaitHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_waitable_timer* self_; + }; + + detail::io_object_impl< + detail::deadline_timer_service< + detail::chrono_time_traits<Clock, WaitTraits>>, + executor_type > impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_BASIC_WAITABLE_TIMER_HPP diff --git a/3rdparty/asio/include/asio/basic_writable_pipe.hpp b/3rdparty/asio/include/asio/basic_writable_pipe.hpp new file mode 100644 index 00000000000..4c389c9b464 --- /dev/null +++ b/3rdparty/asio/include/asio/basic_writable_pipe.hpp @@ -0,0 +1,622 @@ +// +// basic_writable_pipe.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BASIC_WRITABLE_PIPE_HPP +#define ASIO_BASIC_WRITABLE_PIPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PIPE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <string> +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_handle_service.hpp" +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_descriptor_service.hpp" +#else +# include "asio/detail/reactive_descriptor_service.hpp" +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides pipe functionality. +/** + * The basic_writable_pipe class provides a wrapper over pipe + * functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <typename Executor = any_io_executor> +class basic_writable_pipe +{ +private: + class initiate_async_write_some; + +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the pipe type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The pipe type when rebound to the specified executor. + typedef basic_writable_pipe<Executor1> other; + }; + + /// The native representation of a pipe. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef detail::win_iocp_handle_service::native_handle_type + native_handle_type; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef detail::io_uring_descriptor_service::native_handle_type + native_handle_type; +#else + typedef detail::reactive_descriptor_service::native_handle_type + native_handle_type; +#endif + + /// A basic_writable_pipe is always the lowest layer. + typedef basic_writable_pipe lowest_layer_type; + + /// Construct a basic_writable_pipe without opening it. + /** + * This constructor creates a pipe without opening it. + * + * @param ex The I/O executor that the pipe will use, by default, to dispatch + * handlers for any asynchronous operations performed on the pipe. + */ + explicit basic_writable_pipe(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a basic_writable_pipe without opening it. + /** + * This constructor creates a pipe without opening it. + * + * @param context An execution context which provides the I/O executor that + * the pipe will use, by default, to dispatch handlers for any asynchronous + * operations performed on the pipe. + */ + template <typename ExecutionContext> + explicit basic_writable_pipe(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct a basic_writable_pipe on an existing native pipe. + /** + * This constructor creates a pipe object to hold an existing native + * pipe. + * + * @param ex The I/O executor that the pipe will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * pipe. + * + * @param native_pipe A native pipe. + * + * @throws asio::system_error Thrown on failure. + */ + basic_writable_pipe(const executor_type& ex, + const native_handle_type& native_pipe) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_pipe, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_writable_pipe on an existing native pipe. + /** + * This constructor creates a pipe object to hold an existing native + * pipe. + * + * @param context An execution context which provides the I/O executor that + * the pipe will use, by default, to dispatch handlers for any + * asynchronous operations performed on the pipe. + * + * @param native_pipe A native pipe. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_writable_pipe(ExecutionContext& context, + const native_handle_type& native_pipe, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_pipe, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Move-construct a basic_writable_pipe from another. + /** + * This constructor moves a pipe from one object to another. + * + * @param other The other basic_writable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_writable_pipe(const executor_type&) + * constructor. + */ + basic_writable_pipe(basic_writable_pipe&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_writable_pipe from another. + /** + * This assignment operator moves a pipe from one object to another. + * + * @param other The other basic_writable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_writable_pipe(const executor_type&) + * constructor. + */ + basic_writable_pipe& operator=(basic_writable_pipe&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All pipes have access to each other's implementations. + template <typename Executor1> + friend class basic_writable_pipe; + + /// Move-construct a basic_writable_pipe from a pipe of another executor type. + /** + * This constructor moves a pipe from one object to another. + * + * @param other The other basic_writable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_writable_pipe(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_writable_pipe(basic_writable_pipe<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_writable_pipe from a pipe of another executor type. + /** + * This assignment operator moves a pipe from one object to another. + * + * @param other The other basic_writable_pipe object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_writable_pipe(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_writable_pipe& + > operator=(basic_writable_pipe<Executor1>&& other) + { + basic_writable_pipe tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } + + /// Destroys the pipe. + /** + * This function destroys the pipe, cancelling any outstanding + * asynchronous wait operations associated with the pipe as if by + * calling @c cancel. + */ + ~basic_writable_pipe() + { + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_writable_pipe cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_writable_pipe cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native pipe to the pipe. + /* + * This function opens the pipe to hold an existing native pipe. + * + * @param native_pipe A native pipe. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_pipe) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native pipe to the pipe. + /* + * This function opens the pipe to hold an existing native pipe. + * + * @param native_pipe A native pipe. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe, + asio::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the pipe is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the pipe. + /** + * This function is used to close the pipe. Any asynchronous write operations + * will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the pipe. + /** + * This function is used to close the pipe. Any asynchronous write operations + * will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native pipe. + /** + * This function causes all outstanding asynchronous write operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native pipe is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native pipe. + /** + * This function causes all outstanding asynchronous write operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. Ownership of the + * native pipe is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native pipe representation. + /** + * This function may be used to obtain the underlying representation of the + * pipe. This is intended to allow access to native pipe + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the pipe. + /** + * This function causes all outstanding asynchronous write operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the pipe. + /** + * This function causes all outstanding asynchronous write operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Write some data to the pipe. + /** + * This function is used to write data to the pipe. The function call will + * block until one or more bytes of the data has been written successfully, + * or until an error occurs. + * + * @param buffers One or more data buffers to be written to the pipe. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * pipe.write_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the pipe. + /** + * This function is used to write data to the pipe. The function call will + * block until one or more bytes of the data has been written successfully, + * or until an error occurs. + * + * @param buffers One or more data buffers to be written to the pipe. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the pipe. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. + * + * @param buffers One or more data buffers to be written to the pipe. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * pipe.async_write_some(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_write_some>(), token, buffers)) + { + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some(this), token, buffers); + } + +private: + // Disallow copying and assignment. + basic_writable_pipe(const basic_writable_pipe&) = delete; + basic_writable_pipe& operator=(const basic_writable_pipe&) = delete; + + class initiate_async_write_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_writable_pipe* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_writable_pipe* self_; + }; + +#if defined(ASIO_HAS_IOCP) + detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_; +#else + detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_; +#endif +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PIPE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_WRITABLE_PIPE_HPP diff --git a/3rdparty/asio/include/asio/bind_allocator.hpp b/3rdparty/asio/include/asio/bind_allocator.hpp new file mode 100644 index 00000000000..27910a2ec69 --- /dev/null +++ b/3rdparty/asio/include/asio/bind_allocator.hpp @@ -0,0 +1,530 @@ +// +// bind_allocator.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BIND_ALLOCATOR_HPP +#define ASIO_BIND_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper to automatically define nested typedef result_type. + +template <typename T, typename = void> +struct allocator_binder_result_type +{ +protected: + typedef void result_type_or_void; +}; + +template <typename T> +struct allocator_binder_result_type<T, void_t<typename T::result_type>> +{ + typedef typename T::result_type result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct allocator_binder_result_type<R(*)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct allocator_binder_result_type<R(&)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct allocator_binder_result_type<R(*)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct allocator_binder_result_type<R(&)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct allocator_binder_result_type<R(*)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct allocator_binder_result_type<R(&)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +// Helper to automatically define nested typedef argument_type. + +template <typename T, typename = void> +struct allocator_binder_argument_type {}; + +template <typename T> +struct allocator_binder_argument_type<T, void_t<typename T::argument_type>> +{ + typedef typename T::argument_type argument_type; +}; + +template <typename R, typename A1> +struct allocator_binder_argument_type<R(*)(A1)> +{ + typedef A1 argument_type; +}; + +template <typename R, typename A1> +struct allocator_binder_argument_type<R(&)(A1)> +{ + typedef A1 argument_type; +}; + +// Helper to automatically define nested typedefs first_argument_type and +// second_argument_type. + +template <typename T, typename = void> +struct allocator_binder_argument_types {}; + +template <typename T> +struct allocator_binder_argument_types<T, + void_t<typename T::first_argument_type>> +{ + typedef typename T::first_argument_type first_argument_type; + typedef typename T::second_argument_type second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct allocator_binder_argument_type<R(*)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct allocator_binder_argument_type<R(&)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +} // namespace detail + +/// A call wrapper type to bind an allocator of type @c Allocator +/// to an object of type @c T. +template <typename T, typename Allocator> +class allocator_binder +#if !defined(GENERATING_DOCUMENTATION) + : public detail::allocator_binder_result_type<T>, + public detail::allocator_binder_argument_type<T>, + public detail::allocator_binder_argument_types<T> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +public: + /// The type of the target object. + typedef T target_type; + + /// The type of the associated allocator. + typedef Allocator allocator_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The return type if a function. + /** + * The type of @c result_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to function type, @c result_type is a synonym for + * the return type of @c T; + * + * @li if @c T is a class type with a member type @c result_type, then @c + * result_type is a synonym for @c T::result_type; + * + * @li otherwise @c result_type is not defined. + */ + typedef see_below result_type; + + /// The type of the function's argument. + /** + * The type of @c argument_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to a function type accepting a single argument, + * @c argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c argument_type, then @c + * argument_type is a synonym for @c T::argument_type; + * + * @li otherwise @c argument_type is not defined. + */ + typedef see_below argument_type; + + /// The type of the function's first argument. + /** + * The type of @c first_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * first_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c first_argument_type is a synonym for @c T::first_argument_type; + * + * @li otherwise @c first_argument_type is not defined. + */ + typedef see_below first_argument_type; + + /// The type of the function's second argument. + /** + * The type of @c second_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * second_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c second_argument_type is a synonym for @c T::second_argument_type; + * + * @li otherwise @c second_argument_type is not defined. + */ + typedef see_below second_argument_type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct an allocator wrapper for the specified object. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U> + allocator_binder(const allocator_type& s, U&& u) + : allocator_(s), + target_(static_cast<U&&>(u)) + { + } + + /// Copy constructor. + allocator_binder(const allocator_binder& other) + : allocator_(other.get_allocator()), + target_(other.get()) + { + } + + /// Construct a copy, but specify a different allocator. + allocator_binder(const allocator_type& s, const allocator_binder& other) + : allocator_(s), + target_(other.get()) + { + } + + /// Construct a copy of a different allocator wrapper type. + /** + * This constructor is only valid if the @c Allocator type is + * constructible from type @c OtherAllocator, and the type @c T is + * constructible from type @c U. + */ + template <typename U, typename OtherAllocator> + allocator_binder(const allocator_binder<U, OtherAllocator>& other, + constraint_t<is_constructible<Allocator, OtherAllocator>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) + : allocator_(other.get_allocator()), + target_(other.get()) + { + } + + /// Construct a copy of a different allocator wrapper type, but + /// specify a different allocator. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U, typename OtherAllocator> + allocator_binder(const allocator_type& s, + const allocator_binder<U, OtherAllocator>& other, + constraint_t<is_constructible<T, U>::value> = 0) + : allocator_(s), + target_(other.get()) + { + } + + /// Move constructor. + allocator_binder(allocator_binder&& other) + : allocator_(static_cast<allocator_type&&>( + other.get_allocator())), + target_(static_cast<T&&>(other.get())) + { + } + + /// Move construct the target object, but specify a different allocator. + allocator_binder(const allocator_type& s, + allocator_binder&& other) + : allocator_(s), + target_(static_cast<T&&>(other.get())) + { + } + + /// Move construct from a different allocator wrapper type. + template <typename U, typename OtherAllocator> + allocator_binder( + allocator_binder<U, OtherAllocator>&& other, + constraint_t<is_constructible<Allocator, OtherAllocator>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) + : allocator_(static_cast<OtherAllocator&&>( + other.get_allocator())), + target_(static_cast<U&&>(other.get())) + { + } + + /// Move construct from a different allocator wrapper type, but + /// specify a different allocator. + template <typename U, typename OtherAllocator> + allocator_binder(const allocator_type& s, + allocator_binder<U, OtherAllocator>&& other, + constraint_t<is_constructible<T, U>::value> = 0) + : allocator_(s), + target_(static_cast<U&&>(other.get())) + { + } + + /// Destructor. + ~allocator_binder() + { + } + + /// Obtain a reference to the target object. + target_type& get() noexcept + { + return target_; + } + + /// Obtain a reference to the target object. + const target_type& get() const noexcept + { + return target_; + } + + /// Obtain the associated allocator. + allocator_type get_allocator() const noexcept + { + return allocator_; + } + + /// Forwarding function call operator. + template <typename... Args> + result_of_t<T(Args...)> operator()(Args&&... args) + { + return target_(static_cast<Args&&>(args)...); + } + + /// Forwarding function call operator. + template <typename... Args> + result_of_t<T(Args...)> operator()(Args&&... args) const + { + return target_(static_cast<Args&&>(args)...); + } + +private: + Allocator allocator_; + T target_; +}; + +/// Associate an object of type @c T with an allocator of type +/// @c Allocator. +template <typename Allocator, typename T> +ASIO_NODISCARD inline allocator_binder<decay_t<T>, Allocator> +bind_allocator(const Allocator& s, T&& t) +{ + return allocator_binder<decay_t<T>, Allocator>(s, static_cast<T&&>(t)); +} + +#if !defined(GENERATING_DOCUMENTATION) + +namespace detail { + +template <typename TargetAsyncResult, typename Allocator, typename = void> +class allocator_binder_completion_handler_async_result +{ +public: + template <typename T> + explicit allocator_binder_completion_handler_async_result(T&) + { + } +}; + +template <typename TargetAsyncResult, typename Allocator> +class allocator_binder_completion_handler_async_result< + TargetAsyncResult, Allocator, + void_t<typename TargetAsyncResult::completion_handler_type>> +{ +private: + TargetAsyncResult target_; + +public: + typedef allocator_binder< + typename TargetAsyncResult::completion_handler_type, Allocator> + completion_handler_type; + + explicit allocator_binder_completion_handler_async_result( + typename TargetAsyncResult::completion_handler_type& handler) + : target_(handler) + { + } + + auto get() -> decltype(target_.get()) + { + return target_.get(); + } +}; + +template <typename TargetAsyncResult, typename = void> +struct allocator_binder_async_result_return_type +{ +}; + +template <typename TargetAsyncResult> +struct allocator_binder_async_result_return_type< + TargetAsyncResult, void_type<typename TargetAsyncResult::return_type>> +{ + typedef typename TargetAsyncResult::return_type return_type; +}; + +} // namespace detail + +template <typename T, typename Allocator, typename Signature> +class async_result<allocator_binder<T, Allocator>, Signature> : + public detail::allocator_binder_completion_handler_async_result< + async_result<T, Signature>, Allocator>, + public detail::allocator_binder_async_result_return_type< + async_result<T, Signature>> +{ +public: + explicit async_result(allocator_binder<T, Allocator>& b) + : detail::allocator_binder_completion_handler_async_result< + async_result<T, Signature>, Allocator>(b.get()) + { + } + + template <typename Initiation> + struct init_wrapper + { + template <typename Init> + init_wrapper(const Allocator& allocator, Init&& init) + : allocator_(allocator), + initiation_(static_cast<Init&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + allocator_binder<decay_t<Handler>, Allocator>( + allocator_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) const + { + initiation_( + allocator_binder<decay_t<Handler>, Allocator>( + allocator_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + Allocator allocator_; + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<T, Signature>( + declval<init_wrapper<decay_t<Initiation>>>(), + token.get(), static_cast<Args&&>(args)...)) + { + return async_initiate<T, Signature>( + init_wrapper<decay_t<Initiation>>(token.get_allocator(), + static_cast<Initiation&&>(initiation)), + token.get(), static_cast<Args&&>(args)...); + } + +private: + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + async_result<T, Signature> target_; +}; + +template <template <typename, typename> class Associator, + typename T, typename Allocator, typename DefaultCandidate> +struct associator<Associator, allocator_binder<T, Allocator>, DefaultCandidate> + : Associator<T, DefaultCandidate> +{ + static typename Associator<T, DefaultCandidate>::type get( + const allocator_binder<T, Allocator>& b) noexcept + { + return Associator<T, DefaultCandidate>::get(b.get()); + } + + static auto get(const allocator_binder<T, Allocator>& b, + const DefaultCandidate& c) noexcept + -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c)) + { + return Associator<T, DefaultCandidate>::get(b.get(), c); + } +}; + +template <typename T, typename Allocator, typename Allocator1> +struct associated_allocator<allocator_binder<T, Allocator>, Allocator1> +{ + typedef Allocator type; + + static auto get(const allocator_binder<T, Allocator>& b, + const Allocator1& = Allocator1()) noexcept + -> decltype(b.get_allocator()) + { + return b.get_allocator(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BIND_ALLOCATOR_HPP diff --git a/3rdparty/asio/include/asio/bind_cancellation_slot.hpp b/3rdparty/asio/include/asio/bind_cancellation_slot.hpp new file mode 100644 index 00000000000..7be13426283 --- /dev/null +++ b/3rdparty/asio/include/asio/bind_cancellation_slot.hpp @@ -0,0 +1,544 @@ +// +// bind_cancellation_slot.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BIND_CANCELLATION_SLOT_HPP +#define ASIO_BIND_CANCELLATION_SLOT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper to automatically define nested typedef result_type. + +template <typename T, typename = void> +struct cancellation_slot_binder_result_type +{ +protected: + typedef void result_type_or_void; +}; + +template <typename T> +struct cancellation_slot_binder_result_type<T, void_t<typename T::result_type>> +{ + typedef typename T::result_type result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct cancellation_slot_binder_result_type<R(*)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct cancellation_slot_binder_result_type<R(&)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct cancellation_slot_binder_result_type<R(*)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct cancellation_slot_binder_result_type<R(&)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct cancellation_slot_binder_result_type<R(*)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct cancellation_slot_binder_result_type<R(&)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +// Helper to automatically define nested typedef argument_type. + +template <typename T, typename = void> +struct cancellation_slot_binder_argument_type {}; + +template <typename T> +struct cancellation_slot_binder_argument_type<T, + void_t<typename T::argument_type>> +{ + typedef typename T::argument_type argument_type; +}; + +template <typename R, typename A1> +struct cancellation_slot_binder_argument_type<R(*)(A1)> +{ + typedef A1 argument_type; +}; + +template <typename R, typename A1> +struct cancellation_slot_binder_argument_type<R(&)(A1)> +{ + typedef A1 argument_type; +}; + +// Helper to automatically define nested typedefs first_argument_type and +// second_argument_type. + +template <typename T, typename = void> +struct cancellation_slot_binder_argument_types {}; + +template <typename T> +struct cancellation_slot_binder_argument_types<T, + void_t<typename T::first_argument_type>> +{ + typedef typename T::first_argument_type first_argument_type; + typedef typename T::second_argument_type second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct cancellation_slot_binder_argument_type<R(*)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct cancellation_slot_binder_argument_type<R(&)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +} // namespace detail + +/// A call wrapper type to bind a cancellation slot of type @c CancellationSlot +/// to an object of type @c T. +template <typename T, typename CancellationSlot> +class cancellation_slot_binder +#if !defined(GENERATING_DOCUMENTATION) + : public detail::cancellation_slot_binder_result_type<T>, + public detail::cancellation_slot_binder_argument_type<T>, + public detail::cancellation_slot_binder_argument_types<T> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +public: + /// The type of the target object. + typedef T target_type; + + /// The type of the associated cancellation slot. + typedef CancellationSlot cancellation_slot_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The return type if a function. + /** + * The type of @c result_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to function type, @c result_type is a synonym for + * the return type of @c T; + * + * @li if @c T is a class type with a member type @c result_type, then @c + * result_type is a synonym for @c T::result_type; + * + * @li otherwise @c result_type is not defined. + */ + typedef see_below result_type; + + /// The type of the function's argument. + /** + * The type of @c argument_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to a function type accepting a single argument, + * @c argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c argument_type, then @c + * argument_type is a synonym for @c T::argument_type; + * + * @li otherwise @c argument_type is not defined. + */ + typedef see_below argument_type; + + /// The type of the function's first argument. + /** + * The type of @c first_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * first_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c first_argument_type is a synonym for @c T::first_argument_type; + * + * @li otherwise @c first_argument_type is not defined. + */ + typedef see_below first_argument_type; + + /// The type of the function's second argument. + /** + * The type of @c second_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * second_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c second_argument_type is a synonym for @c T::second_argument_type; + * + * @li otherwise @c second_argument_type is not defined. + */ + typedef see_below second_argument_type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct a cancellation slot wrapper for the specified object. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U> + cancellation_slot_binder(const cancellation_slot_type& s, U&& u) + : slot_(s), + target_(static_cast<U&&>(u)) + { + } + + /// Copy constructor. + cancellation_slot_binder(const cancellation_slot_binder& other) + : slot_(other.get_cancellation_slot()), + target_(other.get()) + { + } + + /// Construct a copy, but specify a different cancellation slot. + cancellation_slot_binder(const cancellation_slot_type& s, + const cancellation_slot_binder& other) + : slot_(s), + target_(other.get()) + { + } + + /// Construct a copy of a different cancellation slot wrapper type. + /** + * This constructor is only valid if the @c CancellationSlot type is + * constructible from type @c OtherCancellationSlot, and the type @c T is + * constructible from type @c U. + */ + template <typename U, typename OtherCancellationSlot> + cancellation_slot_binder( + const cancellation_slot_binder<U, OtherCancellationSlot>& other, + constraint_t<is_constructible<CancellationSlot, + OtherCancellationSlot>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) + : slot_(other.get_cancellation_slot()), + target_(other.get()) + { + } + + /// Construct a copy of a different cancellation slot wrapper type, but + /// specify a different cancellation slot. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U, typename OtherCancellationSlot> + cancellation_slot_binder(const cancellation_slot_type& s, + const cancellation_slot_binder<U, OtherCancellationSlot>& other, + constraint_t<is_constructible<T, U>::value> = 0) + : slot_(s), + target_(other.get()) + { + } + + /// Move constructor. + cancellation_slot_binder(cancellation_slot_binder&& other) + : slot_(static_cast<cancellation_slot_type&&>( + other.get_cancellation_slot())), + target_(static_cast<T&&>(other.get())) + { + } + + /// Move construct the target object, but specify a different cancellation + /// slot. + cancellation_slot_binder(const cancellation_slot_type& s, + cancellation_slot_binder&& other) + : slot_(s), + target_(static_cast<T&&>(other.get())) + { + } + + /// Move construct from a different cancellation slot wrapper type. + template <typename U, typename OtherCancellationSlot> + cancellation_slot_binder( + cancellation_slot_binder<U, OtherCancellationSlot>&& other, + constraint_t<is_constructible<CancellationSlot, + OtherCancellationSlot>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) + : slot_(static_cast<OtherCancellationSlot&&>( + other.get_cancellation_slot())), + target_(static_cast<U&&>(other.get())) + { + } + + /// Move construct from a different cancellation slot wrapper type, but + /// specify a different cancellation slot. + template <typename U, typename OtherCancellationSlot> + cancellation_slot_binder(const cancellation_slot_type& s, + cancellation_slot_binder<U, OtherCancellationSlot>&& other, + constraint_t<is_constructible<T, U>::value> = 0) + : slot_(s), + target_(static_cast<U&&>(other.get())) + { + } + + /// Destructor. + ~cancellation_slot_binder() + { + } + + /// Obtain a reference to the target object. + target_type& get() noexcept + { + return target_; + } + + /// Obtain a reference to the target object. + const target_type& get() const noexcept + { + return target_; + } + + /// Obtain the associated cancellation slot. + cancellation_slot_type get_cancellation_slot() const noexcept + { + return slot_; + } + + /// Forwarding function call operator. + template <typename... Args> + result_of_t<T(Args...)> operator()(Args&&... args) + { + return target_(static_cast<Args&&>(args)...); + } + + /// Forwarding function call operator. + template <typename... Args> + result_of_t<T(Args...)> operator()(Args&&... args) const + { + return target_(static_cast<Args&&>(args)...); + } + +private: + CancellationSlot slot_; + T target_; +}; + +/// Associate an object of type @c T with a cancellation slot of type +/// @c CancellationSlot. +template <typename CancellationSlot, typename T> +ASIO_NODISCARD inline +cancellation_slot_binder<decay_t<T>, CancellationSlot> +bind_cancellation_slot(const CancellationSlot& s, T&& t) +{ + return cancellation_slot_binder<decay_t<T>, CancellationSlot>( + s, static_cast<T&&>(t)); +} + +#if !defined(GENERATING_DOCUMENTATION) + +namespace detail { + +template <typename TargetAsyncResult, + typename CancellationSlot, typename = void> +class cancellation_slot_binder_completion_handler_async_result +{ +public: + template <typename T> + explicit cancellation_slot_binder_completion_handler_async_result(T&) + { + } +}; + +template <typename TargetAsyncResult, typename CancellationSlot> +class cancellation_slot_binder_completion_handler_async_result< + TargetAsyncResult, CancellationSlot, + void_t<typename TargetAsyncResult::completion_handler_type>> +{ +private: + TargetAsyncResult target_; + +public: + typedef cancellation_slot_binder< + typename TargetAsyncResult::completion_handler_type, CancellationSlot> + completion_handler_type; + + explicit cancellation_slot_binder_completion_handler_async_result( + typename TargetAsyncResult::completion_handler_type& handler) + : target_(handler) + { + } + + auto get() -> decltype(target_.get()) + { + return target_.get(); + } +}; + +template <typename TargetAsyncResult, typename = void> +struct cancellation_slot_binder_async_result_return_type +{ +}; + +template <typename TargetAsyncResult> +struct cancellation_slot_binder_async_result_return_type< + TargetAsyncResult, void_t<typename TargetAsyncResult::return_type>> +{ + typedef typename TargetAsyncResult::return_type return_type; +}; + +} // namespace detail + +template <typename T, typename CancellationSlot, typename Signature> +class async_result<cancellation_slot_binder<T, CancellationSlot>, Signature> : + public detail::cancellation_slot_binder_completion_handler_async_result< + async_result<T, Signature>, CancellationSlot>, + public detail::cancellation_slot_binder_async_result_return_type< + async_result<T, Signature>> +{ +public: + explicit async_result(cancellation_slot_binder<T, CancellationSlot>& b) + : detail::cancellation_slot_binder_completion_handler_async_result< + async_result<T, Signature>, CancellationSlot>(b.get()) + { + } + + template <typename Initiation> + struct init_wrapper + { + template <typename Init> + init_wrapper(const CancellationSlot& slot, Init&& init) + : slot_(slot), + initiation_(static_cast<Init&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + cancellation_slot_binder<decay_t<Handler>, CancellationSlot>( + slot_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) const + { + initiation_( + cancellation_slot_binder<decay_t<Handler>, CancellationSlot>( + slot_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + CancellationSlot slot_; + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<T, Signature>( + declval<init_wrapper<decay_t<Initiation>>>(), + token.get(), static_cast<Args&&>(args)...)) + { + return async_initiate<T, Signature>( + init_wrapper<decay_t<Initiation>>( + token.get_cancellation_slot(), + static_cast<Initiation&&>(initiation)), + token.get(), static_cast<Args&&>(args)...); + } + +private: + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + async_result<T, Signature> target_; +}; + +template <template <typename, typename> class Associator, + typename T, typename CancellationSlot, typename DefaultCandidate> +struct associator<Associator, + cancellation_slot_binder<T, CancellationSlot>, + DefaultCandidate> + : Associator<T, DefaultCandidate> +{ + static typename Associator<T, DefaultCandidate>::type get( + const cancellation_slot_binder<T, CancellationSlot>& b) noexcept + { + return Associator<T, DefaultCandidate>::get(b.get()); + } + + static auto get(const cancellation_slot_binder<T, CancellationSlot>& b, + const DefaultCandidate& c) noexcept + -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c)) + { + return Associator<T, DefaultCandidate>::get(b.get(), c); + } +}; + +template <typename T, typename CancellationSlot, typename CancellationSlot1> +struct associated_cancellation_slot< + cancellation_slot_binder<T, CancellationSlot>, + CancellationSlot1> +{ + typedef CancellationSlot type; + + static auto get(const cancellation_slot_binder<T, CancellationSlot>& b, + const CancellationSlot1& = CancellationSlot1()) noexcept + -> decltype(b.get_cancellation_slot()) + { + return b.get_cancellation_slot(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BIND_CANCELLATION_SLOT_HPP diff --git a/3rdparty/asio/include/asio/bind_executor.hpp b/3rdparty/asio/include/asio/bind_executor.hpp index 3ed890d9d73..f117b4ce903 100644 --- a/3rdparty/asio/include/asio/bind_executor.hpp +++ b/3rdparty/asio/include/asio/bind_executor.hpp @@ -2,7 +2,7 @@ // bind_executor.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,10 +17,10 @@ #include "asio/detail/config.hpp" #include "asio/detail/type_traits.hpp" -#include "asio/detail/variadic_templates.hpp" #include "asio/associated_executor.hpp" -#include "asio/associated_allocator.hpp" +#include "asio/associator.hpp" #include "asio/async_result.hpp" +#include "asio/execution/executor.hpp" #include "asio/execution_context.hpp" #include "asio/is_executor.hpp" #include "asio/uses_executor.hpp" @@ -30,12 +30,6 @@ namespace asio { namespace detail { -template <typename T> -struct executor_binder_check -{ - typedef void type; -}; - // Helper to automatically define nested typedef result_type. template <typename T, typename = void> @@ -46,8 +40,7 @@ protected: }; template <typename T> -struct executor_binder_result_type<T, - typename executor_binder_check<typename T::result_type>::type> +struct executor_binder_result_type<T, void_t<typename T::result_type>> { typedef typename T::result_type result_type; protected: @@ -108,8 +101,7 @@ template <typename T, typename = void> struct executor_binder_argument_type {}; template <typename T> -struct executor_binder_argument_type<T, - typename executor_binder_check<typename T::argument_type>::type> +struct executor_binder_argument_type<T, void_t<typename T::argument_type>> { typedef typename T::argument_type argument_type; }; @@ -134,7 +126,7 @@ struct executor_binder_argument_types {}; template <typename T> struct executor_binder_argument_types<T, - typename executor_binder_check<typename T::first_argument_type>::type> + void_t<typename T::first_argument_type>> { typedef typename T::first_argument_type first_argument_type; typedef typename T::second_argument_type second_argument_type; @@ -154,22 +146,20 @@ struct executor_binder_argument_type<R(&)(A1, A2)> typedef A2 second_argument_type; }; -// Helper to: -// - Apply the empty base optimisation to the executor. -// - Perform uses_executor construction of the target type, if required. +// Helper to perform uses_executor construction of the target type, if +// required. template <typename T, typename Executor, bool UsesExecutor> class executor_binder_base; template <typename T, typename Executor> class executor_binder_base<T, Executor, true> - : protected Executor { protected: template <typename E, typename U> - executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u) - : executor_(ASIO_MOVE_CAST(E)(e)), - target_(executor_arg_t(), executor_, ASIO_MOVE_CAST(U)(u)) + executor_binder_base(E&& e, U&& u) + : executor_(static_cast<E&&>(e)), + target_(executor_arg_t(), executor_, static_cast<U&&>(u)) { } @@ -182,9 +172,9 @@ class executor_binder_base<T, Executor, false> { protected: template <typename E, typename U> - executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u) - : executor_(ASIO_MOVE_CAST(E)(e)), - target_(ASIO_MOVE_CAST(U)(u)) + executor_binder_base(E&& e, U&& u) + : executor_(static_cast<E&&>(e)), + target_(static_cast<U&&>(u)) { } @@ -192,21 +182,6 @@ protected: T target_; }; -// Helper to enable SFINAE on zero-argument operator() below. - -template <typename T, typename = void> -struct executor_binder_result_of0 -{ - typedef void type; -}; - -template <typename T> -struct executor_binder_result_of0<T, - typename executor_binder_check<typename result_of<T()>::type>::type> -{ - typedef typename result_of<T()>::type type; -}; - } // namespace detail /// A call wrapper type to bind an executor of type @c Executor to an object of @@ -297,8 +272,8 @@ public: */ template <typename U> executor_binder(executor_arg_t, const executor_type& e, - ASIO_MOVE_ARG(U) u) - : base_type(e, ASIO_MOVE_CAST(U)(u)) + U&& u) + : base_type(e, static_cast<U&&>(u)) { } @@ -322,7 +297,9 @@ public: * @c U. */ template <typename U, typename OtherExecutor> - executor_binder(const executor_binder<U, OtherExecutor>& other) + executor_binder(const executor_binder<U, OtherExecutor>& other, + constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) : base_type(other.get_executor(), other.get()) { } @@ -335,32 +312,33 @@ public: */ template <typename U, typename OtherExecutor> executor_binder(executor_arg_t, const executor_type& e, - const executor_binder<U, OtherExecutor>& other) + const executor_binder<U, OtherExecutor>& other, + constraint_t<is_constructible<T, U>::value> = 0) : base_type(e, other.get()) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move constructor. executor_binder(executor_binder&& other) - : base_type(ASIO_MOVE_CAST(executor_type)(other.get_executor()), - ASIO_MOVE_CAST(T)(other.get())) + : base_type(static_cast<executor_type&&>(other.get_executor()), + static_cast<T&&>(other.get())) { } /// Move construct the target object, but specify a different executor. executor_binder(executor_arg_t, const executor_type& e, executor_binder&& other) - : base_type(e, ASIO_MOVE_CAST(T)(other.get())) + : base_type(e, static_cast<T&&>(other.get())) { } /// Move construct from a different executor wrapper type. template <typename U, typename OtherExecutor> - executor_binder(executor_binder<U, OtherExecutor>&& other) - : base_type(ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()), - ASIO_MOVE_CAST(U)(other.get())) + executor_binder(executor_binder<U, OtherExecutor>&& other, + constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) + : base_type(static_cast<OtherExecutor&&>(other.get_executor()), + static_cast<U&&>(other.get())) { } @@ -368,124 +346,49 @@ public: /// different executor. template <typename U, typename OtherExecutor> executor_binder(executor_arg_t, const executor_type& e, - executor_binder<U, OtherExecutor>&& other) - : base_type(e, ASIO_MOVE_CAST(U)(other.get())) + executor_binder<U, OtherExecutor>&& other, + constraint_t<is_constructible<T, U>::value> = 0) + : base_type(e, static_cast<U&&>(other.get())) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Destructor. ~executor_binder() { } /// Obtain a reference to the target object. - target_type& get() ASIO_NOEXCEPT + target_type& get() noexcept { return this->target_; } /// Obtain a reference to the target object. - const target_type& get() const ASIO_NOEXCEPT + const target_type& get() const noexcept { return this->target_; } /// Obtain the associated executor. - executor_type get_executor() const ASIO_NOEXCEPT + executor_type get_executor() const noexcept { return this->executor_; } -#if defined(GENERATING_DOCUMENTATION) - - template <typename... Args> auto operator()(Args&& ...); - template <typename... Args> auto operator()(Args&& ...) const; - -#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) - /// Forwarding function call operator. template <typename... Args> - typename result_of<T(Args...)>::type operator()( - ASIO_MOVE_ARG(Args)... args) + result_of_t<T(Args...)> operator()(Args&&... args) { - return this->target_(ASIO_MOVE_CAST(Args)(args)...); + return this->target_(static_cast<Args&&>(args)...); } /// Forwarding function call operator. template <typename... Args> - typename result_of<T(Args...)>::type operator()( - ASIO_MOVE_ARG(Args)... args) const - { - return this->target_(ASIO_MOVE_CAST(Args)(args)...); - } - -#elif defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) - - typename detail::executor_binder_result_of0<T>::type operator()() - { - return this->target_(); - } - - typename detail::executor_binder_result_of0<T>::type operator()() const - { - return this->target_(); - } - -#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \ - ASIO_VARIADIC_MOVE_PARAMS(n)) \ - { \ - return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ - } \ - \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \ - ASIO_VARIADIC_MOVE_PARAMS(n)) const \ - { \ - return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) -#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF - -#else // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) - - typedef typename detail::executor_binder_result_type<T>::result_type_or_void - result_type_or_void; - - result_type_or_void operator()() - { - return this->target_(); - } - - result_type_or_void operator()() const + result_of_t<T(Args...)> operator()(Args&&... args) const { - return this->target_(); + return this->target_(static_cast<Args&&>(args)...); } -#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - result_type_or_void operator()( \ - ASIO_VARIADIC_MOVE_PARAMS(n)) \ - { \ - return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ - } \ - \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - result_type_or_void operator()( \ - ASIO_VARIADIC_MOVE_PARAMS(n)) const \ - { \ - return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) -#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF - -#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) - private: typedef detail::executor_binder_base<T, Executor, uses_executor<T, Executor>::value> base_type; @@ -493,25 +396,27 @@ private: /// Associate an object of type @c T with an executor of type @c Executor. template <typename Executor, typename T> -inline executor_binder<typename decay<T>::type, Executor> -bind_executor(const Executor& ex, ASIO_MOVE_ARG(T) t, - typename enable_if<is_executor<Executor>::value>::type* = 0) +ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor> +bind_executor(const Executor& ex, T&& t, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) { - return executor_binder<typename decay<T>::type, Executor>( - executor_arg_t(), ex, ASIO_MOVE_CAST(T)(t)); + return executor_binder<decay_t<T>, Executor>( + executor_arg_t(), ex, static_cast<T&&>(t)); } /// Associate an object of type @c T with an execution context's executor. template <typename ExecutionContext, typename T> -inline executor_binder<typename decay<T>::type, - typename ExecutionContext::executor_type> -bind_executor(ExecutionContext& ctx, ASIO_MOVE_ARG(T) t, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type* = 0) +ASIO_NODISCARD inline executor_binder<decay_t<T>, + typename ExecutionContext::executor_type> +bind_executor(ExecutionContext& ctx, T&& t, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) { - return executor_binder<typename decay<T>::type, - typename ExecutionContext::executor_type>( - executor_arg_t(), ctx.get_executor(), ASIO_MOVE_CAST(T)(t)); + return executor_binder<decay_t<T>, typename ExecutionContext::executor_type>( + executor_arg_t(), ctx.get_executor(), static_cast<T&&>(t)); } #if !defined(GENERATING_DOCUMENTATION) @@ -520,73 +425,138 @@ template <typename T, typename Executor> struct uses_executor<executor_binder<T, Executor>, Executor> : true_type {}; -template <typename T, typename Executor, typename Signature> -class async_result<executor_binder<T, Executor>, Signature> +namespace detail { + +template <typename TargetAsyncResult, typename Executor, typename = void> +class executor_binder_completion_handler_async_result +{ +public: + template <typename T> + explicit executor_binder_completion_handler_async_result(T&) + { + } +}; + +template <typename TargetAsyncResult, typename Executor> +class executor_binder_completion_handler_async_result< + TargetAsyncResult, Executor, + void_t<typename TargetAsyncResult::completion_handler_type >> { +private: + TargetAsyncResult target_; + public: typedef executor_binder< - typename async_result<T, Signature>::completion_handler_type, Executor> + typename TargetAsyncResult::completion_handler_type, Executor> completion_handler_type; - typedef typename async_result<T, Signature>::return_type return_type; - - explicit async_result(executor_binder<T, Executor>& b) - : target_(b.get()) + explicit executor_binder_completion_handler_async_result( + typename TargetAsyncResult::completion_handler_type& handler) + : target_(handler) { } - return_type get() + auto get() -> decltype(target_.get()) { return target_.get(); } - -private: - async_result(const async_result&) ASIO_DELETED; - async_result& operator=(const async_result&) ASIO_DELETED; - - async_result<T, Signature> target_; }; -#if !defined(ASIO_NO_DEPRECATED) +template <typename TargetAsyncResult, typename = void> +struct executor_binder_async_result_return_type +{ +}; -template <typename T, typename Executor, typename Signature> -struct handler_type<executor_binder<T, Executor>, Signature> +template <typename TargetAsyncResult> +struct executor_binder_async_result_return_type<TargetAsyncResult, + void_t<typename TargetAsyncResult::return_type>> { - typedef executor_binder< - typename handler_type<T, Signature>::type, Executor> type; + typedef typename TargetAsyncResult::return_type return_type; }; -template <typename T, typename Executor> -class async_result<executor_binder<T, Executor> > +} // namespace detail + +template <typename T, typename Executor, typename Signature> +class async_result<executor_binder<T, Executor>, Signature> : + public detail::executor_binder_completion_handler_async_result< + async_result<T, Signature>, Executor>, + public detail::executor_binder_async_result_return_type< + async_result<T, Signature>> { public: - typedef typename async_result<T>::type type; - explicit async_result(executor_binder<T, Executor>& b) - : target_(b.get()) + : detail::executor_binder_completion_handler_async_result< + async_result<T, Signature>, Executor>(b.get()) { } - type get() + template <typename Initiation> + struct init_wrapper { - return target_.get(); + template <typename Init> + init_wrapper(const Executor& ex, Init&& init) + : ex_(ex), + initiation_(static_cast<Init&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + executor_binder<decay_t<Handler>, Executor>( + executor_arg_t(), ex_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) const + { + initiation_( + executor_binder<decay_t<Handler>, Executor>( + executor_arg_t(), ex_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + Executor ex_; + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<T, Signature>( + declval<init_wrapper<decay_t<Initiation>>>(), + token.get(), static_cast<Args&&>(args)...)) + { + return async_initiate<T, Signature>( + init_wrapper<decay_t<Initiation>>( + token.get_executor(), static_cast<Initiation&&>(initiation)), + token.get(), static_cast<Args&&>(args)...); } private: - async_result<T> target_; + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; }; -#endif // !defined(ASIO_NO_DEPRECATED) - -template <typename T, typename Executor, typename Allocator> -struct associated_allocator<executor_binder<T, Executor>, Allocator> +template <template <typename, typename> class Associator, + typename T, typename Executor, typename DefaultCandidate> +struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate> + : Associator<T, DefaultCandidate> { - typedef typename associated_allocator<T, Allocator>::type type; + static typename Associator<T, DefaultCandidate>::type get( + const executor_binder<T, Executor>& b) noexcept + { + return Associator<T, DefaultCandidate>::get(b.get()); + } - static type get(const executor_binder<T, Executor>& b, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static auto get(const executor_binder<T, Executor>& b, + const DefaultCandidate& c) noexcept + -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c)) { - return associated_allocator<T, Allocator>::get(b.get(), a); + return Associator<T, DefaultCandidate>::get(b.get(), c); } }; @@ -595,8 +565,9 @@ struct associated_executor<executor_binder<T, Executor>, Executor1> { typedef Executor type; - static type get(const executor_binder<T, Executor>& b, - const Executor1& = Executor1()) ASIO_NOEXCEPT + static auto get(const executor_binder<T, Executor>& b, + const Executor1& = Executor1()) noexcept + -> decltype(b.get_executor()) { return b.get_executor(); } diff --git a/3rdparty/asio/include/asio/bind_immediate_executor.hpp b/3rdparty/asio/include/asio/bind_immediate_executor.hpp new file mode 100644 index 00000000000..b02c520a689 --- /dev/null +++ b/3rdparty/asio/include/asio/bind_immediate_executor.hpp @@ -0,0 +1,549 @@ +// +// bind_immediate_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BIND_IMMEDIATE_EXECUTOR_HPP +#define ASIO_BIND_IMMEDIATE_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/associated_immediate_executor.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper to automatically define nested typedef result_type. + +template <typename T, typename = void> +struct immediate_executor_binder_result_type +{ +protected: + typedef void result_type_or_void; +}; + +template <typename T> +struct immediate_executor_binder_result_type<T, void_t<typename T::result_type>> +{ + typedef typename T::result_type result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct immediate_executor_binder_result_type<R(*)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct immediate_executor_binder_result_type<R(&)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct immediate_executor_binder_result_type<R(*)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct immediate_executor_binder_result_type<R(&)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct immediate_executor_binder_result_type<R(*)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct immediate_executor_binder_result_type<R(&)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +// Helper to automatically define nested typedef argument_type. + +template <typename T, typename = void> +struct immediate_executor_binder_argument_type {}; + +template <typename T> +struct immediate_executor_binder_argument_type<T, + void_t<typename T::argument_type>> +{ + typedef typename T::argument_type argument_type; +}; + +template <typename R, typename A1> +struct immediate_executor_binder_argument_type<R(*)(A1)> +{ + typedef A1 argument_type; +}; + +template <typename R, typename A1> +struct immediate_executor_binder_argument_type<R(&)(A1)> +{ + typedef A1 argument_type; +}; + +// Helper to automatically define nested typedefs first_argument_type and +// second_argument_type. + +template <typename T, typename = void> +struct immediate_executor_binder_argument_types {}; + +template <typename T> +struct immediate_executor_binder_argument_types<T, + void_t<typename T::first_argument_type>> +{ + typedef typename T::first_argument_type first_argument_type; + typedef typename T::second_argument_type second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct immediate_executor_binder_argument_type<R(*)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct immediate_executor_binder_argument_type<R(&)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +} // namespace detail + +/// A call wrapper type to bind a immediate executor of type @c Executor +/// to an object of type @c T. +template <typename T, typename Executor> +class immediate_executor_binder +#if !defined(GENERATING_DOCUMENTATION) + : public detail::immediate_executor_binder_result_type<T>, + public detail::immediate_executor_binder_argument_type<T>, + public detail::immediate_executor_binder_argument_types<T> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +public: + /// The type of the target object. + typedef T target_type; + + /// The type of the associated immediate executor. + typedef Executor immediate_executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The return type if a function. + /** + * The type of @c result_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to function type, @c result_type is a synonym for + * the return type of @c T; + * + * @li if @c T is a class type with a member type @c result_type, then @c + * result_type is a synonym for @c T::result_type; + * + * @li otherwise @c result_type is not defined. + */ + typedef see_below result_type; + + /// The type of the function's argument. + /** + * The type of @c argument_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to a function type accepting a single argument, + * @c argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c argument_type, then @c + * argument_type is a synonym for @c T::argument_type; + * + * @li otherwise @c argument_type is not defined. + */ + typedef see_below argument_type; + + /// The type of the function's first argument. + /** + * The type of @c first_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * first_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c first_argument_type is a synonym for @c T::first_argument_type; + * + * @li otherwise @c first_argument_type is not defined. + */ + typedef see_below first_argument_type; + + /// The type of the function's second argument. + /** + * The type of @c second_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * second_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c second_argument_type is a synonym for @c T::second_argument_type; + * + * @li otherwise @c second_argument_type is not defined. + */ + typedef see_below second_argument_type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct a immediate executor wrapper for the specified object. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U> + immediate_executor_binder(const immediate_executor_type& e, + U&& u) + : executor_(e), + target_(static_cast<U&&>(u)) + { + } + + /// Copy constructor. + immediate_executor_binder(const immediate_executor_binder& other) + : executor_(other.get_immediate_executor()), + target_(other.get()) + { + } + + /// Construct a copy, but specify a different immediate executor. + immediate_executor_binder(const immediate_executor_type& e, + const immediate_executor_binder& other) + : executor_(e), + target_(other.get()) + { + } + + /// Construct a copy of a different immediate executor wrapper type. + /** + * This constructor is only valid if the @c Executor type is + * constructible from type @c OtherExecutor, and the type @c T is + * constructible from type @c U. + */ + template <typename U, typename OtherExecutor> + immediate_executor_binder( + const immediate_executor_binder<U, OtherExecutor>& other, + constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) + : executor_(other.get_immediate_executor()), + target_(other.get()) + { + } + + /// Construct a copy of a different immediate executor wrapper type, but + /// specify a different immediate executor. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U, typename OtherExecutor> + immediate_executor_binder(const immediate_executor_type& e, + const immediate_executor_binder<U, OtherExecutor>& other, + constraint_t<is_constructible<T, U>::value> = 0) + : executor_(e), + target_(other.get()) + { + } + + /// Move constructor. + immediate_executor_binder(immediate_executor_binder&& other) + : executor_(static_cast<immediate_executor_type&&>( + other.get_immediate_executor())), + target_(static_cast<T&&>(other.get())) + { + } + + /// Move construct the target object, but specify a different immediate + /// executor. + immediate_executor_binder(const immediate_executor_type& e, + immediate_executor_binder&& other) + : executor_(e), + target_(static_cast<T&&>(other.get())) + { + } + + /// Move construct from a different immediate executor wrapper type. + template <typename U, typename OtherExecutor> + immediate_executor_binder( + immediate_executor_binder<U, OtherExecutor>&& other, + constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0, + constraint_t<is_constructible<T, U>::value> = 0) + : executor_(static_cast<OtherExecutor&&>( + other.get_immediate_executor())), + target_(static_cast<U&&>(other.get())) + { + } + + /// Move construct from a different immediate executor wrapper type, but + /// specify a different immediate executor. + template <typename U, typename OtherExecutor> + immediate_executor_binder(const immediate_executor_type& e, + immediate_executor_binder<U, OtherExecutor>&& other, + constraint_t<is_constructible<T, U>::value> = 0) + : executor_(e), + target_(static_cast<U&&>(other.get())) + { + } + + /// Destructor. + ~immediate_executor_binder() + { + } + + /// Obtain a reference to the target object. + target_type& get() noexcept + { + return target_; + } + + /// Obtain a reference to the target object. + const target_type& get() const noexcept + { + return target_; + } + + /// Obtain the associated immediate executor. + immediate_executor_type get_immediate_executor() const noexcept + { + return executor_; + } + + /// Forwarding function call operator. + template <typename... Args> + result_of_t<T(Args...)> operator()(Args&&... args) + { + return target_(static_cast<Args&&>(args)...); + } + + /// Forwarding function call operator. + template <typename... Args> + result_of_t<T(Args...)> operator()(Args&&... args) const + { + return target_(static_cast<Args&&>(args)...); + } + +private: + Executor executor_; + T target_; +}; + +/// Associate an object of type @c T with a immediate executor of type +/// @c Executor. +template <typename Executor, typename T> +ASIO_NODISCARD inline immediate_executor_binder<decay_t<T>, Executor> +bind_immediate_executor(const Executor& e, T&& t) +{ + return immediate_executor_binder< + decay_t<T>, Executor>( + e, static_cast<T&&>(t)); +} + +#if !defined(GENERATING_DOCUMENTATION) + +namespace detail { + +template <typename TargetAsyncResult, typename Executor, typename = void> +class immediate_executor_binder_completion_handler_async_result +{ +public: + template <typename T> + explicit immediate_executor_binder_completion_handler_async_result(T&) + { + } +}; + +template <typename TargetAsyncResult, typename Executor> +class immediate_executor_binder_completion_handler_async_result< + TargetAsyncResult, Executor, + void_t< + typename TargetAsyncResult::completion_handler_type + >> +{ +private: + TargetAsyncResult target_; + +public: + typedef immediate_executor_binder< + typename TargetAsyncResult::completion_handler_type, Executor> + completion_handler_type; + + explicit immediate_executor_binder_completion_handler_async_result( + typename TargetAsyncResult::completion_handler_type& handler) + : target_(handler) + { + } + + auto get() -> decltype(target_.get()) + { + return target_.get(); + } +}; + +template <typename TargetAsyncResult, typename = void> +struct immediate_executor_binder_async_result_return_type +{ +}; + +template <typename TargetAsyncResult> +struct immediate_executor_binder_async_result_return_type< + TargetAsyncResult, + void_t< + typename TargetAsyncResult::return_type + >> +{ + typedef typename TargetAsyncResult::return_type return_type; +}; + +} // namespace detail + +template <typename T, typename Executor, typename Signature> +class async_result<immediate_executor_binder<T, Executor>, Signature> : + public detail::immediate_executor_binder_completion_handler_async_result< + async_result<T, Signature>, Executor>, + public detail::immediate_executor_binder_async_result_return_type< + async_result<T, Signature>> +{ +public: + explicit async_result(immediate_executor_binder<T, Executor>& b) + : detail::immediate_executor_binder_completion_handler_async_result< + async_result<T, Signature>, Executor>(b.get()) + { + } + + template <typename Initiation> + struct init_wrapper + { + template <typename Init> + init_wrapper(const Executor& e, Init&& init) + : executor_(e), + initiation_(static_cast<Init&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + immediate_executor_binder< + decay_t<Handler>, Executor>( + executor_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) const + { + initiation_( + immediate_executor_binder< + decay_t<Handler>, Executor>( + executor_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + Executor executor_; + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<T, Signature>( + declval<init_wrapper<decay_t<Initiation>>>(), + token.get(), static_cast<Args&&>(args)...)) + { + return async_initiate<T, Signature>( + init_wrapper<decay_t<Initiation>>( + token.get_immediate_executor(), + static_cast<Initiation&&>(initiation)), + token.get(), static_cast<Args&&>(args)...); + } + +private: + async_result(const async_result&) = delete; + async_result& operator=(const async_result&) = delete; + + async_result<T, Signature> target_; +}; + +template <template <typename, typename> class Associator, + typename T, typename Executor, typename DefaultCandidate> +struct associator<Associator, + immediate_executor_binder<T, Executor>, + DefaultCandidate> + : Associator<T, DefaultCandidate> +{ + static typename Associator<T, DefaultCandidate>::type get( + const immediate_executor_binder<T, Executor>& b) noexcept + { + return Associator<T, DefaultCandidate>::get(b.get()); + } + + static auto get(const immediate_executor_binder<T, Executor>& b, + const DefaultCandidate& c) noexcept + -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c)) + { + return Associator<T, DefaultCandidate>::get(b.get(), c); + } +}; + +template <typename T, typename Executor, typename Executor1> +struct associated_immediate_executor< + immediate_executor_binder<T, Executor>, + Executor1> +{ + typedef Executor type; + + static auto get(const immediate_executor_binder<T, Executor>& b, + const Executor1& = Executor1()) noexcept + -> decltype(b.get_immediate_executor()) + { + return b.get_immediate_executor(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BIND_IMMEDIATE_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/buffer.hpp b/3rdparty/asio/include/asio/buffer.hpp index 094353eb52d..ad49f290a66 100644 --- a/3rdparty/asio/include/asio/buffer.hpp +++ b/3rdparty/asio/include/asio/buffer.hpp @@ -2,7 +2,7 @@ // buffer.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,18 +23,19 @@ #include <string> #include <vector> #include "asio/detail/array_fwd.hpp" -#include "asio/detail/is_buffer_sequence.hpp" +#include "asio/detail/memory.hpp" #include "asio/detail/string_view.hpp" #include "asio/detail/throw_exception.hpp" #include "asio/detail/type_traits.hpp" +#include "asio/is_contiguous_iterator.hpp" -#if defined(ASIO_MSVC) +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1700) # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) # if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # define ASIO_ENABLE_BUFFER_DEBUGGING # endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # endif // defined(_HAS_ITERATOR_DEBUGGING) -#endif // defined(ASIO_MSVC) +#endif // defined(ASIO_MSVC) && (ASIO_MSVC >= 1700) #if defined(__GNUC__) # if defined(_GLIBCXX_DEBUG) @@ -48,19 +49,6 @@ # include "asio/detail/functional.hpp" #endif // ASIO_ENABLE_BUFFER_DEBUGGING -#if defined(ASIO_HAS_BOOST_WORKAROUND) -# include <boost/detail/workaround.hpp> -# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ - || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) -# define ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND -# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) - // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) -#endif // defined(ASIO_HAS_BOOST_WORKAROUND) - -#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) -# include "asio/detail/type_traits.hpp" -#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) - #include "asio/detail/push_options.hpp" namespace asio { @@ -91,14 +79,14 @@ class mutable_buffer { public: /// Construct an empty buffer. - mutable_buffer() ASIO_NOEXCEPT + mutable_buffer() noexcept : data_(0), size_(0) { } /// Construct a buffer to represent a given memory range. - mutable_buffer(void* data, std::size_t size) ASIO_NOEXCEPT + mutable_buffer(void* data, std::size_t size) noexcept : data_(data), size_(size) { @@ -120,7 +108,7 @@ public: #endif // ASIO_ENABLE_BUFFER_DEBUGGING /// Get a pointer to the beginning of the memory range. - void* data() const ASIO_NOEXCEPT + void* data() const noexcept { #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (size_ && debug_check_) @@ -130,13 +118,13 @@ public: } /// Get the size of the memory range. - std::size_t size() const ASIO_NOEXCEPT + std::size_t size() const noexcept { return size_; } /// Move the start of the buffer by the specified number of bytes. - mutable_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT + mutable_buffer& operator+=(std::size_t n) noexcept { std::size_t offset = n < size_ ? n : size_; data_ = static_cast<char*>(data_) + offset; @@ -168,7 +156,7 @@ public: typedef const mutable_buffer* const_iterator; /// Construct to represent a given memory range. - mutable_buffers_1(void* data, std::size_t size) ASIO_NOEXCEPT + mutable_buffers_1(void* data, std::size_t size) noexcept : mutable_buffer(data, size) { } @@ -182,19 +170,19 @@ public: #endif // ASIO_ENABLE_BUFFER_DEBUGGING /// Construct to represent a single modifiable buffer. - explicit mutable_buffers_1(const mutable_buffer& b) ASIO_NOEXCEPT + explicit mutable_buffers_1(const mutable_buffer& b) noexcept : mutable_buffer(b) { } /// Get a random-access iterator to the first element. - const_iterator begin() const ASIO_NOEXCEPT + const_iterator begin() const noexcept { return this; } /// Get a random-access iterator for one past the last element. - const_iterator end() const ASIO_NOEXCEPT + const_iterator end() const noexcept { return begin() + 1; } @@ -225,21 +213,21 @@ class const_buffer { public: /// Construct an empty buffer. - const_buffer() ASIO_NOEXCEPT + const_buffer() noexcept : data_(0), size_(0) { } /// Construct a buffer to represent a given memory range. - const_buffer(const void* data, std::size_t size) ASIO_NOEXCEPT + const_buffer(const void* data, std::size_t size) noexcept : data_(data), size_(size) { } /// Construct a non-modifiable buffer from a modifiable one. - const_buffer(const mutable_buffer& b) ASIO_NOEXCEPT + const_buffer(const mutable_buffer& b) noexcept : data_(b.data()), size_(b.size()) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) @@ -264,7 +252,7 @@ public: #endif // ASIO_ENABLE_BUFFER_DEBUGGING /// Get a pointer to the beginning of the memory range. - const void* data() const ASIO_NOEXCEPT + const void* data() const noexcept { #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (size_ && debug_check_) @@ -274,13 +262,13 @@ public: } /// Get the size of the memory range. - std::size_t size() const ASIO_NOEXCEPT + std::size_t size() const noexcept { return size_; } /// Move the start of the buffer by the specified number of bytes. - const_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT + const_buffer& operator+=(std::size_t n) noexcept { std::size_t offset = n < size_ ? n : size_; data_ = static_cast<const char*>(data_) + offset; @@ -312,7 +300,7 @@ public: typedef const const_buffer* const_iterator; /// Construct to represent a given memory range. - const_buffers_1(const void* data, std::size_t size) ASIO_NOEXCEPT + const_buffers_1(const void* data, std::size_t size) noexcept : const_buffer(data, size) { } @@ -326,19 +314,19 @@ public: #endif // ASIO_ENABLE_BUFFER_DEBUGGING /// Construct to represent a single non-modifiable buffer. - explicit const_buffers_1(const const_buffer& b) ASIO_NOEXCEPT + explicit const_buffers_1(const const_buffer& b) noexcept : const_buffer(b) { } /// Get a random-access iterator to the first element. - const_iterator begin() const ASIO_NOEXCEPT + const_iterator begin() const noexcept { return this; } /// Get a random-access iterator for one past the last element. - const_iterator end() const ASIO_NOEXCEPT + const_iterator end() const noexcept { return begin() + 1; } @@ -346,41 +334,6 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) -/// Trait to determine whether a type satisfies the MutableBufferSequence -/// requirements. -template <typename T> -struct is_mutable_buffer_sequence -#if defined(GENERATING_DOCUMENTATION) - : integral_constant<bool, automatically_determined> -#else // defined(GENERATING_DOCUMENTATION) - : asio::detail::is_buffer_sequence<T, mutable_buffer> -#endif // defined(GENERATING_DOCUMENTATION) -{ -}; - -/// Trait to determine whether a type satisfies the ConstBufferSequence -/// requirements. -template <typename T> -struct is_const_buffer_sequence -#if defined(GENERATING_DOCUMENTATION) - : integral_constant<bool, automatically_determined> -#else // defined(GENERATING_DOCUMENTATION) - : asio::detail::is_buffer_sequence<T, const_buffer> -#endif // defined(GENERATING_DOCUMENTATION) -{ -}; - -/// Trait to determine whether a type satisfies the DynamicBuffer requirements. -template <typename T> -struct is_dynamic_buffer -#if defined(GENERATING_DOCUMENTATION) - : integral_constant<bool, automatically_determined> -#else // defined(GENERATING_DOCUMENTATION) - : asio::detail::is_dynamic_buffer<T> -#endif // defined(GENERATING_DOCUMENTATION) -{ -}; - /// (Deprecated: Use the socket/descriptor wait() and async_wait() member /// functions.) An implementation of both the ConstBufferSequence and /// MutableBufferSequence concepts to represent a null buffer sequence. @@ -394,13 +347,13 @@ public: typedef const mutable_buffer* const_iterator; /// Get a random-access iterator to the first element. - const_iterator begin() const ASIO_NOEXCEPT + const_iterator begin() const noexcept { return &buf_; } /// Get a random-access iterator for one past the last element. - const_iterator end() const ASIO_NOEXCEPT + const_iterator end() const noexcept { return &buf_; } @@ -417,49 +370,47 @@ private: /*@{*/ /// Get an iterator to the first element in a buffer sequence. -inline const mutable_buffer* buffer_sequence_begin(const mutable_buffer& b) +template <typename MutableBuffer> +inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b, + constraint_t< + is_convertible<const MutableBuffer*, const mutable_buffer*>::value + > = 0) noexcept { - return &b; + return static_cast<const mutable_buffer*>(detail::addressof(b)); } /// Get an iterator to the first element in a buffer sequence. -inline const const_buffer* buffer_sequence_begin(const const_buffer& b) +template <typename ConstBuffer> +inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b, + constraint_t< + is_convertible<const ConstBuffer*, const const_buffer*>::value + > = 0) noexcept { - return &b; + return static_cast<const const_buffer*>(detail::addressof(b)); } -#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) - /// Get an iterator to the first element in a buffer sequence. template <typename C> -inline auto buffer_sequence_begin(C& c) -> decltype(c.begin()) +inline auto buffer_sequence_begin(C& c, + constraint_t< + !is_convertible<const C*, const mutable_buffer*>::value + && !is_convertible<const C*, const const_buffer*>::value + > = 0) noexcept -> decltype(c.begin()) { return c.begin(); } /// Get an iterator to the first element in a buffer sequence. template <typename C> -inline auto buffer_sequence_begin(const C& c) -> decltype(c.begin()) +inline auto buffer_sequence_begin(const C& c, + constraint_t< + !is_convertible<const C*, const mutable_buffer*>::value + && !is_convertible<const C*, const const_buffer*>::value + > = 0) noexcept -> decltype(c.begin()) { return c.begin(); } -#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) - -template <typename C> -inline typename C::iterator buffer_sequence_begin(C& c) -{ - return c.begin(); -} - -template <typename C> -inline typename C::const_iterator buffer_sequence_begin(const C& c) -{ - return c.begin(); -} - -#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) - /*@}*/ /** @defgroup buffer_sequence_end asio::buffer_sequence_end @@ -470,49 +421,47 @@ inline typename C::const_iterator buffer_sequence_begin(const C& c) /*@{*/ /// Get an iterator to one past the end element in a buffer sequence. -inline const mutable_buffer* buffer_sequence_end(const mutable_buffer& b) +template <typename MutableBuffer> +inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b, + constraint_t< + is_convertible<const MutableBuffer*, const mutable_buffer*>::value + > = 0) noexcept { - return &b + 1; + return static_cast<const mutable_buffer*>(detail::addressof(b)) + 1; } /// Get an iterator to one past the end element in a buffer sequence. -inline const const_buffer* buffer_sequence_end(const const_buffer& b) +template <typename ConstBuffer> +inline const const_buffer* buffer_sequence_end(const ConstBuffer& b, + constraint_t< + is_convertible<const ConstBuffer*, const const_buffer*>::value + > = 0) noexcept { - return &b + 1; + return static_cast<const const_buffer*>(detail::addressof(b)) + 1; } -#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) - /// Get an iterator to one past the end element in a buffer sequence. template <typename C> -inline auto buffer_sequence_end(C& c) -> decltype(c.end()) +inline auto buffer_sequence_end(C& c, + constraint_t< + !is_convertible<const C*, const mutable_buffer*>::value + && !is_convertible<const C*, const const_buffer*>::value + > = 0) noexcept -> decltype(c.end()) { return c.end(); } /// Get an iterator to one past the end element in a buffer sequence. template <typename C> -inline auto buffer_sequence_end(const C& c) -> decltype(c.end()) -{ - return c.end(); -} - -#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) - -template <typename C> -inline typename C::iterator buffer_sequence_end(C& c) +inline auto buffer_sequence_end(const C& c, + constraint_t< + !is_convertible<const C*, const mutable_buffer*>::value + && !is_convertible<const C*, const const_buffer*>::value + > = 0) noexcept -> decltype(c.end()) { return c.end(); } -template <typename C> -inline typename C::const_iterator buffer_sequence_end(const C& c) -{ - return c.end(); -} - -#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) - /*@}*/ namespace detail { @@ -524,25 +473,25 @@ struct multiple_buffers {}; // Helper trait to detect single buffers. template <typename BufferSequence> struct buffer_sequence_cardinality : - conditional< + conditional_t< is_same<BufferSequence, mutable_buffer>::value #if !defined(ASIO_NO_DEPRECATED) || is_same<BufferSequence, mutable_buffers_1>::value || is_same<BufferSequence, const_buffers_1>::value #endif // !defined(ASIO_NO_DEPRECATED) || is_same<BufferSequence, const_buffer>::value, - one_buffer, multiple_buffers>::type {}; + one_buffer, multiple_buffers> {}; template <typename Iterator> inline std::size_t buffer_size(one_buffer, - Iterator begin, Iterator) ASIO_NOEXCEPT + Iterator begin, Iterator) noexcept { return const_buffer(*begin).size(); } template <typename Iterator> inline std::size_t buffer_size(multiple_buffers, - Iterator begin, Iterator end) ASIO_NOEXCEPT + Iterator begin, Iterator end) noexcept { std::size_t total_buffer_size = 0; @@ -577,7 +526,7 @@ inline std::size_t buffer_size(multiple_buffers, * ConstBufferSequence or @c MutableBufferSequence type requirements. */ template <typename BufferSequence> -inline std::size_t buffer_size(const BufferSequence& b) ASIO_NOEXCEPT +inline std::size_t buffer_size(const BufferSequence& b) noexcept { return detail::buffer_size( detail::buffer_sequence_cardinality<BufferSequence>(), @@ -612,14 +561,14 @@ inline std::size_t buffer_size(const BufferSequence& b) ASIO_NOEXCEPT /// Cast a non-modifiable buffer to a specified pointer to POD type. template <typename PointerToPodType> -inline PointerToPodType buffer_cast(const mutable_buffer& b) ASIO_NOEXCEPT +inline PointerToPodType buffer_cast(const mutable_buffer& b) noexcept { return static_cast<PointerToPodType>(b.data()); } /// Cast a non-modifiable buffer to a specified pointer to POD type. template <typename PointerToPodType> -inline PointerToPodType buffer_cast(const const_buffer& b) ASIO_NOEXCEPT +inline PointerToPodType buffer_cast(const const_buffer& b) noexcept { return static_cast<PointerToPodType>(b.data()); } @@ -633,7 +582,7 @@ inline PointerToPodType buffer_cast(const const_buffer& b) ASIO_NOEXCEPT * @relates mutable_buffer */ inline mutable_buffer operator+(const mutable_buffer& b, - std::size_t n) ASIO_NOEXCEPT + std::size_t n) noexcept { std::size_t offset = n < b.size() ? n : b.size(); char* new_data = static_cast<char*>(b.data()) + offset; @@ -650,7 +599,7 @@ inline mutable_buffer operator+(const mutable_buffer& b, * @relates mutable_buffer */ inline mutable_buffer operator+(std::size_t n, - const mutable_buffer& b) ASIO_NOEXCEPT + const mutable_buffer& b) noexcept { return b + n; } @@ -660,7 +609,7 @@ inline mutable_buffer operator+(std::size_t n, * @relates const_buffer */ inline const_buffer operator+(const const_buffer& b, - std::size_t n) ASIO_NOEXCEPT + std::size_t n) noexcept { std::size_t offset = n < b.size() ? n : b.size(); const char* new_data = static_cast<const char*>(b.data()) + offset; @@ -677,7 +626,7 @@ inline const_buffer operator+(const const_buffer& b, * @relates const_buffer */ inline const_buffer operator+(std::size_t n, - const const_buffer& b) ASIO_NOEXCEPT + const const_buffer& b) noexcept { return b + n; } @@ -876,6 +825,25 @@ private: * bufs2.push_back(asio::buffer(d2)); * bufs2.push_back(asio::buffer(d3)); * bytes_transferred = sock.send(bufs2); @endcode + * + * @par Buffer Literals + * + * The `_buf` literal suffix, defined in namespace + * <tt>asio::buffer_literals</tt>, may be used to create @c const_buffer + * objects from string, binary integer, and hexadecimal integer literals. + * For example: + * + * @code + * using namespace asio::buffer_literals; + * + * asio::const_buffer b1 = "hello"_buf; + * asio::const_buffer b2 = 0xdeadbeef_buf; + * asio::const_buffer b3 = 0x0123456789abcdef0123456789abcdef_buf; + * asio::const_buffer b4 = 0b1010101011001100_buf; @endcode + * + * Note that the memory associated with a buffer literal is valid for the + * lifetime of the program. This means that the buffer can be safely used with + * asynchronous operations. */ /*@{*/ @@ -891,8 +859,8 @@ private: /** * @returns <tt>mutable_buffer(b)</tt>. */ -inline ASIO_MUTABLE_BUFFER buffer( - const mutable_buffer& b) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + const mutable_buffer& b) noexcept { return ASIO_MUTABLE_BUFFER(b); } @@ -904,8 +872,9 @@ inline ASIO_MUTABLE_BUFFER buffer( * b.data(), * min(b.size(), max_size_in_bytes)); @endcode */ -inline ASIO_MUTABLE_BUFFER buffer(const mutable_buffer& b, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + const mutable_buffer& b, + std::size_t max_size_in_bytes) noexcept { return ASIO_MUTABLE_BUFFER( mutable_buffer(b.data(), @@ -921,8 +890,8 @@ inline ASIO_MUTABLE_BUFFER buffer(const mutable_buffer& b, /** * @returns <tt>const_buffer(b)</tt>. */ -inline ASIO_CONST_BUFFER buffer( - const const_buffer& b) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const const_buffer& b) noexcept { return ASIO_CONST_BUFFER(b); } @@ -934,8 +903,9 @@ inline ASIO_CONST_BUFFER buffer( * b.data(), * min(b.size(), max_size_in_bytes)); @endcode */ -inline ASIO_CONST_BUFFER buffer(const const_buffer& b, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const const_buffer& b, + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(b.data(), b.size() < max_size_in_bytes @@ -950,8 +920,8 @@ inline ASIO_CONST_BUFFER buffer(const const_buffer& b, /** * @returns <tt>mutable_buffer(data, size_in_bytes)</tt>. */ -inline ASIO_MUTABLE_BUFFER buffer(void* data, - std::size_t size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + void* data, std::size_t size_in_bytes) noexcept { return ASIO_MUTABLE_BUFFER(data, size_in_bytes); } @@ -960,8 +930,8 @@ inline ASIO_MUTABLE_BUFFER buffer(void* data, /** * @returns <tt>const_buffer(data, size_in_bytes)</tt>. */ -inline ASIO_CONST_BUFFER buffer(const void* data, - std::size_t size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const void* data, std::size_t size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data, size_in_bytes); } @@ -974,7 +944,8 @@ inline ASIO_CONST_BUFFER buffer(const void* data, * N * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N]) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + PodType (&data)[N]) noexcept { return ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType)); } @@ -987,8 +958,9 @@ inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N]) ASIO_NOEXCEPT * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N], - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + PodType (&data)[N], + std::size_t max_size_in_bytes) noexcept { return ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType) < max_size_in_bytes @@ -1003,8 +975,8 @@ inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N], * N * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer( - const PodType (&data)[N]) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const PodType (&data)[N]) noexcept { return ASIO_CONST_BUFFER(data, N * sizeof(PodType)); } @@ -1017,84 +989,15 @@ inline ASIO_CONST_BUFFER buffer( * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer(const PodType (&data)[N], - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const PodType (&data)[N], + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data, N * sizeof(PodType) < max_size_in_bytes ? N * sizeof(PodType) : max_size_in_bytes); } -#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) - -// Borland C++ and Sun Studio think the overloads: -// -// unspecified buffer(boost::array<PodType, N>& array ...); -// -// and -// -// unspecified buffer(boost::array<const PodType, N>& array ...); -// -// are ambiguous. This will be worked around by using a buffer_types traits -// class that contains typedefs for the appropriate buffer and container -// classes, based on whether PodType is const or non-const. - -namespace detail { - -template <bool IsConst> -struct buffer_types_base; - -template <> -struct buffer_types_base<false> -{ - typedef mutable_buffer buffer_type; - typedef ASIO_MUTABLE_BUFFER container_type; -}; - -template <> -struct buffer_types_base<true> -{ - typedef const_buffer buffer_type; - typedef ASIO_CONST_BUFFER container_type; -}; - -template <typename PodType> -struct buffer_types - : public buffer_types_base<is_const<PodType>::value> -{ -}; - -} // namespace detail - -template <typename PodType, std::size_t N> -inline typename detail::buffer_types<PodType>::container_type -buffer(boost::array<PodType, N>& data) ASIO_NOEXCEPT -{ - typedef typename asio::detail::buffer_types<PodType>::buffer_type - buffer_type; - typedef typename asio::detail::buffer_types<PodType>::container_type - container_type; - return container_type( - buffer_type(data.c_array(), data.size() * sizeof(PodType))); -} - -template <typename PodType, std::size_t N> -inline typename detail::buffer_types<PodType>::container_type -buffer(boost::array<PodType, N>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT -{ - typedef typename asio::detail::buffer_types<PodType>::buffer_type - buffer_type; - typedef typename asio::detail::buffer_types<PodType>::container_type - container_type; - return container_type( - buffer_type(data.c_array(), - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes)); -} - -#else // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) - /// Create a new modifiable buffer that represents the given POD array. /** * @returns A mutable_buffer value equivalent to: @@ -1103,8 +1006,8 @@ buffer(boost::array<PodType, N>& data, * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_MUTABLE_BUFFER buffer( - boost::array<PodType, N>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + boost::array<PodType, N>& data) noexcept { return ASIO_MUTABLE_BUFFER( data.c_array(), data.size() * sizeof(PodType)); @@ -1118,8 +1021,9 @@ inline ASIO_MUTABLE_BUFFER buffer( * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_MUTABLE_BUFFER buffer(boost::array<PodType, N>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + boost::array<PodType, N>& data, + std::size_t max_size_in_bytes) noexcept { return ASIO_MUTABLE_BUFFER(data.c_array(), data.size() * sizeof(PodType) < max_size_in_bytes @@ -1134,8 +1038,8 @@ inline ASIO_MUTABLE_BUFFER buffer(boost::array<PodType, N>& data, * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer( - boost::array<const PodType, N>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + boost::array<const PodType, N>& data) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } @@ -1148,16 +1052,15 @@ inline ASIO_CONST_BUFFER buffer( * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer(boost::array<const PodType, N>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + boost::array<const PodType, N>& data, + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes); } -#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) - /// Create a new non-modifiable buffer that represents the given POD array. /** * @returns A const_buffer value equivalent to: @@ -1166,8 +1069,8 @@ inline ASIO_CONST_BUFFER buffer(boost::array<const PodType, N>& data, * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer( - const boost::array<PodType, N>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const boost::array<PodType, N>& data) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } @@ -1180,16 +1083,15 @@ inline ASIO_CONST_BUFFER buffer( * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer(const boost::array<PodType, N>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const boost::array<PodType, N>& data, + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes); } -#if defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) - /// Create a new modifiable buffer that represents the given POD array. /** * @returns A mutable_buffer value equivalent to: @@ -1198,8 +1100,8 @@ inline ASIO_CONST_BUFFER buffer(const boost::array<PodType, N>& data, * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_MUTABLE_BUFFER buffer( - std::array<PodType, N>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + std::array<PodType, N>& data) noexcept { return ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType)); } @@ -1212,8 +1114,9 @@ inline ASIO_MUTABLE_BUFFER buffer( * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_MUTABLE_BUFFER buffer(std::array<PodType, N>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + std::array<PodType, N>& data, + std::size_t max_size_in_bytes) noexcept { return ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType) < max_size_in_bytes @@ -1228,8 +1131,8 @@ inline ASIO_MUTABLE_BUFFER buffer(std::array<PodType, N>& data, * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer( - std::array<const PodType, N>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + std::array<const PodType, N>& data) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } @@ -1242,8 +1145,9 @@ inline ASIO_CONST_BUFFER buffer( * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer(std::array<const PodType, N>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + std::array<const PodType, N>& data, + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType) < max_size_in_bytes @@ -1258,8 +1162,8 @@ inline ASIO_CONST_BUFFER buffer(std::array<const PodType, N>& data, * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer( - const std::array<PodType, N>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const std::array<PodType, N>& data) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } @@ -1272,16 +1176,15 @@ inline ASIO_CONST_BUFFER buffer( * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline ASIO_CONST_BUFFER buffer(const std::array<PodType, N>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const std::array<PodType, N>& data, + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes); } -#endif // defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) - /// Create a new modifiable buffer that represents the given POD vector. /** * @returns A mutable_buffer value equivalent to: @@ -1293,8 +1196,8 @@ inline ASIO_CONST_BUFFER buffer(const std::array<PodType, N>& data, * invalidate iterators. */ template <typename PodType, typename Allocator> -inline ASIO_MUTABLE_BUFFER buffer( - std::vector<PodType, Allocator>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + std::vector<PodType, Allocator>& data) noexcept { return ASIO_MUTABLE_BUFFER( data.size() ? &data[0] : 0, data.size() * sizeof(PodType) @@ -1317,8 +1220,9 @@ inline ASIO_MUTABLE_BUFFER buffer( * invalidate iterators. */ template <typename PodType, typename Allocator> -inline ASIO_MUTABLE_BUFFER buffer(std::vector<PodType, Allocator>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + std::vector<PodType, Allocator>& data, + std::size_t max_size_in_bytes) noexcept { return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) < max_size_in_bytes @@ -1342,8 +1246,8 @@ inline ASIO_MUTABLE_BUFFER buffer(std::vector<PodType, Allocator>& data, * invalidate iterators. */ template <typename PodType, typename Allocator> -inline ASIO_CONST_BUFFER buffer( - const std::vector<PodType, Allocator>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const std::vector<PodType, Allocator>& data) noexcept { return ASIO_CONST_BUFFER( data.size() ? &data[0] : 0, data.size() * sizeof(PodType) @@ -1366,9 +1270,9 @@ inline ASIO_CONST_BUFFER buffer( * invalidate iterators. */ template <typename PodType, typename Allocator> -inline ASIO_CONST_BUFFER buffer( +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( const std::vector<PodType, Allocator>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) < max_size_in_bytes @@ -1390,8 +1294,8 @@ inline ASIO_CONST_BUFFER buffer( * given string object. */ template <typename Elem, typename Traits, typename Allocator> -inline ASIO_MUTABLE_BUFFER buffer( - std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + std::basic_string<Elem, Traits, Allocator>& data) noexcept { return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, data.size() * sizeof(Elem) @@ -1403,7 +1307,7 @@ inline ASIO_MUTABLE_BUFFER buffer( ); } -/// Create a new non-modifiable buffer that represents the given string. +/// Create a new modifiable buffer that represents the given string. /** * @returns A mutable_buffer value equivalent to: * @code mutable_buffer( @@ -1414,9 +1318,9 @@ inline ASIO_MUTABLE_BUFFER buffer( * given string object. */ template <typename Elem, typename Traits, typename Allocator> -inline ASIO_MUTABLE_BUFFER buffer( +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( std::basic_string<Elem, Traits, Allocator>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT + std::size_t max_size_in_bytes) noexcept { return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, data.size() * sizeof(Elem) < max_size_in_bytes @@ -1437,8 +1341,8 @@ inline ASIO_MUTABLE_BUFFER buffer( * given string object. */ template <typename Elem, typename Traits, typename Allocator> -inline ASIO_CONST_BUFFER buffer( - const std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const std::basic_string<Elem, Traits, Allocator>& data) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) @@ -1460,9 +1364,9 @@ inline ASIO_CONST_BUFFER buffer( * given string object. */ template <typename Elem, typename Traits, typename Allocator> -inline ASIO_CONST_BUFFER buffer( +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( const std::basic_string<Elem, Traits, Allocator>& data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem) < max_size_in_bytes @@ -1475,17 +1379,17 @@ inline ASIO_CONST_BUFFER buffer( ); } -#if defined(ASIO_HAS_STD_STRING_VIEW) \ +#if defined(ASIO_HAS_STRING_VIEW) \ || defined(GENERATING_DOCUMENTATION) -/// Create a new modifiable buffer that represents the given string_view. +/// Create a new non-modifiable buffer that represents the given string_view. /** * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0, * data.size() * sizeof(Elem))</tt>. */ template <typename Elem, typename Traits> -inline ASIO_CONST_BUFFER buffer( - basic_string_view<Elem, Traits> data) ASIO_NOEXCEPT +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + basic_string_view<Elem, Traits> data) noexcept { return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, data.size() * sizeof(Elem) @@ -1505,9 +1409,9 @@ inline ASIO_CONST_BUFFER buffer( * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode */ template <typename Elem, typename Traits> -inline ASIO_CONST_BUFFER buffer( +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( basic_string_view<Elem, Traits> data, - std::size_t max_size_in_bytes) ASIO_NOEXCEPT + std::size_t max_size_in_bytes) noexcept { return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, data.size() * sizeof(Elem) < max_size_in_bytes @@ -1520,9 +1424,218 @@ inline ASIO_CONST_BUFFER buffer( ); } -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) // || defined(GENERATING_DOCUMENTATION) +/// Create a new modifiable buffer from a contiguous container. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(typename T::value_type)); @endcode + */ +template <typename T> +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + T& data, + constraint_t< + is_contiguous_iterator<typename T::iterator>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, const_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, mutable_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_const< + remove_reference_t< + typename std::iterator_traits<typename T::iterator>::reference + > + >::value, + defaulted_constraint + > = defaulted_constraint()) noexcept +{ + return ASIO_MUTABLE_BUFFER( + data.size() ? detail::to_address(data.begin()) : 0, + data.size() * sizeof(typename T::value_type)); +} + +/// Create a new modifiable buffer from a contiguous container. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min( + * data.size() * sizeof(typename T::value_type), + * max_size_in_bytes)); @endcode + */ +template <typename T> +ASIO_NODISCARD inline ASIO_MUTABLE_BUFFER buffer( + T& data, std::size_t max_size_in_bytes, + constraint_t< + is_contiguous_iterator<typename T::iterator>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, const_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, mutable_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_const< + remove_reference_t< + typename std::iterator_traits<typename T::iterator>::reference + > + >::value, + defaulted_constraint + > = defaulted_constraint()) noexcept +{ + return ASIO_MUTABLE_BUFFER( + data.size() ? detail::to_address(data.begin()) : 0, + data.size() * sizeof(typename T::value_type) < max_size_in_bytes + ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer from a contiguous container. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(typename T::value_type)); @endcode + */ +template <typename T> +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + T& data, + constraint_t< + is_contiguous_iterator<typename T::iterator>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, const_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, mutable_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + is_const< + remove_reference_t< + typename std::iterator_traits<typename T::iterator>::reference + > + >::value, + defaulted_constraint + > = defaulted_constraint()) noexcept +{ + return ASIO_CONST_BUFFER( + data.size() ? detail::to_address(data.begin()) : 0, + data.size() * sizeof(typename T::value_type)); +} + +/// Create a new non-modifiable buffer from a contiguous container. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * min( + * data.size() * sizeof(typename T::value_type), + * max_size_in_bytes)); @endcode + */ +template <typename T> +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + T& data, std::size_t max_size_in_bytes, + constraint_t< + is_contiguous_iterator<typename T::iterator>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, const_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, mutable_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + is_const< + remove_reference_t< + typename std::iterator_traits<typename T::iterator>::reference + > + >::value, + defaulted_constraint + > = defaulted_constraint()) noexcept +{ + return ASIO_CONST_BUFFER( + data.size() ? detail::to_address(data.begin()) : 0, + data.size() * sizeof(typename T::value_type) < max_size_in_bytes + ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer from a contiguous container. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(typename T::value_type)); @endcode + */ +template <typename T> +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const T& data, + constraint_t< + is_contiguous_iterator<typename T::const_iterator>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, const_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, mutable_buffer>::value, + defaulted_constraint + > = defaulted_constraint()) noexcept +{ + return ASIO_CONST_BUFFER( + data.size() ? detail::to_address(data.begin()) : 0, + data.size() * sizeof(typename T::value_type)); +} + +/// Create a new non-modifiable buffer from a contiguous container. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * min( + * data.size() * sizeof(typename T::value_type), + * max_size_in_bytes)); @endcode + */ +template <typename T> +ASIO_NODISCARD inline ASIO_CONST_BUFFER buffer( + const T& data, std::size_t max_size_in_bytes, + constraint_t< + is_contiguous_iterator<typename T::const_iterator>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, const_buffer>::value, + defaulted_constraint + > = defaulted_constraint(), + constraint_t< + !is_convertible<T, mutable_buffer>::value, + defaulted_constraint + > = defaulted_constraint()) noexcept +{ + return ASIO_CONST_BUFFER( + data.size() ? detail::to_address(data.begin()) : 0, + data.size() * sizeof(typename T::value_type) < max_size_in_bytes + ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes); +} + /*@}*/ /// Adapt a basic_string to the DynamicBuffer requirements. @@ -1533,84 +1646,153 @@ template <typename Elem, typename Traits, typename Allocator> class dynamic_string_buffer { public: - /// The type used to represent the input sequence as a list of buffers. + /// The type used to represent a sequence of constant buffers that refers to + /// the underlying memory. typedef ASIO_CONST_BUFFER const_buffers_type; - /// The type used to represent the output sequence as a list of buffers. + /// The type used to represent a sequence of mutable buffers that refers to + /// the underlying memory. typedef ASIO_MUTABLE_BUFFER mutable_buffers_type; /// Construct a dynamic buffer from a string. /** * @param s The string to be used as backing storage for the dynamic buffer. - * Any existing data in the string is treated as the dynamic buffer's input - * sequence. The object stores a reference to the string and the user is - * responsible for ensuring that the string object remains valid until the - * dynamic_string_buffer object is destroyed. + * The object stores a reference to the string and the user is responsible + * for ensuring that the string object remains valid while the + * dynamic_string_buffer object, and copies of the object, are in use. + * + * @b DynamicBuffer_v1: Any existing data in the string is treated as the + * dynamic buffer's input sequence. * * @param maximum_size Specifies a maximum size for the buffer, in bytes. */ explicit dynamic_string_buffer(std::basic_string<Elem, Traits, Allocator>& s, std::size_t maximum_size = - (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT + (std::numeric_limits<std::size_t>::max)()) noexcept : string_(s), - size_(string_.size()), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_((std::numeric_limits<std::size_t>::max)()), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) max_size_(maximum_size) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// @b DynamicBuffer_v2: Copy construct a dynamic buffer. + dynamic_string_buffer(const dynamic_string_buffer& other) noexcept + : string_(other.string_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } + /// Move construct a dynamic buffer. - dynamic_string_buffer(dynamic_string_buffer&& other) ASIO_NOEXCEPT + dynamic_string_buffer(dynamic_string_buffer&& other) noexcept : string_(other.string_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) max_size_(other.max_size_) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Get the size of the input sequence. - std::size_t size() const ASIO_NOEXCEPT + /// @b DynamicBuffer_v1: Get the size of the input sequence. + /// @b DynamicBuffer_v2: Get the current size of the underlying memory. + /** + * @returns @b DynamicBuffer_v1 The current size of the input sequence. + * @b DynamicBuffer_v2: The current size of the underlying string if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t size() const noexcept { - return size_; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits<std::size_t>::max)()) + return size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + return (std::min)(string_.size(), max_size()); } /// Get the maximum size of the dynamic buffer. /** - * @returns The allowed maximum of the sum of the sizes of the input sequence - * and output sequence. + * @returns The allowed maximum size of the underlying memory. */ - std::size_t max_size() const ASIO_NOEXCEPT + std::size_t max_size() const noexcept { return max_size_; } - /// Get the current capacity of the dynamic buffer. + /// Get the maximum size that the buffer may grow to without triggering + /// reallocation. /** - * @returns The current total capacity of the buffer, i.e. for both the input - * sequence and output sequence. + * @returns The current capacity of the underlying string if less than + * max_size(). Otherwise returns max_size(). */ - std::size_t capacity() const ASIO_NOEXCEPT + std::size_t capacity() const noexcept { - return string_.capacity(); + return (std::min)(string_.capacity(), max_size()); } - /// Get a list of buffers that represents the input sequence. +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the input + /// sequence. /** * @returns An object of type @c const_buffers_type that satisfies * ConstBufferSequence requirements, representing the basic_string memory in - * input sequence. + * the input sequence. * * @note The returned object is invalidated by any @c dynamic_string_buffer - * or @c basic_string member function that modifies the input sequence or - * output sequence. + * or @c basic_string member function that resizes or erases the string. */ - const_buffers_type data() const ASIO_NOEXCEPT + const_buffers_type data() const noexcept { return const_buffers_type(asio::buffer(string_, size_)); } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing the basic_string memory. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + mutable_buffers_type data(std::size_t pos, std::size_t n) noexcept + { + return mutable_buffers_type(asio::buffer( + asio::buffer(string_, max_size_) + pos, n)); + } - /// Get a list of buffers that represents the output sequence, with the given - /// size. + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + const_buffers_type data(std::size_t pos, + std::size_t n) const noexcept + { + return const_buffers_type(asio::buffer( + asio::buffer(string_, max_size_) + pos, n)); + } + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the output + /// sequence, with the given size. /** * Ensures that the output sequence can accommodate @c n bytes, resizing the * basic_string object as necessary. @@ -1627,18 +1809,22 @@ public: */ mutable_buffers_type prepare(std::size_t n) { - if (size () > max_size() || max_size() - size() < n) + if (size() > max_size() || max_size() - size() < n) { std::length_error ex("dynamic_string_buffer too long"); asio::detail::throw_exception(ex); } + if (size_ == (std::numeric_limits<std::size_t>::max)()) + size_ = string_.size(); // Enable v1 behaviour. + string_.resize(size_ + n); return asio::buffer(asio::buffer(string_) + size_, n); } - /// Move bytes from the output sequence to the input sequence. + /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input + /// sequence. /** * @param n The number of bytes to append from the start of the output * sequence to the end of the input sequence. The remainder of the output @@ -1655,24 +1841,69 @@ public: size_ += (std::min)(n, string_.size() - size_); string_.resize(size_); } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) - /// Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of + /// bytes. /** - * Removes @c n characters from the beginning of the input sequence. + * Resizes the string to accommodate an additional @c n bytes at the end. * - * @note If @c n is greater than the size of the input sequence, the entire - * input sequence is consumed and no error is issued. + * @throws std::length_error If <tt>size() + n > max_size()</tt>. + */ + void grow(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_string_buffer too long"); + asio::detail::throw_exception(ex); + } + + string_.resize(size() + n); + } + + /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number + /// of bytes. + /** + * Erases @c n bytes from the end of the string by resizing the basic_string + * object. If @c n is greater than the current size of the string, the string + * is emptied. + */ + void shrink(std::size_t n) + { + string_.resize(n > size() ? 0 : size() - n); + } + + /// @b DynamicBuffer_v1: Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Consume the specified number of bytes from the + /// beginning of the underlying memory. + /** + * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the + * input sequence. @note If @c n is greater than the size of the input + * sequence, the entire input sequence is consumed and no error is issued. + * + * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the string. + * If @c n is greater than the current size of the string, the string is + * emptied. */ void consume(std::size_t n) { - std::size_t consume_length = (std::min)(n, size_); - string_.erase(0, consume_length); - size_ -= consume_length; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits<std::size_t>::max)()) + { + std::size_t consume_length = (std::min)(n, size_); + string_.erase(0, consume_length); + size_ -= consume_length; + return; + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + string_.erase(0, n); } private: std::basic_string<Elem, Traits, Allocator>& string_; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) std::size_t size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) const std::size_t max_size_; }; @@ -1684,97 +1915,168 @@ template <typename Elem, typename Allocator> class dynamic_vector_buffer { public: - /// The type used to represent the input sequence as a list of buffers. + /// The type used to represent a sequence of constant buffers that refers to + /// the underlying memory. typedef ASIO_CONST_BUFFER const_buffers_type; - /// The type used to represent the output sequence as a list of buffers. + /// The type used to represent a sequence of mutable buffers that refers to + /// the underlying memory. typedef ASIO_MUTABLE_BUFFER mutable_buffers_type; - /// Construct a dynamic buffer from a string. + /// Construct a dynamic buffer from a vector. /** * @param v The vector to be used as backing storage for the dynamic buffer. - * Any existing data in the vector is treated as the dynamic buffer's input - * sequence. The object stores a reference to the vector and the user is - * responsible for ensuring that the vector object remains valid until the - * dynamic_vector_buffer object is destroyed. + * The object stores a reference to the vector and the user is responsible + * for ensuring that the vector object remains valid while the + * dynamic_vector_buffer object, and copies of the object, are in use. * * @param maximum_size Specifies a maximum size for the buffer, in bytes. */ explicit dynamic_vector_buffer(std::vector<Elem, Allocator>& v, std::size_t maximum_size = - (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT + (std::numeric_limits<std::size_t>::max)()) noexcept : vector_(v), - size_(vector_.size()), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_((std::numeric_limits<std::size_t>::max)()), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) max_size_(maximum_size) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// @b DynamicBuffer_v2: Copy construct a dynamic buffer. + dynamic_vector_buffer(const dynamic_vector_buffer& other) noexcept + : vector_(other.vector_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } + /// Move construct a dynamic buffer. - dynamic_vector_buffer(dynamic_vector_buffer&& other) ASIO_NOEXCEPT + dynamic_vector_buffer(dynamic_vector_buffer&& other) noexcept : vector_(other.vector_), +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) size_(other.size_), +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) max_size_(other.max_size_) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Get the size of the input sequence. - std::size_t size() const ASIO_NOEXCEPT + /// @b DynamicBuffer_v1: Get the size of the input sequence. + /// @b DynamicBuffer_v2: Get the current size of the underlying memory. + /** + * @returns @b DynamicBuffer_v1 The current size of the input sequence. + * @b DynamicBuffer_v2: The current size of the underlying vector if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t size() const noexcept { - return size_; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits<std::size_t>::max)()) + return size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + return (std::min)(vector_.size(), max_size()); } /// Get the maximum size of the dynamic buffer. /** - * @returns The allowed maximum of the sum of the sizes of the input sequence - * and output sequence. + * @returns @b DynamicBuffer_v1: The allowed maximum of the sum of the sizes + * of the input sequence and output sequence. @b DynamicBuffer_v2: The allowed + * maximum size of the underlying memory. */ - std::size_t max_size() const ASIO_NOEXCEPT + std::size_t max_size() const noexcept { return max_size_; } - /// Get the current capacity of the dynamic buffer. + /// Get the maximum size that the buffer may grow to without triggering + /// reallocation. /** - * @returns The current total capacity of the buffer, i.e. for both the input - * sequence and output sequence. + * @returns @b DynamicBuffer_v1: The current total capacity of the buffer, + * i.e. for both the input sequence and output sequence. @b DynamicBuffer_v2: + * The current capacity of the underlying vector if less than max_size(). + * Otherwise returns max_size(). */ - std::size_t capacity() const ASIO_NOEXCEPT + std::size_t capacity() const noexcept { - return vector_.capacity(); + return (std::min)(vector_.capacity(), max_size()); } - /// Get a list of buffers that represents the input sequence. +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the input + /// sequence. /** * @returns An object of type @c const_buffers_type that satisfies - * ConstBufferSequence requirements, representing the basic_string memory in + * ConstBufferSequence requirements, representing the vector memory in the * input sequence. * * @note The returned object is invalidated by any @c dynamic_vector_buffer - * or @c basic_string member function that modifies the input sequence or - * output sequence. + * or @c vector member function that modifies the input sequence or output + * sequence. */ - const_buffers_type data() const ASIO_NOEXCEPT + const_buffers_type data() const noexcept { return const_buffers_type(asio::buffer(vector_, size_)); } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) - /// Get a list of buffers that represents the output sequence, with the given - /// size. + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing the vector memory. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that resizes or erases the vector. + */ + mutable_buffers_type data(std::size_t pos, std::size_t n) noexcept + { + return mutable_buffers_type(asio::buffer( + asio::buffer(vector_, max_size_) + pos, n)); + } + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that resizes or erases the vector. + */ + const_buffers_type data(std::size_t pos, + std::size_t n) const noexcept + { + return const_buffers_type(asio::buffer( + asio::buffer(vector_, max_size_) + pos, n)); + } + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the output + /// sequence, with the given size. /** * Ensures that the output sequence can accommodate @c n bytes, resizing the - * basic_string object as necessary. + * vector object as necessary. * * @returns An object of type @c mutable_buffers_type that satisfies - * MutableBufferSequence requirements, representing basic_string memory - * at the start of the output sequence of size @c n. + * MutableBufferSequence requirements, representing vector memory at the + * start of the output sequence of size @c n. * * @throws std::length_error If <tt>size() + n > max_size()</tt>. * * @note The returned object is invalidated by any @c dynamic_vector_buffer - * or @c basic_string member function that modifies the input sequence or - * output sequence. + * or @c vector member function that modifies the input sequence or output + * sequence. */ mutable_buffers_type prepare(std::size_t n) { @@ -1784,12 +2086,16 @@ public: asio::detail::throw_exception(ex); } + if (size_ == (std::numeric_limits<std::size_t>::max)()) + size_ = vector_.size(); // Enable v1 behaviour. + vector_.resize(size_ + n); return asio::buffer(asio::buffer(vector_) + size_, n); } - /// Move bytes from the output sequence to the input sequence. + /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input + /// sequence. /** * @param n The number of bytes to append from the start of the output * sequence to the end of the input sequence. The remainder of the output @@ -1806,24 +2112,69 @@ public: size_ += (std::min)(n, vector_.size() - size_); vector_.resize(size_); } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of + /// bytes. + /** + * Resizes the vector to accommodate an additional @c n bytes at the end. + * + * @throws std::length_error If <tt>size() + n > max_size()</tt>. + */ + void grow(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_vector_buffer too long"); + asio::detail::throw_exception(ex); + } + + vector_.resize(size() + n); + } - /// Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number + /// of bytes. /** - * Removes @c n characters from the beginning of the input sequence. + * Erases @c n bytes from the end of the vector by resizing the vector + * object. If @c n is greater than the current size of the vector, the vector + * is emptied. + */ + void shrink(std::size_t n) + { + vector_.resize(n > size() ? 0 : size() - n); + } + + /// @b DynamicBuffer_v1: Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Consume the specified number of bytes from the + /// beginning of the underlying memory. + /** + * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the + * input sequence. @note If @c n is greater than the size of the input + * sequence, the entire input sequence is consumed and no error is issued. * - * @note If @c n is greater than the size of the input sequence, the entire - * input sequence is consumed and no error is issued. + * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the vector. + * If @c n is greater than the current size of the vector, the vector is + * emptied. */ void consume(std::size_t n) { - std::size_t consume_length = (std::min)(n, size_); - vector_.erase(vector_.begin(), vector_.begin() + consume_length); - size_ -= consume_length; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits<std::size_t>::max)()) + { + std::size_t consume_length = (std::min)(n, size_); + vector_.erase(vector_.begin(), vector_.begin() + consume_length); + size_ -= consume_length; + return; + } +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + vector_.erase(vector_.begin(), vector_.begin() + (std::min)(size(), n)); } private: std::vector<Elem, Allocator>& vector_; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) std::size_t size_; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) const std::size_t max_size_; }; @@ -1839,8 +2190,9 @@ private: * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>. */ template <typename Elem, typename Traits, typename Allocator> -inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( - std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline +dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( + std::basic_string<Elem, Traits, Allocator>& data) noexcept { return dynamic_string_buffer<Elem, Traits, Allocator>(data); } @@ -1851,9 +2203,10 @@ inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( * max_size)</tt>. */ template <typename Elem, typename Traits, typename Allocator> -inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( +ASIO_NODISCARD inline +dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( std::basic_string<Elem, Traits, Allocator>& data, - std::size_t max_size) ASIO_NOEXCEPT + std::size_t max_size) noexcept { return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size); } @@ -1863,8 +2216,9 @@ inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>. */ template <typename Elem, typename Allocator> -inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( - std::vector<Elem, Allocator>& data) ASIO_NOEXCEPT +ASIO_NODISCARD inline +dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( + std::vector<Elem, Allocator>& data) noexcept { return dynamic_vector_buffer<Elem, Allocator>(data); } @@ -1874,9 +2228,10 @@ inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>. */ template <typename Elem, typename Allocator> -inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( +ASIO_NODISCARD inline +dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( std::vector<Elem, Allocator>& data, - std::size_t max_size) ASIO_NOEXCEPT + std::size_t max_size) noexcept { return dynamic_vector_buffer<Elem, Allocator>(data, max_size); } @@ -1920,14 +2275,15 @@ inline std::size_t buffer_copy_1(const mutable_buffer& target, std::size_t target_size = target.size(); std::size_t source_size = source.size(); std::size_t n = target_size < source_size ? target_size : source_size; - memcpy(target.data(), source.data(), n); + if (n > 0) + memcpy(target.data(), source.data(), n); return n; } template <typename TargetIterator, typename SourceIterator> inline std::size_t buffer_copy(one_buffer, one_buffer, TargetIterator target_begin, TargetIterator, - SourceIterator source_begin, SourceIterator) ASIO_NOEXCEPT + SourceIterator source_begin, SourceIterator) noexcept { return (buffer_copy_1)(*target_begin, *source_begin); } @@ -1936,7 +2292,7 @@ template <typename TargetIterator, typename SourceIterator> inline std::size_t buffer_copy(one_buffer, one_buffer, TargetIterator target_begin, TargetIterator, SourceIterator source_begin, SourceIterator, - std::size_t max_bytes_to_copy) ASIO_NOEXCEPT + std::size_t max_bytes_to_copy) noexcept { return (buffer_copy_1)(*target_begin, asio::buffer(*source_begin, max_bytes_to_copy)); @@ -1947,7 +2303,7 @@ std::size_t buffer_copy(one_buffer, multiple_buffers, TargetIterator target_begin, TargetIterator, SourceIterator source_begin, SourceIterator source_end, std::size_t max_bytes_to_copy - = (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT + = (std::numeric_limits<std::size_t>::max)()) noexcept { std::size_t total_bytes_copied = 0; SourceIterator source_iter = source_begin; @@ -1970,7 +2326,7 @@ std::size_t buffer_copy(multiple_buffers, one_buffer, TargetIterator target_begin, TargetIterator target_end, SourceIterator source_begin, SourceIterator, std::size_t max_bytes_to_copy - = (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT + = (std::numeric_limits<std::size_t>::max)()) noexcept { std::size_t total_bytes_copied = 0; TargetIterator target_iter = target_begin; @@ -1991,7 +2347,7 @@ std::size_t buffer_copy(multiple_buffers, one_buffer, template <typename TargetIterator, typename SourceIterator> std::size_t buffer_copy(multiple_buffers, multiple_buffers, TargetIterator target_begin, TargetIterator target_end, - SourceIterator source_begin, SourceIterator source_end) ASIO_NOEXCEPT + SourceIterator source_begin, SourceIterator source_end) noexcept { std::size_t total_bytes_copied = 0; @@ -2036,7 +2392,7 @@ template <typename TargetIterator, typename SourceIterator> std::size_t buffer_copy(multiple_buffers, multiple_buffers, TargetIterator target_begin, TargetIterator target_end, SourceIterator source_begin, SourceIterator source_end, - std::size_t max_bytes_to_copy) ASIO_NOEXCEPT + std::size_t max_bytes_to_copy) noexcept { std::size_t total_bytes_copied = 0; @@ -2103,7 +2459,7 @@ std::size_t buffer_copy(multiple_buffers, multiple_buffers, */ template <typename MutableBufferSequence, typename ConstBufferSequence> inline std::size_t buffer_copy(const MutableBufferSequence& target, - const ConstBufferSequence& source) ASIO_NOEXCEPT + const ConstBufferSequence& source) noexcept { return detail::buffer_copy( detail::buffer_sequence_cardinality<MutableBufferSequence>(), @@ -2141,7 +2497,7 @@ inline std::size_t buffer_copy(const MutableBufferSequence& target, template <typename MutableBufferSequence, typename ConstBufferSequence> inline std::size_t buffer_copy(const MutableBufferSequence& target, const ConstBufferSequence& source, - std::size_t max_bytes_to_copy) ASIO_NOEXCEPT + std::size_t max_bytes_to_copy) noexcept { return detail::buffer_copy( detail::buffer_sequence_cardinality<MutableBufferSequence>(), @@ -2157,5 +2513,239 @@ inline std::size_t buffer_copy(const MutableBufferSequence& target, } // namespace asio #include "asio/detail/pop_options.hpp" +#include "asio/detail/is_buffer_sequence.hpp" +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Trait to determine whether a type satisfies the MutableBufferSequence +/// requirements. +template <typename T> +struct is_mutable_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_buffer_sequence<T, mutable_buffer> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the ConstBufferSequence +/// requirements. +template <typename T> +struct is_const_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_buffer_sequence<T, const_buffer> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +/// Trait to determine whether a type satisfies the DynamicBuffer_v1 +/// requirements. +template <typename T> +struct is_dynamic_buffer_v1 +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_dynamic_buffer_v1<T> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Trait to determine whether a type satisfies the DynamicBuffer_v2 +/// requirements. +template <typename T> +struct is_dynamic_buffer_v2 +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : asio::detail::is_dynamic_buffer_v2<T> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the DynamicBuffer requirements. +/** + * If @c ASIO_NO_DYNAMIC_BUFFER_V1 is not defined, determines whether the + * type satisfies the DynamicBuffer_v1 requirements. Otherwise, if @c + * ASIO_NO_DYNAMIC_BUFFER_V1 is defined, determines whether the type + * satisfies the DynamicBuffer_v2 requirements. + */ +template <typename T> +struct is_dynamic_buffer +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#elif defined(ASIO_NO_DYNAMIC_BUFFER_V1) + : asio::is_dynamic_buffer_v2<T> +#else // defined(ASIO_NO_DYNAMIC_BUFFER_V1) + : asio::is_dynamic_buffer_v1<T> +#endif // defined(ASIO_NO_DYNAMIC_BUFFER_V1) +{ +}; + +namespace buffer_literals { +namespace detail { + +template <char... Chars> +struct chars {}; + +template <unsigned char... Bytes> +struct bytes {}; + +// Literal processor that converts binary literals to an array of bytes. + +template <typename Bytes, char... Chars> +struct bin_literal; + +template <unsigned char... Bytes> +struct bin_literal<bytes<Bytes...>> +{ + static const std::size_t size = sizeof...(Bytes); + static const unsigned char data[sizeof...(Bytes)]; +}; + +template <unsigned char... Bytes> +const unsigned char bin_literal<bytes<Bytes...>>::data[sizeof...(Bytes)] + = { Bytes... }; + +template <unsigned char... Bytes, char Bit7, char Bit6, char Bit5, + char Bit4, char Bit3, char Bit2, char Bit1, char Bit0, char... Chars> +struct bin_literal<bytes<Bytes...>, Bit7, Bit6, + Bit5, Bit4, Bit3, Bit2, Bit1, Bit0, Chars...> : + bin_literal< + bytes<Bytes..., + static_cast<unsigned char>( + (Bit7 == '1' ? 0x80 : 0) | + (Bit6 == '1' ? 0x40 : 0) | + (Bit5 == '1' ? 0x20 : 0) | + (Bit4 == '1' ? 0x10 : 0) | + (Bit3 == '1' ? 0x08 : 0) | + (Bit2 == '1' ? 0x04 : 0) | + (Bit1 == '1' ? 0x02 : 0) | + (Bit0 == '1' ? 0x01 : 0)) + >, Chars...> {}; + +template <unsigned char... Bytes, char... Chars> +struct bin_literal<bytes<Bytes...>, Chars...> +{ + static_assert(sizeof...(Chars) == 0, + "number of digits in a binary buffer literal must be a multiple of 8"); + + static const std::size_t size = 0; + static const unsigned char data[1]; +}; + +template <unsigned char... Bytes, char... Chars> +const unsigned char bin_literal<bytes<Bytes...>, Chars...>::data[1] = {}; + +// Literal processor that converts hexadecimal literals to an array of bytes. + +template <typename Bytes, char... Chars> +struct hex_literal; + +template <unsigned char... Bytes> +struct hex_literal<bytes<Bytes...>> +{ + static const std::size_t size = sizeof...(Bytes); + static const unsigned char data[sizeof...(Bytes)]; +}; + +template <unsigned char... Bytes> +const unsigned char hex_literal<bytes<Bytes...>>::data[sizeof...(Bytes)] + = { Bytes... }; + +template <unsigned char... Bytes, char Hi, char Lo, char... Chars> +struct hex_literal<bytes<Bytes...>, Hi, Lo, Chars...> : + hex_literal< + bytes<Bytes..., + static_cast<unsigned char>( + Lo >= 'A' && Lo <= 'F' ? Lo - 'A' + 10 : + (Lo >= 'a' && Lo <= 'f' ? Lo - 'a' + 10 : Lo - '0')) | + ((static_cast<unsigned char>( + Hi >= 'A' && Hi <= 'F' ? Hi - 'A' + 10 : + (Hi >= 'a' && Hi <= 'f' ? Hi - 'a' + 10 : Hi - '0'))) << 4) + >, Chars...> {}; + +template <unsigned char... Bytes, char Char> +struct hex_literal<bytes<Bytes...>, Char> +{ + static_assert(!Char, + "a hexadecimal buffer literal must have an even number of digits"); + + static const std::size_t size = 0; + static const unsigned char data[1]; +}; + +template <unsigned char... Bytes, char Char> +const unsigned char hex_literal<bytes<Bytes...>, Char>::data[1] = {}; + +// Helper template that removes digit separators and then passes the cleaned +// variadic pack of characters to the literal processor. + +template <template <typename, char...> class Literal, + typename Clean, char... Raw> +struct remove_separators; + +template <template <typename, char...> class Literal, + char... Clean, char... Raw> +struct remove_separators<Literal, chars<Clean...>, '\'', Raw...> : + remove_separators<Literal, chars<Clean...>, Raw...> {}; + +template <template <typename, char...> class Literal, + char... Clean, char C, char... Raw> +struct remove_separators<Literal, chars<Clean...>, C, Raw...> : + remove_separators<Literal, chars<Clean..., C>, Raw...> {}; + +template <template <typename, char...> class Literal, char... Clean> +struct remove_separators<Literal, chars<Clean...>> : + Literal<bytes<>, Clean...> {}; + +// Helper template to determine the literal type based on the prefix. + +template <char... Chars> +struct literal; + +template <char... Chars> +struct literal<'0', 'b', Chars...> : + remove_separators<bin_literal, chars<>, Chars...>{}; + +template <char... Chars> +struct literal<'0', 'B', Chars...> : + remove_separators<bin_literal, chars<>, Chars...>{}; + +template <char... Chars> +struct literal<'0', 'x', Chars...> : + remove_separators<hex_literal, chars<>, Chars...>{}; + +template <char... Chars> +struct literal<'0', 'X', Chars...> : + remove_separators<hex_literal, chars<>, Chars...>{}; + +} // namespace detail + +/// Literal operator for creating const_buffer objects from string literals. +inline ASIO_CONST_BUFFER operator ""_buf(const char* data, std::size_t n) +{ + return ASIO_CONST_BUFFER(data, n); +} + +/// Literal operator for creating const_buffer objects from unbounded binary or +/// hexadecimal integer literals. +template <char... Chars> +inline ASIO_CONST_BUFFER operator ""_buf() +{ + return ASIO_CONST_BUFFER( + +detail::literal<Chars...>::data, + detail::literal<Chars...>::size); +} + +} // namespace buffer_literals +} // namespace asio + +#include "asio/detail/pop_options.hpp" #endif // ASIO_BUFFER_HPP diff --git a/3rdparty/asio/include/asio/buffer_registration.hpp b/3rdparty/asio/include/asio/buffer_registration.hpp new file mode 100644 index 00000000000..39897ba2450 --- /dev/null +++ b/3rdparty/asio/include/asio/buffer_registration.hpp @@ -0,0 +1,318 @@ +// +// buffer_registration.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BUFFER_REGISTRATION_HPP +#define ASIO_BUFFER_REGISTRATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <iterator> +#include <utility> +#include <vector> +#include "asio/detail/memory.hpp" +#include "asio/execution/context.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/is_executor.hpp" +#include "asio/query.hpp" +#include "asio/registered_buffer.hpp" + +#if defined(ASIO_HAS_IO_URING) +# include "asio/detail/scheduler.hpp" +# include "asio/detail/io_uring_service.hpp" +#endif // defined(ASIO_HAS_IO_URING) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class buffer_registration_base +{ +protected: + static mutable_registered_buffer make_buffer(const mutable_buffer& b, + const void* scope, int index) noexcept + { + return mutable_registered_buffer(b, registered_buffer_id(scope, index)); + } +}; + +} // namespace detail + +/// Automatically registers and unregistered buffers with an execution context. +/** + * For portability, applications should assume that only one registration is + * permitted per execution context. + */ +template <typename MutableBufferSequence, + typename Allocator = std::allocator<void>> +class buffer_registration + : detail::buffer_registration_base +{ +public: + /// The allocator type used for allocating storage for the buffers container. + typedef Allocator allocator_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The type of an iterator over the registered buffers. + typedef unspecified iterator; + + /// The type of a const iterator over the registered buffers. + typedef unspecified const_iterator; +#else // defined(GENERATING_DOCUMENTATION) + typedef std::vector<mutable_registered_buffer>::const_iterator iterator; + typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator; +#endif // defined(GENERATING_DOCUMENTATION) + + /// Register buffers with an executor's execution context. + template <typename Executor> + buffer_registration(const Executor& ex, + const MutableBufferSequence& buffer_sequence, + const allocator_type& alloc = allocator_type(), + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) + : buffer_sequence_(buffer_sequence), + buffers_( + ASIO_REBIND_ALLOC(allocator_type, + mutable_registered_buffer)(alloc)) + { + init_buffers(buffer_registration::get_context(ex), + asio::buffer_sequence_begin(buffer_sequence_), + asio::buffer_sequence_end(buffer_sequence_)); + } + + /// Register buffers with an execution context. + template <typename ExecutionContext> + buffer_registration(ExecutionContext& ctx, + const MutableBufferSequence& buffer_sequence, + const allocator_type& alloc = allocator_type(), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : buffer_sequence_(buffer_sequence), + buffers_( + ASIO_REBIND_ALLOC(allocator_type, + mutable_registered_buffer)(alloc)) + { + init_buffers(ctx, + asio::buffer_sequence_begin(buffer_sequence_), + asio::buffer_sequence_end(buffer_sequence_)); + } + + /// Move constructor. + buffer_registration(buffer_registration&& other) noexcept + : buffer_sequence_(std::move(other.buffer_sequence_)), + buffers_(std::move(other.buffers_)) + { +#if defined(ASIO_HAS_IO_URING) + service_ = other.service_; + other.service_ = 0; +#endif // defined(ASIO_HAS_IO_URING) + } + + /// Unregisters the buffers. + ~buffer_registration() + { +#if defined(ASIO_HAS_IO_URING) + if (service_) + service_->unregister_buffers(); +#endif // defined(ASIO_HAS_IO_URING) + } + + /// Move assignment. + buffer_registration& operator=(buffer_registration&& other) noexcept + { + if (this != &other) + { + buffer_sequence_ = std::move(other.buffer_sequence_); + buffers_ = std::move(other.buffers_); +#if defined(ASIO_HAS_IO_URING) + if (service_) + service_->unregister_buffers(); + service_ = other.service_; + other.service_ = 0; +#endif // defined(ASIO_HAS_IO_URING) + } + return *this; + } + + /// Get the number of registered buffers. + std::size_t size() const noexcept + { + return buffers_.size(); + } + + /// Get the begin iterator for the sequence of registered buffers. + const_iterator begin() const noexcept + { + return buffers_.begin(); + } + + /// Get the begin iterator for the sequence of registered buffers. + const_iterator cbegin() const noexcept + { + return buffers_.cbegin(); + } + + /// Get the end iterator for the sequence of registered buffers. + const_iterator end() const noexcept + { + return buffers_.end(); + } + + /// Get the end iterator for the sequence of registered buffers. + const_iterator cend() const noexcept + { + return buffers_.cend(); + } + + /// Get the buffer at the specified index. + const mutable_registered_buffer& operator[](std::size_t i) noexcept + { + return buffers_[i]; + } + + /// Get the buffer at the specified index. + const mutable_registered_buffer& at(std::size_t i) noexcept + { + return buffers_.at(i); + } + +private: + // Disallow copying and assignment. + buffer_registration(const buffer_registration&) = delete; + buffer_registration& operator=(const buffer_registration&) = delete; + + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<execution::is_executor<T>::value>* = 0) + { + return asio::query(t, execution::context); + } + + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<!execution::is_executor<T>::value>* = 0) + { + return t.context(); + } + + // Helper function to initialise the container of buffers. + template <typename Iterator> + void init_buffers(execution_context& ctx, Iterator begin, Iterator end) + { + std::size_t n = std::distance(begin, end); + buffers_.resize(n); + +#if defined(ASIO_HAS_IO_URING) + service_ = &use_service<detail::io_uring_service>(ctx); + std::vector<iovec, + ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n, + ASIO_REBIND_ALLOC(allocator_type, iovec)( + buffers_.get_allocator())); +#endif // defined(ASIO_HAS_IO_URING) + + Iterator iter = begin; + for (int index = 0; iter != end; ++index, ++iter) + { + mutable_buffer b(*iter); + std::size_t i = static_cast<std::size_t>(index); + buffers_[i] = this->make_buffer(b, &ctx, index); + +#if defined(ASIO_HAS_IO_URING) + iovecs[i].iov_base = buffers_[i].data(); + iovecs[i].iov_len = buffers_[i].size(); +#endif // defined(ASIO_HAS_IO_URING) + } + +#if defined(ASIO_HAS_IO_URING) + if (n > 0) + { + service_->register_buffers(&iovecs[0], + static_cast<unsigned>(iovecs.size())); + } +#endif // defined(ASIO_HAS_IO_URING) + } + + MutableBufferSequence buffer_sequence_; + std::vector<mutable_registered_buffer, + ASIO_REBIND_ALLOC(allocator_type, + mutable_registered_buffer)> buffers_; +#if defined(ASIO_HAS_IO_URING) + detail::io_uring_service* service_; +#endif // defined(ASIO_HAS_IO_URING) +}; + +/// Register buffers with an execution context. +template <typename Executor, typename MutableBufferSequence> +ASIO_NODISCARD inline +buffer_registration<MutableBufferSequence> +register_buffers(const Executor& ex, + const MutableBufferSequence& buffer_sequence, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) +{ + return buffer_registration<MutableBufferSequence>(ex, buffer_sequence); +} + +/// Register buffers with an execution context. +template <typename Executor, typename MutableBufferSequence, typename Allocator> +ASIO_NODISCARD inline +buffer_registration<MutableBufferSequence, Allocator> +register_buffers(const Executor& ex, + const MutableBufferSequence& buffer_sequence, const Allocator& alloc, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) +{ + return buffer_registration<MutableBufferSequence, Allocator>( + ex, buffer_sequence, alloc); +} + +/// Register buffers with an execution context. +template <typename ExecutionContext, typename MutableBufferSequence> +ASIO_NODISCARD inline +buffer_registration<MutableBufferSequence> +register_buffers(ExecutionContext& ctx, + const MutableBufferSequence& buffer_sequence, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) +{ + return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence); +} + +/// Register buffers with an execution context. +template <typename ExecutionContext, + typename MutableBufferSequence, typename Allocator> +ASIO_NODISCARD inline +buffer_registration<MutableBufferSequence, Allocator> +register_buffers(ExecutionContext& ctx, + const MutableBufferSequence& buffer_sequence, const Allocator& alloc, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) +{ + return buffer_registration<MutableBufferSequence, Allocator>( + ctx, buffer_sequence, alloc); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BUFFER_REGISTRATION_HPP diff --git a/3rdparty/asio/include/asio/buffered_read_stream.hpp b/3rdparty/asio/include/asio/buffered_read_stream.hpp index 908dd37101e..264f66c55d8 100644 --- a/3rdparty/asio/include/asio/buffered_read_stream.hpp +++ b/3rdparty/asio/include/asio/buffered_read_stream.hpp @@ -2,7 +2,7 @@ // buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -26,11 +26,16 @@ #include "asio/detail/noncopyable.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + +template <typename> class initiate_async_buffered_fill; +template <typename> class initiate_async_buffered_read_some; + +} // namespace detail /// Adds buffering to the read-related operations of a stream. /** @@ -50,7 +55,7 @@ class buffered_read_stream { public: /// The type of the next layer. - typedef typename remove_reference<Stream>::type next_layer_type; + typedef remove_reference_t<Stream> next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; @@ -67,16 +72,17 @@ public: /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> - explicit buffered_read_stream(Arg& a) - : next_layer_(a), + explicit buffered_read_stream(Arg&& a) + : next_layer_(static_cast<Arg&&>(a)), storage_(default_buffer_size) { } /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> - buffered_read_stream(Arg& a, std::size_t buffer_size) - : next_layer_(a), + buffered_read_stream(Arg&& a, + std::size_t buffer_size) + : next_layer_(static_cast<Arg&&>(a)), storage_(buffer_size) { } @@ -100,27 +106,11 @@ public: } /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + executor_type get_executor() noexcept { return next_layer_.lowest_layer().get_executor(); } -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_context() - { - return next_layer_.get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_service() - { - return next_layer_.get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - /// Close the stream. void close() { @@ -153,14 +143,21 @@ public: /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + declval<conditional_t<true, Stream&, WriteHandler>>().async_write_some( + buffers, static_cast<WriteHandler&&>(handler))) { return next_layer_.async_write_some(buffers, - ASIO_MOVE_CAST(WriteHandler)(handler)); + static_cast<WriteHandler&&>(handler)); } /// Fill the buffer with some data. Returns the number of bytes placed in the @@ -172,10 +169,20 @@ public: std::size_t fill(asio::error_code& ec); /// Start an asynchronous fill. - template <typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_fill(ASIO_MOVE_ARG(ReadHandler) handler); + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler = default_completion_token_t<executor_type>> + auto async_fill( + ReadHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_fill<Stream>>(), + handler, declval<detail::buffered_stream_storage*>())); /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. @@ -190,11 +197,20 @@ public: /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler); + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_read_some<Stream>>(), + handler, declval<detail::buffered_stream_storage*>(), buffers)); /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. diff --git a/3rdparty/asio/include/asio/buffered_read_stream_fwd.hpp b/3rdparty/asio/include/asio/buffered_read_stream_fwd.hpp index 3f1646afc03..d98aa70483a 100644 --- a/3rdparty/asio/include/asio/buffered_read_stream_fwd.hpp +++ b/3rdparty/asio/include/asio/buffered_read_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_read_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/buffered_stream.hpp b/3rdparty/asio/include/asio/buffered_stream.hpp index cabab60726f..e0e1b47b792 100644 --- a/3rdparty/asio/include/asio/buffered_stream.hpp +++ b/3rdparty/asio/include/asio/buffered_stream.hpp @@ -2,7 +2,7 @@ // buffered_stream.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,6 @@ #include "asio/buffered_stream_fwd.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" #include "asio/detail/push_options.hpp" @@ -47,7 +46,7 @@ class buffered_stream { public: /// The type of the next layer. - typedef typename remove_reference<Stream>::type next_layer_type; + typedef remove_reference_t<Stream> next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; @@ -57,17 +56,17 @@ public: /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> - explicit buffered_stream(Arg& a) - : inner_stream_impl_(a), + explicit buffered_stream(Arg&& a) + : inner_stream_impl_(static_cast<Arg&&>(a)), stream_impl_(inner_stream_impl_) { } /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> - explicit buffered_stream(Arg& a, std::size_t read_buffer_size, - std::size_t write_buffer_size) - : inner_stream_impl_(a, write_buffer_size), + explicit buffered_stream(Arg&& a, + std::size_t read_buffer_size, std::size_t write_buffer_size) + : inner_stream_impl_(static_cast<Arg&&>(a), write_buffer_size), stream_impl_(inner_stream_impl_, read_buffer_size) { } @@ -91,27 +90,11 @@ public: } /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + executor_type get_executor() noexcept { return stream_impl_.lowest_layer().get_executor(); } -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_context() - { - return stream_impl_.get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_service() - { - return stream_impl_.get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - /// Close the stream. void close() { @@ -142,13 +125,21 @@ public: } /// Start an asynchronous flush. - template <typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_flush(ASIO_MOVE_ARG(WriteHandler) handler) + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler = default_completion_token_t<executor_type>> + auto async_flush( + WriteHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + declval<buffered_write_stream<Stream>&>().async_flush( + static_cast<WriteHandler&&>(handler))) { return stream_impl_.next_layer().async_flush( - ASIO_MOVE_CAST(WriteHandler)(handler)); + static_cast<WriteHandler&&>(handler)); } /// Write the given data to the stream. Returns the number of bytes written. @@ -170,14 +161,21 @@ public: /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + declval<Stream&>().async_write_some(buffers, + static_cast<WriteHandler&&>(handler))) { return stream_impl_.async_write_some(buffers, - ASIO_MOVE_CAST(WriteHandler)(handler)); + static_cast<WriteHandler&&>(handler)); } /// Fill the buffer with some data. Returns the number of bytes placed in the @@ -195,12 +193,21 @@ public: } /// Start an asynchronous fill. - template <typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_fill(ASIO_MOVE_ARG(ReadHandler) handler) + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler = default_completion_token_t<executor_type>> + auto async_fill( + ReadHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + declval<buffered_read_stream< + buffered_write_stream<Stream>>&>().async_fill( + static_cast<ReadHandler&&>(handler))) { - return stream_impl_.async_fill(ASIO_MOVE_CAST(ReadHandler)(handler)); + return stream_impl_.async_fill(static_cast<ReadHandler&&>(handler)); } /// Read some data from the stream. Returns the number of bytes read. Throws @@ -222,14 +229,21 @@ public: /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + declval<Stream&>().async_read_some(buffers, + static_cast<ReadHandler&&>(handler))) { return stream_impl_.async_read_some(buffers, - ASIO_MOVE_CAST(ReadHandler)(handler)); + static_cast<ReadHandler&&>(handler)); } /// Peek at the incoming data on the stream. Returns the number of bytes read. diff --git a/3rdparty/asio/include/asio/buffered_stream_fwd.hpp b/3rdparty/asio/include/asio/buffered_stream_fwd.hpp index cc445d225cf..790c76269f9 100644 --- a/3rdparty/asio/include/asio/buffered_stream_fwd.hpp +++ b/3rdparty/asio/include/asio/buffered_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/buffered_write_stream.hpp b/3rdparty/asio/include/asio/buffered_write_stream.hpp index 9cdab8b1d25..f8f0538dcea 100644 --- a/3rdparty/asio/include/asio/buffered_write_stream.hpp +++ b/3rdparty/asio/include/asio/buffered_write_stream.hpp @@ -2,7 +2,7 @@ // buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -25,12 +25,17 @@ #include "asio/detail/noncopyable.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" #include "asio/write.hpp" #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + +template <typename> class initiate_async_buffered_flush; +template <typename> class initiate_async_buffered_write_some; + +} // namespace detail /// Adds buffering to the write-related operations of a stream. /** @@ -50,7 +55,7 @@ class buffered_write_stream { public: /// The type of the next layer. - typedef typename remove_reference<Stream>::type next_layer_type; + typedef remove_reference_t<Stream> next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; @@ -67,16 +72,17 @@ public: /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> - explicit buffered_write_stream(Arg& a) - : next_layer_(a), + explicit buffered_write_stream(Arg&& a) + : next_layer_(static_cast<Arg&&>(a)), storage_(default_buffer_size) { } /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> - buffered_write_stream(Arg& a, std::size_t buffer_size) - : next_layer_(a), + buffered_write_stream(Arg&& a, + std::size_t buffer_size) + : next_layer_(static_cast<Arg&&>(a)), storage_(buffer_size) { } @@ -100,27 +106,11 @@ public: } /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + executor_type get_executor() noexcept { return next_layer_.lowest_layer().get_executor(); } -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_context() - { - return next_layer_.get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_service() - { - return next_layer_.get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - /// Close the stream. void close() { @@ -145,10 +135,20 @@ public: std::size_t flush(asio::error_code& ec); /// Start an asynchronous flush. - template <typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_flush(ASIO_MOVE_ARG(WriteHandler) handler); + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler = default_completion_token_t<executor_type>> + auto async_flush( + WriteHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_flush<Stream>>(), + handler, declval<detail::buffered_stream_storage*>())); /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. @@ -163,11 +163,20 @@ public: /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler); + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_write_some<Stream>>(), + handler, declval<detail::buffered_stream_storage*>(), buffers)); /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. @@ -188,14 +197,21 @@ public: /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + /** + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + */ + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadHandler&& handler = default_completion_token_t<executor_type>()) + -> decltype( + declval<conditional_t<true, Stream&, ReadHandler>>().async_read_some( + buffers, static_cast<ReadHandler&&>(handler))) { return next_layer_.async_read_some(buffers, - ASIO_MOVE_CAST(ReadHandler)(handler)); + static_cast<ReadHandler&&>(handler)); } /// Peek at the incoming data on the stream. Returns the number of bytes read. diff --git a/3rdparty/asio/include/asio/buffered_write_stream_fwd.hpp b/3rdparty/asio/include/asio/buffered_write_stream_fwd.hpp index 88f93a4126e..809f44af03d 100644 --- a/3rdparty/asio/include/asio/buffered_write_stream_fwd.hpp +++ b/3rdparty/asio/include/asio/buffered_write_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_write_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/buffers_iterator.hpp b/3rdparty/asio/include/asio/buffers_iterator.hpp index 9080915134a..2c6d720787c 100644 --- a/3rdparty/asio/include/asio/buffers_iterator.hpp +++ b/3rdparty/asio/include/asio/buffers_iterator.hpp @@ -2,7 +2,7 @@ // buffers_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -38,7 +38,7 @@ namespace detail template <typename ByteType> struct byte_type { - typedef typename add_const<ByteType>::type type; + typedef add_const_t<ByteType> type; }; }; @@ -80,7 +80,7 @@ namespace detail struct buffers_iterator_types<const_buffer, ByteType> { typedef const_buffer buffer_type; - typedef typename add_const<ByteType>::type byte_type; + typedef add_const_t<ByteType> byte_type; typedef const const_buffer* const_iterator; }; @@ -98,7 +98,7 @@ namespace detail struct buffers_iterator_types<const_buffers_1, ByteType> { typedef const_buffer buffer_type; - typedef typename add_const<ByteType>::type byte_type; + typedef add_const_t<ByteType> byte_type; typedef const const_buffer* const_iterator; }; diff --git a/3rdparty/asio/include/asio/cancellation_signal.hpp b/3rdparty/asio/include/asio/cancellation_signal.hpp new file mode 100644 index 00000000000..43540ac3b08 --- /dev/null +++ b/3rdparty/asio/include/asio/cancellation_signal.hpp @@ -0,0 +1,245 @@ +// +// cancellation_signal.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CANCELLATION_SIGNAL_HPP +#define ASIO_CANCELLATION_SIGNAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cassert> +#include <new> +#include <utility> +#include "asio/cancellation_type.hpp" +#include "asio/detail/cstddef.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class cancellation_handler_base +{ +public: + virtual void call(cancellation_type_t) = 0; + virtual std::pair<void*, std::size_t> destroy() noexcept = 0; + +protected: + ~cancellation_handler_base() {} +}; + +template <typename Handler> +class cancellation_handler + : public cancellation_handler_base +{ +public: + template <typename... Args> + cancellation_handler(std::size_t size, Args&&... args) + : handler_(static_cast<Args&&>(args)...), + size_(size) + { + } + + void call(cancellation_type_t type) + { + handler_(type); + } + + std::pair<void*, std::size_t> destroy() noexcept + { + std::pair<void*, std::size_t> mem(this, size_); + this->cancellation_handler::~cancellation_handler(); + return mem; + } + + Handler& handler() noexcept + { + return handler_; + } + +private: + ~cancellation_handler() + { + } + + Handler handler_; + std::size_t size_; +}; + +} // namespace detail + +class cancellation_slot; + +/// A cancellation signal with a single slot. +class cancellation_signal +{ +public: + constexpr cancellation_signal() + : handler_(0) + { + } + + ASIO_DECL ~cancellation_signal(); + + /// Emits the signal and causes invocation of the slot's handler, if any. + void emit(cancellation_type_t type) + { + if (handler_) + handler_->call(type); + } + + /// Returns the single slot associated with the signal. + /** + * The signal object must remain valid for as long the slot may be used. + * Destruction of the signal invalidates the slot. + */ + cancellation_slot slot() noexcept; + +private: + cancellation_signal(const cancellation_signal&) = delete; + cancellation_signal& operator=(const cancellation_signal&) = delete; + + detail::cancellation_handler_base* handler_; +}; + +/// A slot associated with a cancellation signal. +class cancellation_slot +{ +public: + /// Creates a slot that is not connected to any cancellation signal. + constexpr cancellation_slot() + : handler_(0) + { + } + + /// Installs a handler into the slot, constructing the new object directly. + /** + * Destroys any existing handler in the slot, then installs the new handler, + * constructing it with the supplied @c args. + * + * The handler is a function object to be called when the signal is emitted. + * The signature of the handler must be + * @code void handler(asio::cancellation_type_t); @endcode + * + * @param args Arguments to be passed to the @c CancellationHandler object's + * constructor. + * + * @returns A reference to the newly installed handler. + * + * @note Handlers installed into the slot via @c emplace are not required to + * be copy constructible or move constructible. + */ + template <typename CancellationHandler, typename... Args> + CancellationHandler& emplace(Args&&... args) + { + typedef detail::cancellation_handler<CancellationHandler> + cancellation_handler_type; + auto_delete_helper del = { prepare_memory( + sizeof(cancellation_handler_type), + alignof(CancellationHandler)) }; + cancellation_handler_type* handler_obj = + new (del.mem.first) cancellation_handler_type( + del.mem.second, static_cast<Args&&>(args)...); + del.mem.first = 0; + *handler_ = handler_obj; + return handler_obj->handler(); + } + + /// Installs a handler into the slot. + /** + * Destroys any existing handler in the slot, then installs the new handler, + * constructing it as a decay-copy of the supplied handler. + * + * The handler is a function object to be called when the signal is emitted. + * The signature of the handler must be + * @code void handler(asio::cancellation_type_t); @endcode + * + * @param handler The handler to be installed. + * + * @returns A reference to the newly installed handler. + */ + template <typename CancellationHandler> + decay_t<CancellationHandler>& assign(CancellationHandler&& handler) + { + return this->emplace<decay_t<CancellationHandler>>( + static_cast<CancellationHandler&&>(handler)); + } + + /// Clears the slot. + /** + * Destroys any existing handler in the slot. + */ + ASIO_DECL void clear(); + + /// Returns whether the slot is connected to a signal. + constexpr bool is_connected() const noexcept + { + return handler_ != 0; + } + + /// Returns whether the slot is connected and has an installed handler. + constexpr bool has_handler() const noexcept + { + return handler_ != 0 && *handler_ != 0; + } + + /// Compare two slots for equality. + friend constexpr bool operator==(const cancellation_slot& lhs, + const cancellation_slot& rhs) noexcept + { + return lhs.handler_ == rhs.handler_; + } + + /// Compare two slots for inequality. + friend constexpr bool operator!=(const cancellation_slot& lhs, + const cancellation_slot& rhs) noexcept + { + return lhs.handler_ != rhs.handler_; + } + +private: + friend class cancellation_signal; + + constexpr cancellation_slot(int, + detail::cancellation_handler_base** handler) + : handler_(handler) + { + } + + ASIO_DECL std::pair<void*, std::size_t> prepare_memory( + std::size_t size, std::size_t align); + + struct auto_delete_helper + { + std::pair<void*, std::size_t> mem; + + ASIO_DECL ~auto_delete_helper(); + }; + + detail::cancellation_handler_base** handler_; +}; + +inline cancellation_slot cancellation_signal::slot() noexcept +{ + return cancellation_slot(0, &handler_); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/cancellation_signal.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_CANCELLATION_SIGNAL_HPP diff --git a/3rdparty/asio/include/asio/cancellation_state.hpp b/3rdparty/asio/include/asio/cancellation_state.hpp new file mode 100644 index 00000000000..3c13edcab94 --- /dev/null +++ b/3rdparty/asio/include/asio/cancellation_state.hpp @@ -0,0 +1,235 @@ +// +// cancellation_state.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CANCELLATION_STATE_HPP +#define ASIO_CANCELLATION_STATE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cassert> +#include <new> +#include <utility> +#include "asio/cancellation_signal.hpp" +#include "asio/detail/cstddef.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// A simple cancellation signal propagation filter. +template <cancellation_type_t Mask> +struct cancellation_filter +{ + /// Returns <tt>type & Mask</tt>. + cancellation_type_t operator()( + cancellation_type_t type) const noexcept + { + return type & Mask; + } +}; + +/// A cancellation filter that disables cancellation. +typedef cancellation_filter<cancellation_type::none> + disable_cancellation; + +/// A cancellation filter that enables terminal cancellation only. +typedef cancellation_filter<cancellation_type::terminal> + enable_terminal_cancellation; + +#if defined(GENERATING_DOCUMENTATION) + +/// A cancellation filter that enables terminal and partial cancellation. +typedef cancellation_filter< + cancellation_type::terminal | cancellation_type::partial> + enable_partial_cancellation; + +/// A cancellation filter that enables terminal, partial and total cancellation. +typedef cancellation_filter<cancellation_type::terminal + | cancellation_type::partial | cancellation_type::total> + enable_total_cancellation; + +#else // defined(GENERATING_DOCUMENTATION) + +typedef cancellation_filter< + static_cast<cancellation_type_t>( + static_cast<unsigned int>(cancellation_type::terminal) + | static_cast<unsigned int>(cancellation_type::partial))> + enable_partial_cancellation; + +typedef cancellation_filter< + static_cast<cancellation_type_t>( + static_cast<unsigned int>(cancellation_type::terminal) + | static_cast<unsigned int>(cancellation_type::partial) + | static_cast<unsigned int>(cancellation_type::total))> + enable_total_cancellation; + +#endif // defined(GENERATING_DOCUMENTATION) + +/// A cancellation state is used for chaining signals and slots in compositions. +class cancellation_state +{ +public: + /// Construct a disconnected cancellation state. + constexpr cancellation_state() noexcept + : impl_(0) + { + } + + /// Construct and attach to a parent slot to create a new child slot. + /** + * Initialises the cancellation state so that it allows terminal cancellation + * only. Equivalent to <tt>cancellation_state(slot, + * enable_terminal_cancellation())</tt>. + * + * @param slot The parent cancellation slot to which the state will be + * attached. + */ + template <typename CancellationSlot> + constexpr explicit cancellation_state(CancellationSlot slot) + : impl_(slot.is_connected() ? &slot.template emplace<impl<>>() : 0) + { + } + + /// Construct and attach to a parent slot to create a new child slot. + /** + * @param slot The parent cancellation slot to which the state will be + * attached. + * + * @param filter A function object that is used to transform incoming + * cancellation signals as they are received from the parent slot. This + * function object must have the signature: + * @code asio::cancellation_type_t filter( + * asio::cancellation_type_t); @endcode + * + * The library provides the following pre-defined cancellation filters: + * + * @li asio::disable_cancellation + * @li asio::enable_terminal_cancellation + * @li asio::enable_partial_cancellation + * @li asio::enable_total_cancellation + */ + template <typename CancellationSlot, typename Filter> + constexpr cancellation_state(CancellationSlot slot, Filter filter) + : impl_(slot.is_connected() + ? &slot.template emplace<impl<Filter, Filter>>(filter, filter) + : 0) + { + } + + /// Construct and attach to a parent slot to create a new child slot. + /** + * @param slot The parent cancellation slot to which the state will be + * attached. + * + * @param in_filter A function object that is used to transform incoming + * cancellation signals as they are received from the parent slot. This + * function object must have the signature: + * @code asio::cancellation_type_t in_filter( + * asio::cancellation_type_t); @endcode + * + * @param out_filter A function object that is used to transform outcoming + * cancellation signals as they are relayed to the child slot. This function + * object must have the signature: + * @code asio::cancellation_type_t out_filter( + * asio::cancellation_type_t); @endcode + * + * The library provides the following pre-defined cancellation filters: + * + * @li asio::disable_cancellation + * @li asio::enable_terminal_cancellation + * @li asio::enable_partial_cancellation + * @li asio::enable_total_cancellation + */ + template <typename CancellationSlot, typename InFilter, typename OutFilter> + constexpr cancellation_state(CancellationSlot slot, + InFilter in_filter, OutFilter out_filter) + : impl_(slot.is_connected() + ? &slot.template emplace<impl<InFilter, OutFilter>>( + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)) + : 0) + { + } + + /// Returns the single child slot associated with the state. + /** + * This sub-slot is used with the operations that are being composed. + */ + constexpr cancellation_slot slot() const noexcept + { + return impl_ ? impl_->signal_.slot() : cancellation_slot(); + } + + /// Returns the cancellation types that have been triggered. + cancellation_type_t cancelled() const noexcept + { + return impl_ ? impl_->cancelled_ : cancellation_type_t(); + } + + /// Clears the specified cancellation types, if they have been triggered. + void clear(cancellation_type_t mask = cancellation_type::all) + noexcept + { + if (impl_) + impl_->cancelled_ &= ~mask; + } + +private: + struct impl_base + { + impl_base() + : cancelled_() + { + } + + cancellation_signal signal_; + cancellation_type_t cancelled_; + }; + + template < + typename InFilter = enable_terminal_cancellation, + typename OutFilter = InFilter> + struct impl : impl_base + { + impl() + : in_filter_(), + out_filter_() + { + } + + impl(InFilter in_filter, OutFilter out_filter) + : in_filter_(static_cast<InFilter&&>(in_filter)), + out_filter_(static_cast<OutFilter&&>(out_filter)) + { + } + + void operator()(cancellation_type_t in) + { + this->cancelled_ = in_filter_(in); + cancellation_type_t out = out_filter_(this->cancelled_); + if (out != cancellation_type::none) + this->signal_.emit(out); + } + + InFilter in_filter_; + OutFilter out_filter_; + }; + + impl_base* impl_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_CANCELLATION_STATE_HPP diff --git a/3rdparty/asio/include/asio/cancellation_type.hpp b/3rdparty/asio/include/asio/cancellation_type.hpp new file mode 100644 index 00000000000..ec4a4d2458a --- /dev/null +++ b/3rdparty/asio/include/asio/cancellation_type.hpp @@ -0,0 +1,157 @@ +// +// cancellation_type.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CANCELLATION_TYPE_HPP +#define ASIO_CANCELLATION_TYPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +# if defined(GENERATING_DOCUMENTATION) + +/// Enumeration representing the different types of cancellation that may +/// be requested from or implemented by an asynchronous operation. +enum cancellation_type +{ + /// Bitmask representing no types of cancellation. + none = 0, + + /// Requests cancellation where, following a successful cancellation, the only + /// safe operations on the I/O object are closure or destruction. + terminal = 1, + + /// Requests cancellation where a successful cancellation may result in + /// partial side effects or no side effects. Following cancellation, the I/O + /// object is in a well-known state, and may be used for further operations. + partial = 2, + + /// Requests cancellation where a successful cancellation results in no + /// apparent side effects. Following cancellation, the I/O object is in the + /// same observable state as it was prior to the operation. + total = 4, + + /// Bitmask representing all types of cancellation. + all = 0xFFFFFFFF +}; + +/// Portability typedef. +typedef cancellation_type cancellation_type_t; + +#else // defined(GENERATING_DOCUMENTATION) + +enum class cancellation_type : unsigned int +{ + none = 0, + terminal = 1, + partial = 2, + total = 4, + all = 0xFFFFFFFF +}; + +typedef cancellation_type cancellation_type_t; + +#endif // defined(GENERATING_DOCUMENTATION) + +/// Negation operator. +/** + * @relates cancellation_type + */ +inline constexpr bool operator!(cancellation_type_t x) +{ + return static_cast<unsigned int>(x) == 0; +} + +/// Bitwise and operator. +/** + * @relates cancellation_type + */ +inline constexpr cancellation_type_t operator&( + cancellation_type_t x, cancellation_type_t y) +{ + return static_cast<cancellation_type_t>( + static_cast<unsigned int>(x) & static_cast<unsigned int>(y)); +} + +/// Bitwise or operator. +/** + * @relates cancellation_type + */ +inline constexpr cancellation_type_t operator|( + cancellation_type_t x, cancellation_type_t y) +{ + return static_cast<cancellation_type_t>( + static_cast<unsigned int>(x) | static_cast<unsigned int>(y)); +} + +/// Bitwise xor operator. +/** + * @relates cancellation_type + */ +inline constexpr cancellation_type_t operator^( + cancellation_type_t x, cancellation_type_t y) +{ + return static_cast<cancellation_type_t>( + static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y)); +} + +/// Bitwise negation operator. +/** + * @relates cancellation_type + */ +inline constexpr cancellation_type_t operator~(cancellation_type_t x) +{ + return static_cast<cancellation_type_t>(~static_cast<unsigned int>(x)); +} + +/// Bitwise and-assignment operator. +/** + * @relates cancellation_type + */ +inline cancellation_type_t& operator&=( + cancellation_type_t& x, cancellation_type_t y) +{ + x = x & y; + return x; +} + +/// Bitwise or-assignment operator. +/** + * @relates cancellation_type + */ +inline cancellation_type_t& operator|=( + cancellation_type_t& x, cancellation_type_t y) +{ + x = x | y; + return x; +} + +/// Bitwise xor-assignment operator. +/** + * @relates cancellation_type + */ +inline cancellation_type_t& operator^=( + cancellation_type_t& x, cancellation_type_t y) +{ + x = x ^ y; + return x; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_CANCELLATION_TYPE_HPP diff --git a/3rdparty/asio/include/asio/co_spawn.hpp b/3rdparty/asio/include/asio/co_spawn.hpp new file mode 100644 index 00000000000..26988f47da0 --- /dev/null +++ b/3rdparty/asio/include/asio/co_spawn.hpp @@ -0,0 +1,523 @@ +// +// co_spawn.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CO_SPAWN_HPP +#define ASIO_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#include "asio/awaitable.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/is_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +struct awaitable_signature; + +template <typename T, typename Executor> +struct awaitable_signature<awaitable<T, Executor>> +{ + typedef void type(std::exception_ptr, T); +}; + +template <typename Executor> +struct awaitable_signature<awaitable<void, Executor>> +{ + typedef void type(std::exception_ptr); +}; + +} // namespace detail + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The @ref completion_token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr, T); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, T) @endcode + * + * @par Example + * @code + * asio::awaitable<std::size_t> echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_executor, + * echo(std::move(my_tcp_socket)), + * [](std::exception_ptr e, std::size_t n) + * { + * std::cout << "transferred " << n << "\n"; + * }); + * @endcode + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call asio::this_coro::reset_cancellation_state. + */ +template <typename Executor, typename T, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr, T)) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + constraint_t< + (is_executor<Executor>::value || execution::is_executor<Executor>::value) + && is_convertible<Executor, AwaitableExecutor>::value + > = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The @ref completion_token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr) @endcode + * + * @par Example + * @code + * asio::awaitable<void> echo(tcp::socket socket) + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * } + * + * // ... + * + * asio::co_spawn(my_executor, + * echo(std::move(my_tcp_socket)), + * asio::detached); + * @endcode + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call asio::this_coro::reset_cancellation_state. + */ +template <typename Executor, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr)) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + constraint_t< + (is_executor<Executor>::value || execution::is_executor<Executor>::value) + && is_convertible<Executor, AwaitableExecutor>::value + > = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ctx An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The @ref completion_token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, T) @endcode + * + * @par Example + * @code + * asio::awaitable<std::size_t> echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_io_context, + * echo(std::move(my_tcp_socket)), + * [](std::exception_ptr e, std::size_t n) + * { + * std::cout << "transferred " << n << "\n"; + * }); + * @endcode + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call asio::this_coro::reset_cancellation_state. + */ +template <typename ExecutionContext, typename T, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr, T)) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename ExecutionContext::executor_type)> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + && is_convertible<typename ExecutionContext::executor_type, + AwaitableExecutor>::value + > = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ctx An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param a The asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The @ref completion_token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr) @endcode + * + * @par Example + * @code + * asio::awaitable<void> echo(tcp::socket socket) + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * } + * + * // ... + * + * asio::co_spawn(my_io_context, + * echo(std::move(my_tcp_socket)), + * asio::detached); + * @endcode + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call asio::this_coro::reset_cancellation_state. + */ +template <typename ExecutionContext, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr)) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename ExecutionContext::executor_type)> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + && is_convertible<typename ExecutionContext::executor_type, + AwaitableExecutor>::value + > = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param f A nullary function object with a return type of the form + * @c asio::awaitable<R,E> that will be used as the coroutine's entry + * point. + * + * @param token The @ref completion_token that will handle the notification + * that the thread of execution has completed. If @c R is @c void, the function + * signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the first template argument to the @c awaitable returned by the + * supplied function object @c F: + * @code asio::awaitable<R, AwaitableExecutor> F() @endcode + * + * @par Example + * @code + * asio::awaitable<std::size_t> echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_executor, + * [socket = std::move(my_tcp_socket)]() mutable + * -> asio::awaitable<void> + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * }, asio::detached); + * @endcode + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call asio::this_coro::reset_cancellation_state. + */ +template <typename Executor, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< + result_of_t<F()>>::type) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature<result_of_t<F()>>::type) +co_spawn(const Executor& ex, F&& f, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ctx An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param f A nullary function object with a return type of the form + * @c asio::awaitable<R,E> that will be used as the coroutine's entry + * point. + * + * @param token The @ref completion_token that will handle the notification + * that the thread of execution has completed. If @c R is @c void, the function + * signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the first template argument to the @c awaitable returned by the + * supplied function object @c F: + * @code asio::awaitable<R, AwaitableExecutor> F() @endcode + * + * @par Example + * @code + * asio::awaitable<std::size_t> echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * asio::co_spawn(my_io_context, + * [socket = std::move(my_tcp_socket)]() mutable + * -> asio::awaitable<void> + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::use_awaitable); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * }, asio::detached); + * @endcode + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call asio::this_coro::reset_cancellation_state. + */ +template <typename ExecutionContext, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< + result_of_t<F()>>::type) CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename ExecutionContext::executor_type)> +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature<result_of_t<F()>>::type) +co_spawn(ExecutionContext& ctx, F&& f, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0); + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/co_spawn.hpp" + +#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_CO_SPAWN_HPP diff --git a/3rdparty/asio/include/asio/completion_condition.hpp b/3rdparty/asio/include/asio/completion_condition.hpp index cb22ddddd90..3fe774f1ef1 100644 --- a/3rdparty/asio/include/asio/completion_condition.hpp +++ b/3rdparty/asio/include/asio/completion_condition.hpp @@ -2,7 +2,7 @@ // completion_condition.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/compose.hpp b/3rdparty/asio/include/asio/compose.hpp new file mode 100644 index 00000000000..abb438e3da7 --- /dev/null +++ b/3rdparty/asio/include/asio/compose.hpp @@ -0,0 +1,319 @@ +// +// compose.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_COMPOSE_HPP +#define ASIO_COMPOSE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" +#include "asio/detail/composed_work.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Impl, typename Work, typename Handler, typename Signature> +class composed_op; + +template <typename Impl, typename Work, typename Handler, + typename R, typename... Args> +class composed_op<Impl, Work, Handler, R(Args...)> + : public base_from_cancellation_state<Handler> +{ +public: + template <typename I, typename W, typename H> + composed_op(I&& impl, + W&& work, + H&& handler) + : base_from_cancellation_state<Handler>( + handler, enable_terminal_cancellation()), + impl_(static_cast<I&&>(impl)), + work_(static_cast<W&&>(work)), + handler_(static_cast<H&&>(handler)), + invocations_(0) + { + } + + composed_op(composed_op&& other) + : base_from_cancellation_state<Handler>( + static_cast<base_from_cancellation_state<Handler>&&>(other)), + impl_(static_cast<Impl&&>(other.impl_)), + work_(static_cast<Work&&>(other.work_)), + handler_(static_cast<Handler&&>(other.handler_)), + invocations_(other.invocations_) + { + } + + typedef typename composed_work_guard< + typename Work::head_type>::executor_type io_executor_type; + + io_executor_type get_io_executor() const noexcept + { + return work_.head_.get_executor(); + } + + typedef associated_executor_t<Handler, io_executor_type> executor_type; + + executor_type get_executor() const noexcept + { + return (get_associated_executor)(handler_, work_.head_.get_executor()); + } + + typedef associated_allocator_t<Handler, std::allocator<void>> allocator_type; + + allocator_type get_allocator() const noexcept + { + return (get_associated_allocator)(handler_, std::allocator<void>()); + } + + template<typename... T> + void operator()(T&&... t) + { + if (invocations_ < ~0u) + ++invocations_; + this->get_cancellation_state().slot().clear(); + impl_(*this, static_cast<T&&>(t)...); + } + + void complete(Args... args) + { + this->work_.reset(); + static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...); + } + + void reset_cancellation_state() + { + base_from_cancellation_state<Handler>::reset_cancellation_state(handler_); + } + + template <typename Filter> + void reset_cancellation_state(Filter&& filter) + { + base_from_cancellation_state<Handler>::reset_cancellation_state(handler_, + static_cast<Filter&&>(filter)); + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(InFilter&& in_filter, + OutFilter&& out_filter) + { + base_from_cancellation_state<Handler>::reset_cancellation_state(handler_, + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)); + } + + cancellation_type_t cancelled() const noexcept + { + return base_from_cancellation_state<Handler>::cancelled(); + } + +//private: + Impl impl_; + Work work_; + Handler handler_; + unsigned invocations_; +}; + +template <typename Impl, typename Work, typename Handler, typename Signature> +inline bool asio_handler_is_continuation( + composed_op<Impl, Work, Handler, Signature>* this_handler) +{ + return this_handler->invocations_ > 1 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Signature, typename Executors> +class initiate_composed_op +{ +public: + typedef typename composed_io_executors<Executors>::head_type executor_type; + + template <typename T> + explicit initiate_composed_op(int, T&& executors) + : executors_(static_cast<T&&>(executors)) + { + } + + executor_type get_executor() const noexcept + { + return executors_.head_; + } + + template <typename Handler, typename Impl> + void operator()(Handler&& handler, + Impl&& impl) const + { + composed_op<decay_t<Impl>, composed_work<Executors>, + decay_t<Handler>, Signature>( + static_cast<Impl&&>(impl), + composed_work<Executors>(executors_), + static_cast<Handler&&>(handler))(); + } + +private: + composed_io_executors<Executors> executors_; +}; + +template <typename Signature, typename Executors> +inline initiate_composed_op<Signature, Executors> make_initiate_composed_op( + composed_io_executors<Executors>&& executors) +{ + return initiate_composed_op<Signature, Executors>(0, + static_cast<composed_io_executors<Executors>&&>(executors)); +} + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename Impl, typename Work, typename Handler, + typename Signature, typename DefaultCandidate> +struct associator<Associator, + detail::composed_op<Impl, Work, Handler, Signature>, + DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::composed_op<Impl, Work, Handler, Signature>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const detail::composed_op<Impl, Work, Handler, Signature>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Launch an asynchronous operation with a stateful implementation. +/** + * The async_compose function simplifies the implementation of composed + * asynchronous operations automatically wrapping a stateful function object + * with a conforming intermediate completion handler. + * + * @param implementation A function object that contains the implementation of + * the composed asynchronous operation. The first argument to the function + * object is a non-const reference to the enclosing intermediate completion + * handler. The remaining arguments are any arguments that originate from the + * completion handlers of any asynchronous operations performed by the + * implementation. + * + * @param token The completion token. + * + * @param io_objects_or_executors Zero or more I/O objects or I/O executors for + * which outstanding work must be maintained. + * + * @par Per-Operation Cancellation + * By default, terminal per-operation cancellation is enabled for + * composed operations that are implemented using @c async_compose. To + * disable cancellation for the composed operation, or to alter its + * supported cancellation types, call the @c self object's @c + * reset_cancellation_state function. + * + * @par Example: + * + * @code struct async_echo_implementation + * { + * tcp::socket& socket_; + * asio::mutable_buffer buffer_; + * enum { starting, reading, writing } state_; + * + * template <typename Self> + * void operator()(Self& self, + * asio::error_code error = {}, + * std::size_t n = 0) + * { + * switch (state_) + * { + * case starting: + * state_ = reading; + * socket_.async_read_some( + * buffer_, std::move(self)); + * break; + * case reading: + * if (error) + * { + * self.complete(error, 0); + * } + * else + * { + * state_ = writing; + * asio::async_write(socket_, buffer_, + * asio::transfer_exactly(n), + * std::move(self)); + * } + * break; + * case writing: + * self.complete(error, n); + * break; + * } + * } + * }; + * + * template <typename CompletionToken> + * auto async_echo(tcp::socket& socket, + * asio::mutable_buffer buffer, + * CompletionToken&& token) -> + * decltype( + * asio::async_compose<CompletionToken, + * void(asio::error_code, std::size_t)>( + * std::declval<async_echo_implementation>(), + * token, socket)) + * { + * return asio::async_compose<CompletionToken, + * void(asio::error_code, std::size_t)>( + * async_echo_implementation{socket, buffer, + * async_echo_implementation::starting}, + * token, socket); + * } @endcode + */ +template <typename CompletionToken, typename Signature, + typename Implementation, typename... IoObjectsOrExecutors> +auto async_compose(Implementation&& implementation, + type_identity_t<CompletionToken>& token, + IoObjectsOrExecutors&&... io_objects_or_executors) + -> decltype( + async_initiate<CompletionToken, Signature>( + detail::make_initiate_composed_op<Signature>( + detail::make_composed_io_executors( + detail::get_composed_io_executor( + static_cast<IoObjectsOrExecutors&&>( + io_objects_or_executors))...)), + token, static_cast<Implementation&&>(implementation))) +{ + return async_initiate<CompletionToken, Signature>( + detail::make_initiate_composed_op<Signature>( + detail::make_composed_io_executors( + detail::get_composed_io_executor( + static_cast<IoObjectsOrExecutors&&>( + io_objects_or_executors))...)), + token, static_cast<Implementation&&>(implementation)); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_COMPOSE_HPP diff --git a/3rdparty/asio/include/asio/connect.hpp b/3rdparty/asio/include/asio/connect.hpp index 7dba932ecfb..d2916675455 100644 --- a/3rdparty/asio/include/asio/connect.hpp +++ b/3rdparty/asio/include/asio/connect.hpp @@ -2,7 +2,7 @@ // connect.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -27,6 +27,10 @@ namespace asio { namespace detail { + struct default_connect_condition; + template <typename, typename> class initiate_async_range_connect; + template <typename, typename> class initiate_async_iterator_connect; + char (&has_iterator_helper(...))[2]; template <typename T> @@ -58,7 +62,8 @@ struct is_endpoint_sequence /** * @defgroup connect asio::connect * - * @brief Establishes a socket connection by trying each endpoint in a sequence. + * @brief The @c connect function is a composed operation that establishes a + * socket connection by trying each endpoint in a sequence. */ /*@{*/ @@ -81,17 +86,15 @@ struct is_endpoint_sequence * Otherwise, contains the error from the last connection attempt. * * @par Example - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * asio::connect(s, r.resolve(q)); @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename EndpointSequence> +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type* = 0); + constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0); /// Establishes a socket connection by trying each endpoint in a sequence. /** @@ -113,9 +116,9 @@ typename Protocol::endpoint connect( * default-constructed endpoint. * * @par Example - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * asio::error_code ec; * asio::connect(s, r.resolve(q), ec); * if (ec) @@ -123,16 +126,14 @@ typename Protocol::endpoint connect( * // An error occurred. * } @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename EndpointSequence> +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, asio::error_code& ec, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type* = 0); + constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0); #if !defined(ASIO_NO_DEPRECATED) -/// (Deprecated.) Establishes a socket connection by trying each endpoint in a -/// sequence. +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. /** * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c connect member @@ -155,12 +156,12 @@ typename Protocol::endpoint connect( * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c asio::ip::tcp::resolver::iterator. */ -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, + constraint_t<!is_endpoint_sequence<Iterator>::value> = 0); -/// (Deprecated.) Establishes a socket connection by trying each endpoint in a -/// sequence. +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. /** * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c connect member @@ -183,10 +184,10 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c asio::ip::tcp::resolver::iterator. */ -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, asio::error_code& ec, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); + constraint_t<!is_endpoint_sequence<Iterator>::value> = 0); #endif // !defined(ASIO_NO_DEPRECATED) /// Establishes a socket connection by trying each endpoint in a sequence. @@ -210,14 +211,14 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * Otherwise, contains the error from the last connection attempt. * * @par Example - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); * tcp::resolver::results_type e = r.resolve(q); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * asio::connect(s, e.begin(), e.end()); @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end); /// Establishes a socket connection by trying each endpoint in a sequence. @@ -242,10 +243,10 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * endpoint. Otherwise, the end iterator. * * @par Example - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); * tcp::resolver::results_type e = r.resolve(q); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * asio::error_code ec; * asio::connect(s, e.begin(), e.end(), ec); * if (ec) @@ -253,8 +254,8 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * // An error occurred. * } @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, asio::error_code& ec); /// Establishes a socket connection by trying each endpoint in a sequence. @@ -301,20 +302,18 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * } * }; @endcode * It would be used with the asio::connect function as follows: - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * tcp::endpoint e = asio::connect(s, * r.resolve(q), my_connect_condition()); * std::cout << "Connected to: " << e << std::endl; @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type* = 0); + constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0); /// Establishes a socket connection by trying each endpoint in a sequence. /** @@ -361,9 +360,9 @@ typename Protocol::endpoint connect( * } * }; @endcode * It would be used with the asio::connect function as follows: - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * asio::error_code ec; * tcp::endpoint e = asio::connect(s, * r.resolve(q), my_connect_condition(), ec); @@ -376,18 +375,16 @@ typename Protocol::endpoint connect( * std::cout << "Connected to: " << e << std::endl; * } @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, asio::error_code& ec, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type* = 0); + constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0); #if !defined(ASIO_NO_DEPRECATED) -/// (Deprecated.) Establishes a socket connection by trying each endpoint in a -/// sequence. +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. /** * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c connect member @@ -421,14 +418,14 @@ typename Protocol::endpoint connect( * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c asio::ip::tcp::resolver::iterator. */ -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); + constraint_t<!is_endpoint_sequence<Iterator>::value> = 0); -/// (Deprecated.) Establishes a socket connection by trying each endpoint in a -/// sequence. +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. /** * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c connect member @@ -462,11 +459,11 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c asio::ip::tcp::resolver::iterator. */ -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, asio::error_code& ec, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); + constraint_t<!is_endpoint_sequence<Iterator>::value> = 0); #endif // !defined(ASIO_NO_DEPRECATED) /// Establishes a socket connection by trying each endpoint in a sequence. @@ -515,17 +512,17 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * } * }; @endcode * It would be used with the asio::connect function as follows: - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); * tcp::resolver::results_type e = r.resolve(q); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * tcp::resolver::results_type::iterator i = asio::connect( * s, e.begin(), e.end(), my_connect_condition()); * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, ConnectCondition connect_condition); /// Establishes a socket connection by trying each endpoint in a sequence. @@ -575,10 +572,10 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * } * }; @endcode * It would be used with the asio::connect function as follows: - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); * tcp::resolver::results_type e = r.resolve(q); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * asio::error_code ec; * tcp::resolver::results_type::iterator i = asio::connect( * s, e.begin(), e.end(), my_connect_condition()); @@ -591,9 +588,9 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * std::cout << "Connected to: " << i->endpoint() << std::endl; * } @endcode */ -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, asio::error_code& ec); @@ -602,8 +599,8 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, /** * @defgroup async_connect asio::async_connect * - * @brief Asynchronously establishes a socket connection by trying each - * endpoint in a sequence. + * @brief The @c async_connect function is a composed asynchronous operation + * that establishes a socket connection by trying each endpoint in a sequence. */ /*@{*/ @@ -613,16 +610,19 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c async_connect * member function, once for each endpoint in the sequence, until a connection - * is successfully established. + * is successfully established. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param s The socket to be connected. If the socket is already open, it will * be closed. * * @param endpoints A sequence of endpoints. * - * @param handler The handler to be called when the connect operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. if the sequence is empty, set to * // asio::error::not_found. Otherwise, contains the @@ -634,14 +634,17 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * const typename Protocol::endpoint& endpoint * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, typename Protocol::endpoint) @endcode * * @par Example - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * * // ... * @@ -667,34 +670,51 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * { * // ... * } @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the socket's @c async_connect operation. */ -template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename RangeConnectHandler> -ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename EndpointSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::endpoint)) RangeConnectToken + = default_completion_token_t<Executor>> +auto async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, - ASIO_MOVE_ARG(RangeConnectHandler) handler, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type* = 0); + RangeConnectToken&& token = default_completion_token_t<Executor>(), + constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0) + -> decltype( + async_initiate<RangeConnectToken, + void (asio::error_code, typename Protocol::endpoint)>( + declval<detail::initiate_async_range_connect<Protocol, Executor>>(), + token, endpoints, declval<detail::default_connect_condition>())); #if !defined(ASIO_NO_DEPRECATED) -/// (Deprecated.) Asynchronously establishes a socket connection by trying each -/// endpoint in a sequence. +/// (Deprecated: Use range overload.) Asynchronously establishes a socket +/// connection by trying each endpoint in a sequence. /** * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c async_connect * member function, once for each endpoint in the sequence, until a connection - * is successfully established. + * is successfully established. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param s The socket to be connected. If the socket is already open, it will * be closed. * * @param begin An iterator pointing to the start of a sequence of endpoints. * - * @param handler The handler to be called when the connect operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. if the sequence is empty, set to * // asio::error::not_found. Otherwise, contains the @@ -706,21 +726,39 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * Iterator iterator * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, Iterator) @endcode * * @note This overload assumes that a default constructed object of type @c * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c asio::ip::tcp::resolver::iterator. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the socket's @c async_connect operation. */ -template <typename Protocol ASIO_SVC_TPARAM, - typename Iterator, typename IteratorConnectHandler> -ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - Iterator begin, ASIO_MOVE_ARG(IteratorConnectHandler) handler, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); +template <typename Protocol, typename Executor, typename Iterator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken = default_completion_token_t<Executor>> +auto async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, + IteratorConnectToken&& token = default_completion_token_t<Executor>(), + constraint_t<!is_endpoint_sequence<Iterator>::value> = 0) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, Iterator(), + declval<detail::default_connect_condition>())); #endif // !defined(ASIO_NO_DEPRECATED) /// Asynchronously establishes a socket connection by trying each endpoint in a @@ -729,7 +767,8 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c async_connect * member function, once for each endpoint in the sequence, until a connection - * is successfully established. + * is successfully established. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param s The socket to be connected. If the socket is already open, it will * be closed. @@ -738,9 +777,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * * @param end An iterator pointing to the end of a sequence of endpoints. * - * @param handler The handler to be called when the connect operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. if the sequence is empty, set to * // asio::error::not_found. Otherwise, contains the @@ -752,13 +793,16 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * Iterator iterator * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, Iterator) @endcode * * @par Example * @code std::vector<tcp::endpoint> endpoints = ...; - * tcp::socket s(io_context); + * tcp::socket s(my_context); * asio::async_connect(s, * endpoints.begin(), endpoints.end(), * connect_handler); @@ -771,14 +815,28 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * { * // ... * } @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the socket's @c async_connect operation. */ -template <typename Protocol ASIO_SVC_TPARAM, - typename Iterator, typename IteratorConnectHandler> -ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, - ASIO_MOVE_ARG(IteratorConnectHandler) handler); +template <typename Protocol, typename Executor, typename Iterator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken = default_completion_token_t<Executor>> +auto async_connect( + basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, + IteratorConnectToken&& token = default_completion_token_t<Executor>()) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, end, declval<detail::default_connect_condition>())); /// Asynchronously establishes a socket connection by trying each endpoint in a /// sequence. @@ -786,7 +844,8 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c async_connect * member function, once for each endpoint in the sequence, until a connection - * is successfully established. + * is successfully established. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param s The socket to be connected. If the socket is already open, it will * be closed. @@ -804,9 +863,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * The function object should return true if the next endpoint should be tried, * and false if it should be skipped. * - * @param handler The handler to be called when the connect operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. if the sequence is empty, set to * // asio::error::not_found. Otherwise, contains the @@ -818,9 +879,12 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * Iterator iterator * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, typename Protocol::endpoint) @endcode * * @par Example * The following connect condition function object can be used to output @@ -837,9 +901,9 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * } * }; @endcode * It would be used with the asio::connect function as follows: - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * * // ... * @@ -874,25 +938,41 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * std::cout << "Connected to: " << endpoint << std::endl; * } * } @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the socket's @c async_connect operation. */ -template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence, - typename ConnectCondition, typename RangeConnectHandler> -ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, + typename EndpointSequence, typename ConnectCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::endpoint)) RangeConnectToken + = default_completion_token_t<Executor>> +auto async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, - ASIO_MOVE_ARG(RangeConnectHandler) handler, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type* = 0); + RangeConnectToken&& token = default_completion_token_t<Executor>(), + constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0) + -> decltype( + async_initiate<RangeConnectToken, + void (asio::error_code, typename Protocol::endpoint)>( + declval<detail::initiate_async_range_connect<Protocol, Executor>>(), + token, endpoints, connect_condition)); #if !defined(ASIO_NO_DEPRECATED) -/// (Deprecated.) Asynchronously establishes a socket connection by trying each -/// endpoint in a sequence. +/// (Deprecated: Use range overload.) Asynchronously establishes a socket +/// connection by trying each endpoint in a sequence. /** * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c async_connect * member function, once for each endpoint in the sequence, until a connection - * is successfully established. + * is successfully established. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param s The socket to be connected. If the socket is already open, it will * be closed. @@ -910,9 +990,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * The function object should return true if the next endpoint should be tried, * and false if it should be skipped. * - * @param handler The handler to be called when the connect operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. if the sequence is empty, set to * // asio::error::not_found. Otherwise, contains the @@ -924,22 +1006,40 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, * Iterator iterator * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, Iterator) @endcode * * @note This overload assumes that a default constructed object of type @c * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c asio::ip::tcp::resolver::iterator. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the socket's @c async_connect operation. */ -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> -ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, - ConnectCondition connect_condition, - ASIO_MOVE_ARG(IteratorConnectHandler) handler, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); +template <typename Protocol, typename Executor, + typename Iterator, typename ConnectCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken = default_completion_token_t<Executor>> +auto async_connect(basic_socket<Protocol, Executor>& s, + Iterator begin, ConnectCondition connect_condition, + IteratorConnectToken&& token = default_completion_token_t<Executor>(), + constraint_t<!is_endpoint_sequence<Iterator>::value> = 0) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, Iterator(), connect_condition)); #endif // !defined(ASIO_NO_DEPRECATED) /// Asynchronously establishes a socket connection by trying each endpoint in a @@ -948,7 +1048,8 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c async_connect * member function, once for each endpoint in the sequence, until a connection - * is successfully established. + * is successfully established. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param s The socket to be connected. If the socket is already open, it will * be closed. @@ -968,9 +1069,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * The function object should return true if the next endpoint should be tried, * and false if it should be skipped. * - * @param handler The handler to be called when the connect operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. if the sequence is empty, set to * // asio::error::not_found. Otherwise, contains the @@ -982,9 +1085,12 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * Iterator iterator * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, Iterator) @endcode * * @par Example * The following connect condition function object can be used to output @@ -1001,9 +1107,9 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * } * }; @endcode * It would be used with the asio::connect function as follows: - * @code tcp::resolver r(io_context); + * @code tcp::resolver r(my_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_context); + * tcp::socket s(my_context); * * // ... * @@ -1039,14 +1145,29 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, * std::cout << "Connected to: " << i->endpoint() << std::endl; * } * } @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the socket's @c async_connect operation. */ -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> -ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, + typename Iterator, typename ConnectCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken = default_completion_token_t<Executor>> +auto async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, - ASIO_MOVE_ARG(IteratorConnectHandler) handler); + IteratorConnectToken&& token = default_completion_token_t<Executor>()) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, end, connect_condition)); /*@}*/ diff --git a/3rdparty/asio/include/asio/connect_pipe.hpp b/3rdparty/asio/include/asio/connect_pipe.hpp new file mode 100644 index 00000000000..1c9eb79383f --- /dev/null +++ b/3rdparty/asio/include/asio/connect_pipe.hpp @@ -0,0 +1,83 @@ +// +// connect_pipe.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CONNECT_PIPE_HPP +#define ASIO_CONNECT_PIPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PIPE) \ + || defined(GENERATING_DOCUMENTATION) + +#include "asio/basic_readable_pipe.hpp" +#include "asio/basic_writable_pipe.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) +typedef HANDLE native_pipe_handle; +#else // defined(ASIO_HAS_IOCP) +typedef int native_pipe_handle; +#endif // defined(ASIO_HAS_IOCP) + +ASIO_DECL void create_pipe(native_pipe_handle p[2], + asio::error_code& ec); + +ASIO_DECL void close_pipe(native_pipe_handle p); + +} // namespace detail + +/// Connect two pipe ends using an anonymous pipe. +/** + * @param read_end The read end of the pipe. + * + * @param write_end The write end of the pipe. + * + * @throws asio::system_error Thrown on failure. + */ +template <typename Executor1, typename Executor2> +void connect_pipe(basic_readable_pipe<Executor1>& read_end, + basic_writable_pipe<Executor2>& write_end); + +/// Connect two pipe ends using an anonymous pipe. +/** + * @param read_end The read end of the pipe. + * + * @param write_end The write end of the pipe. + * + * @throws asio::system_error Thrown on failure. + * + * @param ec Set to indicate what error occurred, if any. + */ +template <typename Executor1, typename Executor2> +ASIO_SYNC_OP_VOID connect_pipe(basic_readable_pipe<Executor1>& read_end, + basic_writable_pipe<Executor2>& write_end, asio::error_code& ec); + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/connect_pipe.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/connect_pipe.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_PIPE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_CONNECT_PIPE_HPP diff --git a/3rdparty/asio/include/asio/consign.hpp b/3rdparty/asio/include/asio/consign.hpp new file mode 100644 index 00000000000..4b0bc431309 --- /dev/null +++ b/3rdparty/asio/include/asio/consign.hpp @@ -0,0 +1,75 @@ +// +// consign.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CONSIGN_HPP +#define ASIO_CONSIGN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <tuple> +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Completion token type used to specify that the completion handler should +/// carry additional values along with it. +/** + * This completion token adapter is typically used to keep at least one copy of + * an object, such as a smart pointer, alive until the completion handler is + * called. + */ +template <typename CompletionToken, typename... Values> +class consign_t +{ +public: + /// Constructor. + template <typename T, typename... V> + constexpr explicit consign_t(T&& completion_token, V&&... values) + : token_(static_cast<T&&>(completion_token)), + values_(static_cast<V&&>(values)...) + { + } + +#if defined(GENERATING_DOCUMENTATION) +private: +#endif // defined(GENERATING_DOCUMENTATION) + CompletionToken token_; + std::tuple<Values...> values_; +}; + +/// Completion token adapter used to specify that the completion handler should +/// carry additional values along with it. +/** + * This completion token adapter is typically used to keep at least one copy of + * an object, such as a smart pointer, alive until the completion handler is + * called. + */ +template <typename CompletionToken, typename... Values> +ASIO_NODISCARD inline constexpr +consign_t<decay_t<CompletionToken>, decay_t<Values>...> +consign(CompletionToken&& completion_token, Values&&... values) +{ + return consign_t<decay_t<CompletionToken>, decay_t<Values>...>( + static_cast<CompletionToken&&>(completion_token), + static_cast<Values&&>(values)...); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/consign.hpp" + +#endif // ASIO_CONSIGN_HPP diff --git a/3rdparty/asio/include/asio/coroutine.hpp b/3rdparty/asio/include/asio/coroutine.hpp index d4a03356d69..036e5148ad0 100644 --- a/3rdparty/asio/include/asio/coroutine.hpp +++ b/3rdparty/asio/include/asio/coroutine.hpp @@ -2,7 +2,7 @@ // coroutine.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -205,7 +205,7 @@ class coroutine_ref; * { * do * { - * socket_.reset(new tcp::socket(io_context_)); + * socket_.reset(new tcp::socket(my_context_)); * yield acceptor->async_accept(*socket_, *this); * fork server(*this)(); * } while (is_parent()); @@ -227,7 +227,7 @@ class coroutine_ref; * Note that @c fork doesn't do the actual forking by itself. It is the * application's responsibility to create a clone of the coroutine and call it. * The clone can be called immediately, as above, or scheduled for delayed - * execution using something like io_context::post(). + * execution using something like asio::post(). * * @par Alternate macro names * @@ -266,6 +266,7 @@ class coroutine_ref public: coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} + coroutine_ref(const coroutine_ref&) = default; ~coroutine_ref() { if (!modified_) value_ = -1; } operator int() const { return value_; } int& operator=(int v) { modified_ = true; return value_ = v; } @@ -289,7 +290,7 @@ private: bail_out_of_coroutine: \ break; \ } \ - else case 0: + else /* fall-through */ case 0: #define ASIO_CORO_YIELD_IMPL(n) \ for (_coro_value = (n);;) \ @@ -301,12 +302,12 @@ private: else \ switch (_coro_value ? 0 : 1) \ for (;;) \ - case -1: if (_coro_value) \ + /* fall-through */ case -1: if (_coro_value) \ goto terminate_coroutine; \ else for (;;) \ - case 1: if (_coro_value) \ + /* fall-through */ case 1: if (_coro_value) \ goto bail_out_of_coroutine; \ - else case 0: + else /* fall-through */ case 0: #define ASIO_CORO_FORK_IMPL(n) \ for (_coro_value = -(n);; _coro_value = (n)) \ diff --git a/3rdparty/asio/include/asio/datagram_socket_service.hpp b/3rdparty/asio/include/asio/datagram_socket_service.hpp deleted file mode 100644 index 4b9047dee90..00000000000 --- a/3rdparty/asio/include/asio/datagram_socket_service.hpp +++ /dev/null @@ -1,455 +0,0 @@ -// -// datagram_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DATAGRAM_SOCKET_SERVICE_HPP -#define ASIO_DATAGRAM_SOCKET_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/type_traits.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/null_socket_service.hpp" -#elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -#else -# include "asio/detail/reactive_socket_service.hpp" -#endif - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a datagram socket. -template <typename Protocol> -class datagram_socket_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<datagram_socket_service<Protocol> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The protocol type. - typedef Protocol protocol_type; - - /// The endpoint type. - typedef typename Protocol::endpoint endpoint_type; - -private: - // The type of the platform-specific implementation. -#if defined(ASIO_WINDOWS_RUNTIME) - typedef detail::null_socket_service<Protocol> service_impl_type; -#elif defined(ASIO_HAS_IOCP) - typedef detail::win_iocp_socket_service<Protocol> service_impl_type; -#else - typedef detail::reactive_socket_service<Protocol> service_impl_type; -#endif - -public: - /// The type of a datagram socket. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef typename service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new datagram socket service for the specified io_context. - explicit datagram_socket_service(asio::io_context& io_context) - : asio::detail::service_base< - datagram_socket_service<Protocol> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new datagram socket implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new datagram socket implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another datagram socket implementation. - void move_assign(implementation_type& impl, - datagram_socket_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } - - /// Move-construct a new datagram socket implementation from another protocol - /// type. - template <typename Protocol1> - void converting_move_construct(implementation_type& impl, - typename datagram_socket_service< - Protocol1>::implementation_type& other_impl, - typename enable_if<is_convertible< - Protocol1, Protocol>::value>::type* = 0) - { - service_impl_.template converting_move_construct<Protocol1>( - impl, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a datagram socket implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - // Open a new datagram socket implementation. - ASIO_SYNC_OP_VOID open(implementation_type& impl, - const protocol_type& protocol, asio::error_code& ec) - { - if (protocol.type() == ASIO_OS_DEF(SOCK_DGRAM)) - service_impl_.open(impl, protocol, ec); - else - ec = asio::error::invalid_argument; - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Assign an existing native socket to a datagram socket. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const protocol_type& protocol, const native_handle_type& native_socket, - asio::error_code& ec) - { - service_impl_.assign(impl, protocol, native_socket, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a datagram socket implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native socket implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the socket. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.at_mark(impl, ec); - } - - /// Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.available(impl, ec); - } - - // Bind the datagram socket to the specified local endpoint. - ASIO_SYNC_OP_VOID bind(implementation_type& impl, - const endpoint_type& endpoint, asio::error_code& ec) - { - service_impl_.bind(impl, endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Connect the datagram socket to the specified endpoint. - ASIO_SYNC_OP_VOID connect(implementation_type& impl, - const endpoint_type& peer_endpoint, asio::error_code& ec) - { - service_impl_.connect(impl, peer_endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Start an asynchronous connect. - template <typename ConnectHandler> - ASIO_INITFN_RESULT_TYPE(ConnectHandler, - void (asio::error_code)) - async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(ConnectHandler) handler) - { - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); - - return init.result.get(); - } - - /// Set a socket option. - template <typename SettableSocketOption> - ASIO_SYNC_OP_VOID set_option(implementation_type& impl, - const SettableSocketOption& option, asio::error_code& ec) - { - service_impl_.set_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get a socket option. - template <typename GettableSocketOption> - ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, - GettableSocketOption& option, asio::error_code& ec) const - { - service_impl_.get_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform an IO control command on the socket. - template <typename IoControlCommand> - ASIO_SYNC_OP_VOID io_control(implementation_type& impl, - IoControlCommand& command, asio::error_code& ec) - { - service_impl_.io_control(impl, command, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the socket. - bool non_blocking(const implementation_type& impl) const - { - return service_impl_.non_blocking(impl); - } - - /// Sets the non-blocking mode of the socket. - ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the native socket implementation. - bool native_non_blocking(const implementation_type& impl) const - { - return service_impl_.native_non_blocking(impl); - } - - /// Sets the non-blocking mode of the native socket implementation. - ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.native_non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the local endpoint. - endpoint_type local_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.local_endpoint(impl, ec); - } - - /// Get the remote endpoint. - endpoint_type remote_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.remote_endpoint(impl, ec); - } - - /// Disable sends or receives on the socket. - ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, - socket_base::shutdown_type what, asio::error_code& ec) - { - service_impl_.shutdown(impl, what, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Wait for the socket to become ready to read, ready to write, or to have - /// pending error conditions. - ASIO_SYNC_OP_VOID wait(implementation_type& impl, - socket_base::wait_type w, asio::error_code& ec) - { - service_impl_.wait(impl, w, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Asynchronously wait for the socket to become ready to read, ready to - /// write, or to have pending error conditions. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, socket_base::wait_type w, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, w, init.completion_handler); - - return init.result.get(); - } - - /// Send the given data to the peer. - template <typename ConstBufferSequence> - std::size_t send(implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.send(impl, buffers, flags, ec); - } - - /// Start an asynchronous send. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) - { - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_send(impl, buffers, flags, init.completion_handler); - - return init.result.get(); - } - - /// Send a datagram to the specified endpoint. - template <typename ConstBufferSequence> - std::size_t send_to(implementation_type& impl, - const ConstBufferSequence& buffers, const endpoint_type& destination, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.send_to(impl, buffers, destination, flags, ec); - } - - /// Start an asynchronous send. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send_to(implementation_type& impl, - const ConstBufferSequence& buffers, const endpoint_type& destination, - socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) - { - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_send_to(impl, buffers, - destination, flags, init.completion_handler); - - return init.result.get(); - } - - /// Receive some data from the peer. - template <typename MutableBufferSequence> - std::size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.receive(impl, buffers, flags, ec); - } - - /// Start an asynchronous receive. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) - { - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_receive(impl, buffers, flags, init.completion_handler); - - return init.result.get(); - } - - /// Receive a datagram with the endpoint of the sender. - template <typename MutableBufferSequence> - std::size_t receive_from(implementation_type& impl, - const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.receive_from(impl, buffers, sender_endpoint, flags, - ec); - } - - /// Start an asynchronous receive that will get the endpoint of the sender. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive_from(implementation_type& impl, - const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) - { - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_receive_from(impl, buffers, - sender_endpoint, flags, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_DATAGRAM_SOCKET_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/deadline_timer.hpp b/3rdparty/asio/include/asio/deadline_timer.hpp index 1ffbfe534d0..dfa0b9ca169 100644 --- a/3rdparty/asio/include/asio/deadline_timer.hpp +++ b/3rdparty/asio/include/asio/deadline_timer.hpp @@ -2,7 +2,7 @@ // deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/deadline_timer_service.hpp b/3rdparty/asio/include/asio/deadline_timer_service.hpp deleted file mode 100644 index 7acac1cb109..00000000000 --- a/3rdparty/asio/include/asio/deadline_timer_service.hpp +++ /dev/null @@ -1,173 +0,0 @@ -// -// deadline_timer_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DEADLINE_TIMER_SERVICE_HPP -#define ASIO_DEADLINE_TIMER_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_BOOST_DATE_TIME) \ - || defined(GENERATING_DOCUMENTATION) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/deadline_timer_service.hpp" -#include "asio/io_context.hpp" -#include "asio/time_traits.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a timer. -template <typename TimeType, - typename TimeTraits = asio::time_traits<TimeType> > -class deadline_timer_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base< - deadline_timer_service<TimeType, TimeTraits> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The time traits type. - typedef TimeTraits traits_type; - - /// The time type. - typedef typename traits_type::time_type time_type; - - /// The duration type. - typedef typename traits_type::duration_type duration_type; - -private: - // The type of the platform-specific implementation. - typedef detail::deadline_timer_service<traits_type> service_impl_type; - -public: - /// The implementation type of the deadline timer. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// Construct a new timer service for the specified io_context. - explicit deadline_timer_service(asio::io_context& io_context) - : asio::detail::service_base< - deadline_timer_service<TimeType, TimeTraits> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new timer implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - - /// Destroy a timer implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Cancel any asynchronous wait operations associated with the timer. - std::size_t cancel(implementation_type& impl, asio::error_code& ec) - { - return service_impl_.cancel(impl, ec); - } - - /// Cancels one asynchronous wait operation associated with the timer. - std::size_t cancel_one(implementation_type& impl, - asio::error_code& ec) - { - return service_impl_.cancel_one(impl, ec); - } - - /// Get the expiry time for the timer as an absolute time. - time_type expires_at(const implementation_type& impl) const - { - return service_impl_.expiry(impl); - } - - /// Set the expiry time for the timer as an absolute time. - std::size_t expires_at(implementation_type& impl, - const time_type& expiry_time, asio::error_code& ec) - { - return service_impl_.expires_at(impl, expiry_time, ec); - } - - /// Get the expiry time for the timer relative to now. - duration_type expires_from_now(const implementation_type& impl) const - { - return TimeTraits::subtract(service_impl_.expiry(impl), TimeTraits::now()); - } - - /// Set the expiry time for the timer relative to now. - std::size_t expires_from_now(implementation_type& impl, - const duration_type& expiry_time, asio::error_code& ec) - { - return service_impl_.expires_after(impl, expiry_time, ec); - } - - // Perform a blocking wait on the timer. - void wait(implementation_type& impl, asio::error_code& ec) - { - service_impl_.wait(impl, ec); - } - - // Start an asynchronous wait on the timer. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_HAS_BOOST_DATE_TIME) - // || defined(GENERATING_DOCUMENTATION) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_DEADLINE_TIMER_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/defer.hpp b/3rdparty/asio/include/asio/defer.hpp index 5e8061406ab..608debe4d91 100644 --- a/3rdparty/asio/include/asio/defer.hpp +++ b/3rdparty/asio/include/asio/defer.hpp @@ -2,7 +2,7 @@ // defer.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,9 +17,13 @@ #include "asio/detail/config.hpp" #include "asio/async_result.hpp" +#include "asio/detail/initiate_defer.hpp" #include "asio/detail/type_traits.hpp" #include "asio/execution_context.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" #include "asio/is_executor.hpp" +#include "asio/require.hpp" #include "asio/detail/push_options.hpp" @@ -31,27 +35,58 @@ namespace asio { * executor. The function object is queued for execution, and is never called * from the current thread prior to returning from <tt>defer()</tt>. * - * This function has the following effects: + * The use of @c defer(), rather than @ref post(), indicates the caller's + * preference that the executor defer the queueing of the function object. This + * may allow the executor to optimise queueing for cases when the function + * object represents a continuation of the current call context. * - * @li Constructs a function object handler of type @c Handler, initialized - * with <tt>handler(forward<CompletionToken>(token))</tt>. + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode * - * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, - * initializing the object as <tt>result(handler)</tt>. + * @returns This function returns <tt>async_initiate<NullaryToken, + * void()>(Init{}, token)</tt>, where @c Init is a function object type defined + * as: * - * @li Obtains the handler's associated executor object @c ex by performing - * <tt>get_associated_executor(handler)</tt>. + * @code class Init + * { + * public: + * template <typename CompletionHandler> + * void operator()(CompletionHandler&& completion_handler) const; + * }; @endcode * - * @li Obtains the handler's associated allocator object @c alloc by performing - * <tt>get_associated_allocator(handler)</tt>. + * The function call operator of @c Init: * - * @li Performs <tt>ex.defer(std::move(handler), alloc)</tt>. + * @li Obtains the handler's associated executor object @c ex of type @c Ex by + * performing @code auto ex = get_associated_executor(handler); @endcode * - * @li Returns <tt>result.get()</tt>. + * @li Obtains the handler's associated allocator object @c alloc by performing + * @code auto alloc = get_associated_allocator(handler); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs + * @code prefer( + * require(ex, execution::blocking.never), + * execution::relationship.continuation, + * execution::allocator(alloc) + * ).execute(std::forward<CompletionHandler>(completion_handler)); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs + * @code ex.defer( + * std::forward<CompletionHandler>(completion_handler), + * alloc); @endcode + * + * @par Completion Signature + * @code void() @endcode */ -template <typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - ASIO_MOVE_ARG(CompletionToken) token); +template <ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken> +auto defer(NullaryToken&& token) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_defer>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_defer(), token); +} /// Submits a completion token or function object for execution. /** @@ -59,49 +94,125 @@ ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( * The function object is queued for execution, and is never called from the * current thread prior to returning from <tt>defer()</tt>. * - * This function has the following effects: + * The use of @c defer(), rather than @ref post(), indicates the caller's + * preference that the executor defer the queueing of the function object. This + * may allow the executor to optimise queueing for cases when the function + * object represents a continuation of the current call context. * - * @li Constructs a function object handler of type @c Handler, initialized - * with <tt>handler(forward<CompletionToken>(token))</tt>. + * @param ex The target executor. * - * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, - * initializing the object as <tt>result(handler)</tt>. + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode * - * @li Obtains the handler's associated executor object @c ex1 by performing - * <tt>get_associated_executor(handler)</tt>. + * @returns This function returns <tt>async_initiate<NullaryToken, + * void()>(Init{ex}, token)</tt>, where @c Init is a function object type + * defined as: * - * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. + * @code class Init + * { + * public: + * using executor_type = Executor; + * explicit Init(const Executor& ex) : ex_(ex) {} + * executor_type get_executor() const noexcept { return ex_; } + * template <typename CompletionHandler> + * void operator()(CompletionHandler&& completion_handler) const; + * private: + * Executor ex_; // exposition only + * }; @endcode * - * @li Obtains the handler's associated allocator object @c alloc by performing - * <tt>get_associated_allocator(handler)</tt>. + * The function call operator of @c Init: * - * @li Constructs a function object @c f with a function call operator that - * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by - * <tt>w.reset()</tt>. + * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by + * performing @code auto ex1 = get_associated_executor(handler, ex); @endcode * - * @li Performs <tt>Executor(ex).defer(std::move(f), alloc)</tt>. - * - * @li Returns <tt>result.get()</tt>. + * @li Obtains the handler's associated allocator object @c alloc by performing + * @code auto alloc = get_associated_allocator(handler); @endcode + * + * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a + * function object @c f with a member @c executor_ that is initialised with + * <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c + * handler_ that is a decay-copy of @c completion_handler, and a function call + * operator that performs: + * @code auto a = get_associated_allocator(handler_); + * prefer(executor_, execution::allocator(a)).execute(std::move(handler_)); + * @endcode + * + * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a + * function object @c f with a member @c work_ that is initialised with + * <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of + * @c completion_handler, and a function call operator that performs: + * @code auto a = get_associated_allocator(handler_); + * work_.get_executor().dispatch(std::move(handler_), a); + * work_.reset(); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs + * @code prefer( + * require(ex, execution::blocking.never), + * execution::relationship.continuation, + * execution::allocator(alloc) + * ).execute(std::move(f)); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs + * @code ex.defer(std::move(f), alloc); @endcode + * + * @par Completion Signature + * @code void() @endcode */ -template <typename Executor, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_executor<Executor>::value>::type* = 0); +template <typename Executor, + ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken + = default_completion_token_t<Executor>> +auto defer(const Executor& ex, + NullaryToken&& token + = default_completion_token_t<Executor>(), + constraint_t< + (execution::is_executor<Executor>::value + && can_require<Executor, execution::blocking_t::never_t>::value) + || is_executor<Executor>::value + > = 0) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_defer_with_executor<Executor>>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_defer_with_executor<Executor>(ex), token); +} /// Submits a completion token or function object for execution. /** - * @returns <tt>defer(ctx.get_executor(), forward<CompletionToken>(token))</tt>. + * @param ctx An execution context, from which the target executor is obtained. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode + * + * @returns <tt>defer(ctx.get_executor(), forward<NullaryToken>(token))</tt>. + * + * @par Completion Signature + * @code void() @endcode */ -template <typename ExecutionContext, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type* = 0); +template <typename ExecutionContext, + ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken + = default_completion_token_t<typename ExecutionContext::executor_type>> +auto defer(ExecutionContext& ctx, + NullaryToken&& token + = default_completion_token_t<typename ExecutionContext::executor_type>(), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_defer_with_executor< + typename ExecutionContext::executor_type>>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_defer_with_executor< + typename ExecutionContext::executor_type>( + ctx.get_executor()), token); +} } // namespace asio #include "asio/detail/pop_options.hpp" -#include "asio/impl/defer.hpp" - #endif // ASIO_DEFER_HPP diff --git a/3rdparty/asio/include/asio/deferred.hpp b/3rdparty/asio/include/asio/deferred.hpp new file mode 100644 index 00000000000..b919f249553 --- /dev/null +++ b/3rdparty/asio/include/asio/deferred.hpp @@ -0,0 +1,715 @@ +// +// deferred.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DEFERRED_HPP +#define ASIO_DEFERRED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <tuple> +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/utility.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Trait for detecting objects that are usable as deferred operations. +template <typename T> +struct is_deferred : false_type +{ +}; + +/// Helper type to wrap multiple completion signatures. +template <typename... Signatures> +struct deferred_signatures +{ +}; + +namespace detail { + +// Helper trait for getting the completion signatures of the tail in a sequence +// when invoked with the specified arguments. + +template <typename Tail, typename... Signatures> +struct deferred_sequence_signatures; + +template <typename Tail, typename R, typename... Args, typename... Signatures> +struct deferred_sequence_signatures<Tail, R(Args...), Signatures...> + : completion_signature_of<decltype(declval<Tail>()(declval<Args>()...))> +{ + static_assert( + !is_same<decltype(declval<Tail>()(declval<Args>()...)), void>::value, + "deferred functions must produce a deferred return type"); +}; + +// Completion handler for the head component of a deferred sequence. +template <typename Handler, typename Tail> +class deferred_sequence_handler +{ +public: + template <typename H, typename T> + explicit deferred_sequence_handler(H&& handler, T&& tail) + : handler_(static_cast<H&&>(handler)), + tail_(static_cast<T&&>(tail)) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + static_cast<Tail&&>(tail_)( + static_cast<Args&&>(args)...)( + static_cast<Handler&&>(handler_)); + } + +//private: + Handler handler_; + Tail tail_; +}; + +template <typename Head, typename Tail, typename... Signatures> +class deferred_sequence_base +{ +private: + struct initiate + { + template <typename Handler> + void operator()(Handler&& handler, Head head, Tail&& tail) + { + static_cast<Head&&>(head)( + deferred_sequence_handler<decay_t<Handler>, decay_t<Tail>>( + static_cast<Handler&&>(handler), static_cast<Tail&&>(tail))); + } + }; + + Head head_; + Tail tail_; + +public: + template <typename H, typename T> + constexpr explicit deferred_sequence_base(H&& head, T&& tail) + : head_(static_cast<H&&>(head)), + tail_(static_cast<T&&>(tail)) + { + } + + template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken> + auto operator()(CompletionToken&& token) && + -> decltype( + async_initiate<CompletionToken, Signatures...>( + initiate(), token, static_cast<Head&&>(this->head_), + static_cast<Tail&&>(this->tail_))) + { + return async_initiate<CompletionToken, Signatures...>(initiate(), + token, static_cast<Head&&>(head_), static_cast<Tail&&>(tail_)); + } + + template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken> + auto operator()(CompletionToken&& token) const & + -> decltype( + async_initiate<CompletionToken, Signatures...>( + initiate(), token, this->head_, this->tail_)) + { + return async_initiate<CompletionToken, Signatures...>( + initiate(), token, head_, tail_); + } +}; + +// Two-step application of variadic Signatures to determine correct base type. + +template <typename Head, typename Tail> +struct deferred_sequence_types +{ + template <typename... Signatures> + struct op1 + { + typedef deferred_sequence_base<Head, Tail, Signatures...> type; + }; + + template <typename... Signatures> + struct op2 + { + typedef typename deferred_sequence_signatures<Tail, Signatures...>::template + apply<op1>::type::type type; + }; + + typedef typename completion_signature_of<Head>::template + apply<op2>::type::type base; +}; + +} // namespace detail + +/// Used to represent an empty deferred action. +struct deferred_noop +{ + /// No effect. + template <typename... Args> + void operator()(Args&&...) && + { + } + + /// No effect. + template <typename... Args> + void operator()(Args&&...) const & + { + } +}; + +#if !defined(GENERATING_DOCUMENTATION) +template <> +struct is_deferred<deferred_noop> : true_type +{ +}; +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Tag type to disambiguate deferred constructors. +struct deferred_init_tag {}; + +/// Wraps a function object so that it may be used as an element in a deferred +/// composition. +template <typename Function> +class deferred_function +{ +public: + /// Constructor. + template <typename F> + constexpr explicit deferred_function(deferred_init_tag, F&& function) + : function_(static_cast<F&&>(function)) + { + } + +//private: + Function function_; + +public: + template <typename... Args> + auto operator()(Args&&... args) && + -> decltype( + static_cast<Function&&>(this->function_)(static_cast<Args&&>(args)...)) + { + return static_cast<Function&&>(function_)(static_cast<Args&&>(args)...); + } + + template <typename... Args> + auto operator()(Args&&... args) const & + -> decltype(Function(function_)(static_cast<Args&&>(args)...)) + { + return Function(function_)(static_cast<Args&&>(args)...); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) +template <typename Function> +struct is_deferred<deferred_function<Function>> : true_type +{ +}; +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Encapsulates deferred values. +template <typename... Values> +class ASIO_NODISCARD deferred_values +{ +private: + std::tuple<Values...> values_; + + struct initiate + { + template <typename Handler, typename... V> + void operator()(Handler handler, V&&... values) + { + static_cast<Handler&&>(handler)(static_cast<V&&>(values)...); + } + }; + + template <typename CompletionToken, std::size_t... I> + auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>) + -> decltype( + async_initiate<CompletionToken, void(Values...)>(initiate(), token, + std::get<I>(static_cast<std::tuple<Values...>&&>(this->values_))...)) + { + return async_initiate<CompletionToken, void(Values...)>(initiate(), token, + std::get<I>(static_cast<std::tuple<Values...>&&>(values_))...); + } + + template <typename CompletionToken, std::size_t... I> + auto const_invoke_helper(CompletionToken&& token, + detail::index_sequence<I...>) + -> decltype( + async_initiate<CompletionToken, void(Values...)>( + initiate(), token, std::get<I>(values_)...)) + { + return async_initiate<CompletionToken, void(Values...)>( + initiate(), token, std::get<I>(values_)...); + } + +public: + /// Construct a deferred asynchronous operation from the arguments to an + /// initiation function object. + template <typename... V> + constexpr explicit deferred_values( + deferred_init_tag, V&&... values) + : values_(static_cast<V&&>(values)...) + { + } + + /// Initiate the deferred operation using the supplied completion token. + template <ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken> + auto operator()(CompletionToken&& token) && + -> decltype( + this->invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<Values...>())) + { + return this->invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<Values...>()); + } + + template <ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken> + auto operator()(CompletionToken&& token) const & + -> decltype( + this->const_invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<Values...>())) + { + return this->const_invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<Values...>()); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) +template <typename... Values> +struct is_deferred<deferred_values<Values...>> : true_type +{ +}; +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Encapsulates a deferred asynchronous operation. +template <typename Signature, typename Initiation, typename... InitArgs> +class ASIO_NODISCARD deferred_async_operation +{ +private: + typedef decay_t<Initiation> initiation_t; + initiation_t initiation_; + typedef std::tuple<decay_t<InitArgs>...> init_args_t; + init_args_t init_args_; + + template <typename CompletionToken, std::size_t... I> + auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>) + -> decltype( + async_initiate<CompletionToken, Signature>( + static_cast<initiation_t&&>(initiation_), token, + std::get<I>(static_cast<init_args_t&&>(init_args_))...)) + { + return async_initiate<CompletionToken, Signature>( + static_cast<initiation_t&&>(initiation_), token, + std::get<I>(static_cast<init_args_t&&>(init_args_))...); + } + + template <typename CompletionToken, std::size_t... I> + auto const_invoke_helper(CompletionToken&& token, + detail::index_sequence<I...>) const & + -> decltype( + async_initiate<CompletionToken, Signature>( + initiation_t(initiation_), token, std::get<I>(init_args_)...)) + { + return async_initiate<CompletionToken, Signature>( + initiation_t(initiation_), token, std::get<I>(init_args_)...); + } + +public: + /// Construct a deferred asynchronous operation from the arguments to an + /// initiation function object. + template <typename I, typename... A> + constexpr explicit deferred_async_operation( + deferred_init_tag, I&& initiation, A&&... init_args) + : initiation_(static_cast<I&&>(initiation)), + init_args_(static_cast<A&&>(init_args)...) + { + } + + /// Initiate the asynchronous operation using the supplied completion token. + template <ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken> + auto operator()(CompletionToken&& token) && + -> decltype( + this->invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>())) + { + return this->invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>()); + } + + template <ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken> + auto operator()(CompletionToken&& token) const & + -> decltype( + this->const_invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>())) + { + return this->const_invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>()); + } +}; + +/// Encapsulates a deferred asynchronous operation thas has multiple completion +/// signatures. +template <typename... Signatures, typename Initiation, typename... InitArgs> +class ASIO_NODISCARD deferred_async_operation< + deferred_signatures<Signatures...>, Initiation, InitArgs...> +{ +private: + typedef decay_t<Initiation> initiation_t; + initiation_t initiation_; + typedef std::tuple<decay_t<InitArgs>...> init_args_t; + init_args_t init_args_; + + template <typename CompletionToken, std::size_t... I> + auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>) + -> decltype( + async_initiate<CompletionToken, Signatures...>( + static_cast<initiation_t&&>(initiation_), token, + std::get<I>(static_cast<init_args_t&&>(init_args_))...)) + { + return async_initiate<CompletionToken, Signatures...>( + static_cast<initiation_t&&>(initiation_), token, + std::get<I>(static_cast<init_args_t&&>(init_args_))...); + } + + template <typename CompletionToken, std::size_t... I> + auto const_invoke_helper(CompletionToken&& token, + detail::index_sequence<I...>) const & + -> decltype( + async_initiate<CompletionToken, Signatures...>( + initiation_t(initiation_), token, std::get<I>(init_args_)...)) + { + return async_initiate<CompletionToken, Signatures...>( + initiation_t(initiation_), token, std::get<I>(init_args_)...); + } + +public: + /// Construct a deferred asynchronous operation from the arguments to an + /// initiation function object. + template <typename I, typename... A> + constexpr explicit deferred_async_operation( + deferred_init_tag, I&& initiation, A&&... init_args) + : initiation_(static_cast<I&&>(initiation)), + init_args_(static_cast<A&&>(init_args)...) + { + } + + /// Initiate the asynchronous operation using the supplied completion token. + template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken> + auto operator()(CompletionToken&& token) && + -> decltype( + this->invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>())) + { + return this->invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>()); + } + + template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken> + auto operator()(CompletionToken&& token) const & + -> decltype( + this->const_invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>())) + { + return this->const_invoke_helper( + static_cast<CompletionToken&&>(token), + detail::index_sequence_for<InitArgs...>()); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) +template <typename Signature, typename Initiation, typename... InitArgs> +struct is_deferred< + deferred_async_operation<Signature, Initiation, InitArgs...>> : true_type +{ +}; +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Defines a link between two consecutive operations in a sequence. +template <typename Head, typename Tail> +class ASIO_NODISCARD deferred_sequence : + public detail::deferred_sequence_types<Head, Tail>::base +{ +public: + template <typename H, typename T> + constexpr explicit deferred_sequence(deferred_init_tag, H&& head, T&& tail) + : detail::deferred_sequence_types<Head, Tail>::base( + static_cast<H&&>(head), static_cast<T&&>(tail)) + { + } + +#if defined(GENERATING_DOCUMENTATION) + template <typename CompletionToken> + auto operator()(CompletionToken&& token) &&; + + template <typename CompletionToken> + auto operator()(CompletionToken&& token) const &; +#endif // defined(GENERATING_DOCUMENTATION) +}; + +#if !defined(GENERATING_DOCUMENTATION) +template <typename Head, typename Tail> +struct is_deferred<deferred_sequence<Head, Tail>> : true_type +{ +}; +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Used to represent a deferred conditional branch. +template <typename OnTrue = deferred_noop, typename OnFalse = deferred_noop> +class ASIO_NODISCARD deferred_conditional +{ +private: + template <typename T, typename F> friend class deferred_conditional; + + // Helper constructor. + template <typename T, typename F> + explicit deferred_conditional(bool b, T&& on_true, F&& on_false) + : on_true_(static_cast<T&&>(on_true)), + on_false_(static_cast<F&&>(on_false)), + bool_(b) + { + } + + OnTrue on_true_; + OnFalse on_false_; + bool bool_; + +public: + /// Construct a deferred conditional with the value to determine which branch + /// will be executed. + constexpr explicit deferred_conditional(bool b) + : on_true_(), + on_false_(), + bool_(b) + { + } + + /// Invoke the conditional branch bsaed on the stored value. + template <typename... Args> + auto operator()(Args&&... args) && + -> decltype(static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...)) + { + if (bool_) + { + return static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...); + } + else + { + return static_cast<OnFalse&&>(on_false_)(static_cast<Args&&>(args)...); + } + } + + template <typename... Args> + auto operator()(Args&&... args) const & + -> decltype(on_true_(static_cast<Args&&>(args)...)) + { + if (bool_) + { + return on_true_(static_cast<Args&&>(args)...); + } + else + { + return on_false_(static_cast<Args&&>(args)...); + } + } + + /// Set the true branch of the conditional. + template <typename T> + deferred_conditional<T, OnFalse> then(T on_true, + constraint_t< + is_deferred<T>::value + >* = 0, + constraint_t< + is_same< + conditional_t<true, OnTrue, T>, + deferred_noop + >::value + >* = 0) && + { + return deferred_conditional<T, OnFalse>( + bool_, static_cast<T&&>(on_true), + static_cast<OnFalse&&>(on_false_)); + } + + /// Set the false branch of the conditional. + template <typename T> + deferred_conditional<OnTrue, T> otherwise(T on_false, + constraint_t< + is_deferred<T>::value + >* = 0, + constraint_t< + !is_same< + conditional_t<true, OnTrue, T>, + deferred_noop + >::value + >* = 0, + constraint_t< + is_same< + conditional_t<true, OnFalse, T>, + deferred_noop + >::value + >* = 0) && + { + return deferred_conditional<OnTrue, T>( + bool_, static_cast<OnTrue&&>(on_true_), + static_cast<T&&>(on_false)); + } +}; + +#if !defined(GENERATING_DOCUMENTATION) +template <typename OnTrue, typename OnFalse> +struct is_deferred<deferred_conditional<OnTrue, OnFalse>> : true_type +{ +}; +#endif // !defined(GENERATING_DOCUMENTATION) + +/// Class used to specify that an asynchronous operation should return a +/// function object to lazily launch the operation. +/** + * The deferred_t class is used to indicate that an asynchronous operation + * should return a function object which is itself an initiation function. A + * deferred_t object may be passed as a completion token to an asynchronous + * operation, typically using the special value @c asio::deferred. For + * example: + * + * @code auto my_deferred_op + * = my_socket.async_read_some(my_buffer, + * asio::deferred); @endcode + * + * The initiating function (async_read_some in the above example) returns a + * function object that will lazily initiate the operation. + */ +class deferred_t +{ +public: + /// Default constructor. + constexpr deferred_t() + { + } + + /// Adapts an executor to add the @c deferred_t completion token as the + /// default. + template <typename InnerExecutor> + struct executor_with_default : InnerExecutor + { + /// Specify @c deferred_t as the default completion token type. + typedef deferred_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + template <typename InnerExecutor1> + executor_with_default(const InnerExecutor1& ex, + constraint_t< + conditional_t< + !is_same<InnerExecutor1, executor_with_default>::value, + is_convertible<InnerExecutor1, InnerExecutor>, + false_type + >::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c deferred_t as its + /// default completion token type. + template <typename T> + using as_default_on_t = typename T::template rebind_executor< + executor_with_default<typename T::executor_type>>::other; + + /// Function helper to adapt an I/O object to use @c deferred_t as its + /// default completion token type. + template <typename T> + static typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other(static_cast<T&&>(object)); + } + + /// Creates a new deferred from a function. + template <typename Function> + constraint_t< + !is_deferred<decay_t<Function>>::value, + deferred_function<decay_t<Function>> + > operator()(Function&& function) const + { + return deferred_function<decay_t<Function>>( + deferred_init_tag{}, static_cast<Function&&>(function)); + } + + /// Passes through anything that is already deferred. + template <typename T> + constraint_t< + is_deferred<decay_t<T>>::value, + decay_t<T> + > operator()(T&& t) const + { + return static_cast<T&&>(t); + } + + /// Returns a deferred operation that returns the provided values. + template <typename... Args> + static constexpr deferred_values<decay_t<Args>...> values(Args&&... args) + { + return deferred_values<decay_t<Args>...>( + deferred_init_tag{}, static_cast<Args&&>(args)...); + } + + /// Creates a conditional object for branching deferred operations. + static constexpr deferred_conditional<> when(bool b) + { + return deferred_conditional<>(b); + } +}; + +/// Pipe operator used to chain deferred operations. +template <typename Head, typename Tail> +inline auto operator|(Head head, Tail&& tail) + -> constraint_t< + is_deferred<Head>::value, + decltype(static_cast<Head&&>(head)(static_cast<Tail&&>(tail))) + > +{ + return static_cast<Head&&>(head)(static_cast<Tail&&>(tail)); +} + +/// A @ref completion_token object used to specify that an asynchronous +/// operation should return a function object to lazily launch the operation. +/** + * See the documentation for asio::deferred_t for a usage example. + */ +constexpr deferred_t deferred; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/deferred.hpp" + +#endif // ASIO_DEFERRED_HPP diff --git a/3rdparty/asio/include/asio/detached.hpp b/3rdparty/asio/include/asio/detached.hpp new file mode 100644 index 00000000000..b71bd9d978b --- /dev/null +++ b/3rdparty/asio/include/asio/detached.hpp @@ -0,0 +1,105 @@ +// +// detached.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETACHED_HPP +#define ASIO_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <memory> +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// A @ref completion_token type used to specify that an asynchronous operation +/// is detached. +/** + * The detached_t class is used to indicate that an asynchronous operation is + * detached. That is, there is no completion handler waiting for the + * operation's result. A detached_t object may be passed as a handler to an + * asynchronous operation, typically using the special value + * @c asio::detached. For example: + * + * @code my_socket.async_send(my_buffer, asio::detached); + * @endcode + */ +class detached_t +{ +public: + /// Constructor. + constexpr detached_t() + { + } + + /// Adapts an executor to add the @c detached_t completion token as the + /// default. + template <typename InnerExecutor> + struct executor_with_default : InnerExecutor + { + /// Specify @c detached_t as the default completion token type. + typedef detached_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + executor_with_default(const InnerExecutor& ex) noexcept + : InnerExecutor(ex) + { + } + + /// Convert the specified executor to the inner executor type, then use + /// that to construct the adapted executor. + template <typename OtherExecutor> + executor_with_default(const OtherExecutor& ex, + constraint_t< + is_convertible<OtherExecutor, InnerExecutor>::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c detached_t as its + /// default completion token type. + template <typename T> + using as_default_on_t = typename T::template rebind_executor< + executor_with_default<typename T::executor_type>>::other; + + /// Function helper to adapt an I/O object to use @c detached_t as its + /// default completion token type. + template <typename T> + static typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other(static_cast<T&&>(object)); + } +}; + +/// A @ref completion_token object used to specify that an asynchronous +/// operation is detached. +/** + * See the documentation for asio::detached_t for a usage example. + */ +constexpr detached_t detached; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/detached.hpp" + +#endif // ASIO_DETACHED_HPP diff --git a/3rdparty/asio/include/asio/detail/array.hpp b/3rdparty/asio/include/asio/detail/array.hpp index cfb0acce60a..f2015c7919b 100644 --- a/3rdparty/asio/include/asio/detail/array.hpp +++ b/3rdparty/asio/include/asio/detail/array.hpp @@ -2,7 +2,7 @@ // detail/array.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,20 +17,12 @@ #include "asio/detail/config.hpp" -#if defined(ASIO_HAS_STD_ARRAY) -# include <array> -#else // defined(ASIO_HAS_STD_ARRAY) -# include <boost/array.hpp> -#endif // defined(ASIO_HAS_STD_ARRAY) +#include <array> namespace asio { namespace detail { -#if defined(ASIO_HAS_STD_ARRAY) using std::array; -#else // defined(ASIO_HAS_STD_ARRAY) -using boost::array; -#endif // defined(ASIO_HAS_STD_ARRAY) } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/array_fwd.hpp b/3rdparty/asio/include/asio/detail/array_fwd.hpp index 6a19a820461..79491348a69 100644 --- a/3rdparty/asio/include/asio/detail/array_fwd.hpp +++ b/3rdparty/asio/include/asio/detail/array_fwd.hpp @@ -2,7 +2,7 @@ // detail/array_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -27,8 +27,6 @@ class array; // Standard library components can't be forward declared, so we'll have to // include the array header. Fortunately, it's fairly lightweight and doesn't // add significantly to the compile time. -#if defined(ASIO_HAS_STD_ARRAY) -# include <array> -#endif // defined(ASIO_HAS_STD_ARRAY) +#include <array> #endif // ASIO_DETAIL_ARRAY_FWD_HPP diff --git a/3rdparty/asio/include/asio/detail/assert.hpp b/3rdparty/asio/include/asio/detail/assert.hpp index 22bb4b94fd9..b53774d9aff 100644 --- a/3rdparty/asio/include/asio/detail/assert.hpp +++ b/3rdparty/asio/include/asio/detail/assert.hpp @@ -2,7 +2,7 @@ // detail/assert.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/atomic_count.hpp b/3rdparty/asio/include/asio/detail/atomic_count.hpp index 798f9150097..6116279c89e 100644 --- a/3rdparty/asio/include/asio/detail/atomic_count.hpp +++ b/3rdparty/asio/include/asio/detail/atomic_count.hpp @@ -2,7 +2,7 @@ // detail/atomic_count.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,11 +19,9 @@ #if !defined(ASIO_HAS_THREADS) // Nothing to include. -#elif defined(ASIO_HAS_STD_ATOMIC) +#else // !defined(ASIO_HAS_THREADS) # include <atomic> -#else // defined(ASIO_HAS_STD_ATOMIC) -# include <boost/detail/atomic_count.hpp> -#endif // defined(ASIO_HAS_STD_ATOMIC) +#endif // !defined(ASIO_HAS_THREADS) namespace asio { namespace detail { @@ -31,13 +29,29 @@ namespace detail { #if !defined(ASIO_HAS_THREADS) typedef long atomic_count; inline void increment(atomic_count& a, long b) { a += b; } -#elif defined(ASIO_HAS_STD_ATOMIC) +inline void decrement(atomic_count& a, long b) { a -= b; } +inline void ref_count_up(atomic_count& a) { ++a; } +inline bool ref_count_down(atomic_count& a) { return --a == 0; } +#else // !defined(ASIO_HAS_THREADS) typedef std::atomic<long> atomic_count; inline void increment(atomic_count& a, long b) { a += b; } -#else // defined(ASIO_HAS_STD_ATOMIC) -typedef boost::detail::atomic_count atomic_count; -inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; } -#endif // defined(ASIO_HAS_STD_ATOMIC) +inline void decrement(atomic_count& a, long b) { a -= b; } + +inline void ref_count_up(atomic_count& a) +{ + a.fetch_add(1, std::memory_order_relaxed); +} + +inline bool ref_count_down(atomic_count& a) +{ + if (a.fetch_sub(1, std::memory_order_release) == 1) + { + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + return false; +} +#endif // !defined(ASIO_HAS_THREADS) } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/base_from_cancellation_state.hpp b/3rdparty/asio/include/asio/detail/base_from_cancellation_state.hpp new file mode 100644 index 00000000000..3ce7dcf0b7f --- /dev/null +++ b/3rdparty/asio/include/asio/detail/base_from_cancellation_state.hpp @@ -0,0 +1,164 @@ +// +// detail/base_from_cancellation_state.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP +#define ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/cancellation_state.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler, typename = void> +class base_from_cancellation_state +{ +public: + typedef cancellation_slot cancellation_slot_type; + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return cancellation_state_.slot(); + } + + cancellation_state get_cancellation_state() const noexcept + { + return cancellation_state_; + } + +protected: + explicit base_from_cancellation_state(const Handler& handler) + : cancellation_state_( + asio::get_associated_cancellation_slot(handler)) + { + } + + template <typename Filter> + base_from_cancellation_state(const Handler& handler, Filter filter) + : cancellation_state_( + asio::get_associated_cancellation_slot(handler), filter, filter) + { + } + + template <typename InFilter, typename OutFilter> + base_from_cancellation_state(const Handler& handler, + InFilter&& in_filter, + OutFilter&& out_filter) + : cancellation_state_( + asio::get_associated_cancellation_slot(handler), + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)) + { + } + + void reset_cancellation_state(const Handler& handler) + { + cancellation_state_ = cancellation_state( + asio::get_associated_cancellation_slot(handler)); + } + + template <typename Filter> + void reset_cancellation_state(const Handler& handler, Filter filter) + { + cancellation_state_ = cancellation_state( + asio::get_associated_cancellation_slot(handler), filter, filter); + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(const Handler& handler, + InFilter&& in_filter, + OutFilter&& out_filter) + { + cancellation_state_ = cancellation_state( + asio::get_associated_cancellation_slot(handler), + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)); + } + + cancellation_type_t cancelled() const noexcept + { + return cancellation_state_.cancelled(); + } + +private: + cancellation_state cancellation_state_; +}; + +template <typename Handler> +class base_from_cancellation_state<Handler, + enable_if_t< + is_same< + typename associated_cancellation_slot< + Handler, cancellation_slot + >::asio_associated_cancellation_slot_is_unspecialised, + void + >::value + > + > +{ +public: + cancellation_state get_cancellation_state() const noexcept + { + return cancellation_state(); + } + +protected: + explicit base_from_cancellation_state(const Handler&) + { + } + + template <typename Filter> + base_from_cancellation_state(const Handler&, Filter) + { + } + + template <typename InFilter, typename OutFilter> + base_from_cancellation_state(const Handler&, + InFilter&&, + OutFilter&&) + { + } + + void reset_cancellation_state(const Handler&) + { + } + + template <typename Filter> + void reset_cancellation_state(const Handler&, Filter) + { + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(const Handler&, + InFilter&&, + OutFilter&&) + { + } + + constexpr cancellation_type_t cancelled() const noexcept + { + return cancellation_type::none; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP diff --git a/3rdparty/asio/include/asio/detail/base_from_completion_cond.hpp b/3rdparty/asio/include/asio/detail/base_from_completion_cond.hpp index 9f5165b230d..ba0cc879602 100644 --- a/3rdparty/asio/include/asio/detail/base_from_completion_cond.hpp +++ b/3rdparty/asio/include/asio/detail/base_from_completion_cond.hpp @@ -2,7 +2,7 @@ // detail/base_from_completion_cond.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -27,8 +27,9 @@ template <typename CompletionCondition> class base_from_completion_cond { protected: - explicit base_from_completion_cond(CompletionCondition completion_condition) - : completion_condition_(completion_condition) + explicit base_from_completion_cond(CompletionCondition& completion_condition) + : completion_condition_( + static_cast<CompletionCondition&&>(completion_condition)) { } diff --git a/3rdparty/asio/include/asio/detail/bind_handler.hpp b/3rdparty/asio/include/asio/detail/bind_handler.hpp index 3752464a544..3c16b13a458 100644 --- a/3rdparty/asio/include/asio/detail/bind_handler.hpp +++ b/3rdparty/asio/include/asio/detail/bind_handler.hpp @@ -2,7 +2,7 @@ // detail/bind_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,11 +16,8 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/associator.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/type_traits.hpp" #include "asio/detail/push_options.hpp" @@ -28,24 +25,78 @@ namespace asio { namespace detail { +template <typename Handler> +class binder0 +{ +public: + template <typename T> + binder0(int, T&& handler) + : handler_(static_cast<T&&>(handler)) + { + } + + binder0(Handler& handler) + : handler_(static_cast<Handler&&>(handler)) + { + } + + binder0(const binder0& other) + : handler_(other.handler_) + { + } + + binder0(binder0&& other) + : handler_(static_cast<Handler&&>(other.handler_)) + { + } + + void operator()() + { + static_cast<Handler&&>(handler_)(); + } + + void operator()() const + { + handler_(); + } + +//private: + Handler handler_; +}; + +template <typename Handler> +inline bool asio_handler_is_continuation( + binder0<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Handler> +inline binder0<decay_t<Handler>> bind_handler( + Handler&& handler) +{ + return binder0<decay_t<Handler>>( + 0, static_cast<Handler&&>(handler)); +} + template <typename Handler, typename Arg1> class binder1 { public: template <typename T> - binder1(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1) - : handler_(ASIO_MOVE_CAST(T)(handler)), + binder1(int, T&& handler, const Arg1& arg1) + : handler_(static_cast<T&&>(handler)), arg1_(arg1) { } binder1(Handler& handler, const Arg1& arg1) - : handler_(ASIO_MOVE_CAST(Handler)(handler)), + : handler_(static_cast<Handler&&>(handler)), arg1_(arg1) { } -#if defined(ASIO_HAS_MOVE) binder1(const binder1& other) : handler_(other.handler_), arg1_(other.arg1_) @@ -53,15 +104,15 @@ public: } binder1(binder1&& other) - : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), - arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) + : handler_(static_cast<Handler&&>(other.handler_)), + arg1_(static_cast<Arg1&&>(other.arg1_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()() { - handler_(static_cast<const Arg1&>(arg1_)); + static_cast<Handler&&>(handler_)( + static_cast<const Arg1&>(arg1_)); } void operator()() const @@ -75,22 +126,6 @@ public: }; template <typename Handler, typename Arg1> -inline void* asio_handler_allocate(std::size_t size, - binder1<Handler, Arg1>* this_handler) -{ - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); -} - -template <typename Handler, typename Arg1> -inline void asio_handler_deallocate(void* pointer, std::size_t size, - binder1<Handler, Arg1>* this_handler) -{ - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); -} - -template <typename Handler, typename Arg1> inline bool asio_handler_is_continuation( binder1<Handler, Arg1>* this_handler) { @@ -98,28 +133,12 @@ inline bool asio_handler_is_continuation( this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1> -inline void asio_handler_invoke(Function& function, - binder1<Handler, Arg1>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); -} - -template <typename Function, typename Handler, typename Arg1> -inline void asio_handler_invoke(const Function& function, - binder1<Handler, Arg1>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); -} - template <typename Handler, typename Arg1> -inline binder1<typename decay<Handler>::type, Arg1> bind_handler( - ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1) +inline binder1<decay_t<Handler>, Arg1> bind_handler( + Handler&& handler, const Arg1& arg1) { - return binder1<typename decay<Handler>::type, Arg1>(0, - ASIO_MOVE_CAST(Handler)(handler), arg1); + return binder1<decay_t<Handler>, Arg1>(0, + static_cast<Handler&&>(handler), arg1); } template <typename Handler, typename Arg1, typename Arg2> @@ -127,22 +146,21 @@ class binder2 { public: template <typename T> - binder2(int, ASIO_MOVE_ARG(T) handler, + binder2(int, T&& handler, const Arg1& arg1, const Arg2& arg2) - : handler_(ASIO_MOVE_CAST(T)(handler)), + : handler_(static_cast<T&&>(handler)), arg1_(arg1), arg2_(arg2) { } binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2) - : handler_(ASIO_MOVE_CAST(Handler)(handler)), + : handler_(static_cast<Handler&&>(handler)), arg1_(arg1), arg2_(arg2) { } -#if defined(ASIO_HAS_MOVE) binder2(const binder2& other) : handler_(other.handler_), arg1_(other.arg1_), @@ -151,16 +169,16 @@ public: } binder2(binder2&& other) - : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), - arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), - arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) + : handler_(static_cast<Handler&&>(other.handler_)), + arg1_(static_cast<Arg1&&>(other.arg1_)), + arg2_(static_cast<Arg2&&>(other.arg2_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()() { - handler_(static_cast<const Arg1&>(arg1_), + static_cast<Handler&&>(handler_)( + static_cast<const Arg1&>(arg1_), static_cast<const Arg2&>(arg2_)); } @@ -176,99 +194,302 @@ public: }; template <typename Handler, typename Arg1, typename Arg2> -inline void* asio_handler_allocate(std::size_t size, +inline bool asio_handler_is_continuation( binder2<Handler, Arg1, Arg2>* this_handler) { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); } template <typename Handler, typename Arg1, typename Arg2> -inline void asio_handler_deallocate(void* pointer, std::size_t size, - binder2<Handler, Arg1, Arg2>* this_handler) +inline binder2<decay_t<Handler>, Arg1, Arg2> bind_handler( + Handler&& handler, const Arg1& arg1, const Arg2& arg2) { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); + return binder2<decay_t<Handler>, Arg1, Arg2>(0, + static_cast<Handler&&>(handler), arg1, arg2); } -template <typename Handler, typename Arg1, typename Arg2> +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> +class binder3 +{ +public: + template <typename T> + binder3(int, T&& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(static_cast<T&&>(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + + binder3(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(static_cast<Handler&&>(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + + binder3(const binder3& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_) + { + } + + binder3(binder3&& other) + : handler_(static_cast<Handler&&>(other.handler_)), + arg1_(static_cast<Arg1&&>(other.arg1_)), + arg2_(static_cast<Arg2&&>(other.arg2_)), + arg3_(static_cast<Arg3&&>(other.arg3_)) + { + } + + void operator()() + { + static_cast<Handler&&>(handler_)( + static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), + static_cast<const Arg3&>(arg3_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> inline bool asio_handler_is_continuation( - binder2<Handler, Arg1, Arg2>* this_handler) + binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { return asio_handler_cont_helpers::is_continuation( this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2> -inline void asio_handler_invoke(Function& function, - binder2<Handler, Arg1, Arg2>* this_handler) +template <typename Handler, typename Arg1, typename Arg2, typename Arg3> +inline binder3<decay_t<Handler>, Arg1, Arg2, Arg3> bind_handler( + Handler&& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3) { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); + return binder3<decay_t<Handler>, Arg1, Arg2, Arg3>(0, + static_cast<Handler&&>(handler), arg1, arg2, arg3); } -template <typename Function, typename Handler, typename Arg1, typename Arg2> -inline void asio_handler_invoke(const Function& function, - binder2<Handler, Arg1, Arg2>* this_handler) +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +class binder4 { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); -} +public: + template <typename T> + binder4(int, T&& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(static_cast<T&&>(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } -template <typename Handler, typename Arg1, typename Arg2> -inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler( - ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2) + binder4(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(static_cast<Handler&&>(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + + binder4(const binder4& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_) + { + } + + binder4(binder4&& other) + : handler_(static_cast<Handler&&>(other.handler_)), + arg1_(static_cast<Arg1&&>(other.arg1_)), + arg2_(static_cast<Arg2&&>(other.arg2_)), + arg3_(static_cast<Arg3&&>(other.arg3_)), + arg4_(static_cast<Arg4&&>(other.arg4_)) + { + } + + void operator()() + { + static_cast<Handler&&>(handler_)( + static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), + static_cast<const Arg3&>(arg3_), + static_cast<const Arg4&>(arg4_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; +}; + +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline bool asio_handler_is_continuation( + binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { - return binder2<typename decay<Handler>::type, Arg1, Arg2>(0, - ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); } -#if defined(ASIO_HAS_MOVE) +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline binder4<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4> +bind_handler(Handler&& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) +{ + return binder4<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4>(0, + static_cast<Handler&&>(handler), arg1, arg2, arg3, arg4); +} -template <typename Handler, typename Arg1> -class move_binder1 +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +class binder5 { public: - move_binder1(int, ASIO_MOVE_ARG(Handler) handler, - ASIO_MOVE_ARG(Arg1) arg1) - : handler_(ASIO_MOVE_CAST(Handler)(handler)), - arg1_(ASIO_MOVE_CAST(Arg1)(arg1)) + template <typename T> + binder5(int, T&& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(static_cast<T&&>(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) { } - move_binder1(move_binder1&& other) - : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), - arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) + binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(static_cast<Handler&&>(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + + binder5(const binder5& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_), + arg5_(other.arg5_) + { + } + + binder5(binder5&& other) + : handler_(static_cast<Handler&&>(other.handler_)), + arg1_(static_cast<Arg1&&>(other.arg1_)), + arg2_(static_cast<Arg2&&>(other.arg2_)), + arg3_(static_cast<Arg3&&>(other.arg3_)), + arg4_(static_cast<Arg4&&>(other.arg4_)), + arg5_(static_cast<Arg5&&>(other.arg5_)) { } void operator()() { - handler_(ASIO_MOVE_CAST(Arg1)(arg1_)); + static_cast<Handler&&>(handler_)( + static_cast<const Arg1&>(arg1_), + static_cast<const Arg2&>(arg2_), + static_cast<const Arg3&>(arg3_), + static_cast<const Arg4&>(arg4_), + static_cast<const Arg5&>(arg5_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_, arg5_); } //private: Handler handler_; Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; + Arg5 arg5_; }; -template <typename Handler, typename Arg1> -inline void* asio_handler_allocate(std::size_t size, - move_binder1<Handler, Arg1>* this_handler) +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +inline bool asio_handler_is_continuation( + binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); } -template <typename Handler, typename Arg1> -inline void asio_handler_deallocate(void* pointer, std::size_t size, - move_binder1<Handler, Arg1>* this_handler) +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +inline binder5<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4, Arg5> +bind_handler(Handler&& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); + return binder5<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4, Arg5>(0, + static_cast<Handler&&>(handler), arg1, arg2, arg3, arg4, arg5); } template <typename Handler, typename Arg1> +class move_binder1 +{ +public: + move_binder1(int, Handler&& handler, + Arg1&& arg1) + : handler_(static_cast<Handler&&>(handler)), + arg1_(static_cast<Arg1&&>(arg1)) + { + } + + move_binder1(move_binder1&& other) + : handler_(static_cast<Handler&&>(other.handler_)), + arg1_(static_cast<Arg1&&>(other.arg1_)) + { + } + + void operator()() + { + static_cast<Handler&&>(handler_)( + static_cast<Arg1&&>(arg1_)); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template <typename Handler, typename Arg1> inline bool asio_handler_is_continuation( move_binder1<Handler, Arg1>* this_handler) { @@ -276,37 +497,30 @@ inline bool asio_handler_is_continuation( this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1> -inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function, - move_binder1<Handler, Arg1>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - ASIO_MOVE_CAST(Function)(function), this_handler->handler_); -} - template <typename Handler, typename Arg1, typename Arg2> class move_binder2 { public: - move_binder2(int, ASIO_MOVE_ARG(Handler) handler, - const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2) - : handler_(ASIO_MOVE_CAST(Handler)(handler)), + move_binder2(int, Handler&& handler, + const Arg1& arg1, Arg2&& arg2) + : handler_(static_cast<Handler&&>(handler)), arg1_(arg1), - arg2_(ASIO_MOVE_CAST(Arg2)(arg2)) + arg2_(static_cast<Arg2&&>(arg2)) { } move_binder2(move_binder2&& other) - : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), - arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), - arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) + : handler_(static_cast<Handler&&>(other.handler_)), + arg1_(static_cast<Arg1&&>(other.arg1_)), + arg2_(static_cast<Arg2&&>(other.arg2_)) { } void operator()() { - handler_(static_cast<const Arg1&>(arg1_), - ASIO_MOVE_CAST(Arg2)(arg2_)); + static_cast<Handler&&>(handler_)( + static_cast<const Arg1&>(arg1_), + static_cast<Arg2&&>(arg2_)); } //private: @@ -316,22 +530,6 @@ public: }; template <typename Handler, typename Arg1, typename Arg2> -inline void* asio_handler_allocate(std::size_t size, - move_binder2<Handler, Arg1, Arg2>* this_handler) -{ - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); -} - -template <typename Handler, typename Arg1, typename Arg2> -inline void asio_handler_deallocate(void* pointer, std::size_t size, - move_binder2<Handler, Arg1, Arg2>* this_handler) -{ - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); -} - -template <typename Handler, typename Arg1, typename Arg2> inline bool asio_handler_is_continuation( move_binder2<Handler, Arg1, Arg2>* this_handler) { @@ -339,119 +537,173 @@ inline bool asio_handler_is_continuation( this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2> -inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function, - move_binder2<Handler, Arg1, Arg2>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - ASIO_MOVE_CAST(Function)(function), this_handler->handler_); -} - -#endif // defined(ASIO_HAS_MOVE) - } // namespace detail -template <typename Handler, typename Arg1, typename Allocator> -struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator> +template <template <typename, typename> class Associator, + typename Handler, typename DefaultCandidate> +struct associator<Associator, + detail::binder0<Handler>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_allocator<Handler, Allocator>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::binder0<Handler>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::binder1<Handler, Arg1>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static auto get(const detail::binder0<Handler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_allocator<Handler, Allocator>::get(h.handler_, a); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -template <typename Handler, typename Arg1, typename Arg2, typename Allocator> -struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator> +template <template <typename, typename> class Associator, + typename Handler, typename Arg1, typename DefaultCandidate> +struct associator<Associator, + detail::binder1<Handler, Arg1>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_allocator<Handler, Allocator>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::binder1<Handler, Arg1>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::binder2<Handler, Arg1, Arg2>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static auto get(const detail::binder1<Handler, Arg1>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_allocator<Handler, Allocator>::get(h.handler_, a); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -template <typename Handler, typename Arg1, typename Executor> -struct associated_executor<detail::binder1<Handler, Arg1>, Executor> +template <template <typename, typename> class Associator, + typename Handler, typename Arg1, typename Arg2, + typename DefaultCandidate> +struct associator<Associator, + detail::binder2<Handler, Arg1, Arg2>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_executor<Handler, Executor>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::binder2<Handler, Arg1, Arg2>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::binder1<Handler, Arg1>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get(const detail::binder2<Handler, Arg1, Arg2>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<Handler, Executor>::get(h.handler_, ex); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -template <typename Handler, typename Arg1, typename Arg2, typename Executor> -struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor> +template <template <typename, typename> class Associator, + typename Handler, typename Arg1, typename Arg2, typename Arg3, + typename DefaultCandidate> +struct associator<Associator, + detail::binder3<Handler, Arg1, Arg2, Arg3>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_executor<Handler, Executor>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::binder3<Handler, Arg1, Arg2, Arg3>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::binder2<Handler, Arg1, Arg2>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get(const detail::binder3<Handler, Arg1, Arg2, Arg3>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<Handler, Executor>::get(h.handler_, ex); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -#if defined(ASIO_HAS_MOVE) - -template <typename Handler, typename Arg1, typename Allocator> -struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator> +template <template <typename, typename> class Associator, + typename Handler, typename Arg1, typename Arg2, typename Arg3, + typename Arg4, typename DefaultCandidate> +struct associator<Associator, + detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_allocator<Handler, Allocator>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::move_binder1<Handler, Arg1>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static auto get(const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_allocator<Handler, Allocator>::get(h.handler_, a); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -template <typename Handler, typename Arg1, typename Arg2, typename Allocator> -struct associated_allocator< - detail::move_binder2<Handler, Arg1, Arg2>, Allocator> +template <template <typename, typename> class Associator, + typename Handler, typename Arg1, typename Arg2, typename Arg3, + typename Arg4, typename Arg5, typename DefaultCandidate> +struct associator<Associator, + detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_allocator<Handler, Allocator>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static auto get( + const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_allocator<Handler, Allocator>::get(h.handler_, a); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -template <typename Handler, typename Arg1, typename Executor> -struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor> +template <template <typename, typename> class Associator, + typename Handler, typename Arg1, typename DefaultCandidate> +struct associator<Associator, + detail::move_binder1<Handler, Arg1>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_executor<Handler, Executor>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::move_binder1<Handler, Arg1>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::move_binder1<Handler, Arg1>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get(const detail::move_binder1<Handler, Arg1>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<Handler, Executor>::get(h.handler_, ex); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -template <typename Handler, typename Arg1, typename Arg2, typename Executor> -struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor> +template <template <typename, typename> class Associator, + typename Handler, typename Arg1, typename Arg2, typename DefaultCandidate> +struct associator<Associator, + detail::move_binder2<Handler, Arg1, Arg2>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_executor<Handler, Executor>::type type; + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::move_binder2<Handler, Arg1, Arg2>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } - static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get(const detail::move_binder2<Handler, Arg1, Arg2>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<Handler, Executor>::get(h.handler_, ex); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; -#endif // defined(ASIO_HAS_MOVE) - } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/detail/blocking_executor_op.hpp b/3rdparty/asio/include/asio/detail/blocking_executor_op.hpp new file mode 100644 index 00000000000..c70e562f403 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/blocking_executor_op.hpp @@ -0,0 +1,107 @@ +// +// detail/blocking_executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_BLOCKING_EXECUTOR_OP_HPP +#define ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/scheduler_operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Operation = scheduler_operation> +class blocking_executor_op_base : public Operation +{ +public: + blocking_executor_op_base(typename Operation::func_type complete_func) + : Operation(complete_func), + is_complete_(false) + { + } + + void wait() + { + asio::detail::mutex::scoped_lock lock(mutex_); + while (!is_complete_) + event_.wait(lock); + } + +protected: + struct do_complete_cleanup + { + ~do_complete_cleanup() + { + asio::detail::mutex::scoped_lock lock(op_->mutex_); + op_->is_complete_ = true; + op_->event_.unlock_and_signal_one_for_destruction(lock); + } + + blocking_executor_op_base* op_; + }; + +private: + asio::detail::mutex mutex_; + asio::detail::event event_; + bool is_complete_; +}; + +template <typename Handler, typename Operation = scheduler_operation> +class blocking_executor_op : public blocking_executor_op_base<Operation> +{ +public: + blocking_executor_op(Handler& h) + : blocking_executor_op_base<Operation>(&blocking_executor_op::do_complete), + handler_(h) + { + } + + static void do_complete(void* owner, Operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + ASIO_ASSUME(base != 0); + blocking_executor_op* o(static_cast<blocking_executor_op*>(base)); + + typename blocking_executor_op_base<Operation>::do_complete_cleanup + on_exit = { o }; + (void)on_exit; + + ASIO_HANDLER_COMPLETION((*o)); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN(()); + static_cast<Handler&&>(o->handler_)(); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler& handler_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/buffer_resize_guard.hpp b/3rdparty/asio/include/asio/detail/buffer_resize_guard.hpp index 2768c8a107c..1a78307aaae 100644 --- a/3rdparty/asio/include/asio/detail/buffer_resize_guard.hpp +++ b/3rdparty/asio/include/asio/detail/buffer_resize_guard.hpp @@ -2,7 +2,7 @@ // detail/buffer_resize_guard.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/buffer_sequence_adapter.hpp b/3rdparty/asio/include/asio/detail/buffer_sequence_adapter.hpp index f81e312a47c..8ea904e7023 100644 --- a/3rdparty/asio/include/asio/detail/buffer_sequence_adapter.hpp +++ b/3rdparty/asio/include/asio/detail/buffer_sequence_adapter.hpp @@ -2,7 +2,7 @@ // detail/buffer_sequence_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,7 @@ #include "asio/buffer.hpp" #include "asio/detail/array_fwd.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/registered_buffer.hpp" #include "asio/detail/push_options.hpp" @@ -104,6 +105,9 @@ class buffer_sequence_adapter : buffer_sequence_adapter_base { public: + enum { is_single_buffer = false }; + enum { is_registered_buffer = false }; + explicit buffer_sequence_adapter(const Buffers& buffer_sequence) : count_(0), total_buffer_size_(0) { @@ -127,6 +131,11 @@ public: return total_buffer_size_; } + registered_buffer_id registered_id() const + { + return registered_buffer_id(); + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -153,6 +162,16 @@ public: asio::buffer_sequence_end(buffer_sequence)); } + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const Buffers& buffer_sequence, + const asio::mutable_buffer& storage) + { + return buffer_sequence_adapter::linearise( + asio::buffer_sequence_begin(buffer_sequence), + asio::buffer_sequence_end(buffer_sequence), storage); + } + private: template <typename Iterator> void init(Iterator begin, Iterator end) @@ -201,6 +220,30 @@ private: return Buffer(); } + template <typename Iterator> + static Buffer linearise(Iterator begin, Iterator end, + const asio::mutable_buffer& storage) + { + asio::mutable_buffer unused_storage = storage; + Iterator iter = begin; + while (iter != end && unused_storage.size() != 0) + { + Buffer buffer(*iter); + ++iter; + if (buffer.size() == 0) + continue; + if (unused_storage.size() == storage.size()) + { + if (iter == end) + return buffer; + if (buffer.size() >= unused_storage.size()) + return buffer; + } + unused_storage += asio::buffer_copy(unused_storage, buffer); + } + return Buffer(storage.data(), storage.size() - unused_storage.size()); + } + native_buffer_type buffers_[max_buffers]; std::size_t count_; std::size_t total_buffer_size_; @@ -211,6 +254,9 @@ class buffer_sequence_adapter<Buffer, asio::mutable_buffer> : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + enum { is_registered_buffer = false }; + explicit buffer_sequence_adapter( const asio::mutable_buffer& buffer_sequence) { @@ -233,6 +279,11 @@ public: return total_buffer_size_; } + registered_buffer_id registered_id() const + { + return registered_buffer_id(); + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -253,6 +304,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::mutable_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -263,6 +322,9 @@ class buffer_sequence_adapter<Buffer, asio::const_buffer> : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + enum { is_registered_buffer = false }; + explicit buffer_sequence_adapter( const asio::const_buffer& buffer_sequence) { @@ -285,6 +347,11 @@ public: return total_buffer_size_; } + registered_buffer_id registered_id() const + { + return registered_buffer_id(); + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -305,6 +372,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::const_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -317,6 +392,9 @@ class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1> : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + enum { is_registered_buffer = false }; + explicit buffer_sequence_adapter( const asio::mutable_buffers_1& buffer_sequence) { @@ -339,6 +417,11 @@ public: return total_buffer_size_; } + registered_buffer_id registered_id() const + { + return registered_buffer_id(); + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -359,6 +442,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::mutable_buffers_1& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -369,6 +460,9 @@ class buffer_sequence_adapter<Buffer, asio::const_buffers_1> : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + enum { is_registered_buffer = false }; + explicit buffer_sequence_adapter( const asio::const_buffers_1& buffer_sequence) { @@ -391,6 +485,11 @@ public: return total_buffer_size_; } + registered_buffer_id registered_id() const + { + return registered_buffer_id(); + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -411,6 +510,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const asio::const_buffers_1& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -418,11 +525,162 @@ private: #endif // !defined(ASIO_NO_DEPRECATED) +template <typename Buffer> +class buffer_sequence_adapter<Buffer, asio::mutable_registered_buffer> + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = true }; + enum { is_registered_buffer = true }; + + explicit buffer_sequence_adapter( + const asio::mutable_registered_buffer& buffer_sequence) + { + init_native_buffer(buffer_, buffer_sequence.buffer()); + total_buffer_size_ = buffer_sequence.size(); + registered_id_ = buffer_sequence.id(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + registered_buffer_id registered_id() const + { + return registered_id_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty( + const asio::mutable_registered_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate( + const asio::mutable_registered_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first( + const asio::mutable_registered_buffer& buffer_sequence) + { + return Buffer(buffer_sequence.buffer()); + } + + enum { linearisation_storage_size = 1 }; + + static Buffer linearise( + const asio::mutable_registered_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence.buffer()); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; + registered_buffer_id registered_id_; +}; + +template <typename Buffer> +class buffer_sequence_adapter<Buffer, asio::const_registered_buffer> + : buffer_sequence_adapter_base +{ +public: + enum { is_single_buffer = true }; + enum { is_registered_buffer = true }; + + explicit buffer_sequence_adapter( + const asio::const_registered_buffer& buffer_sequence) + { + init_native_buffer(buffer_, buffer_sequence.buffer()); + total_buffer_size_ = buffer_sequence.size(); + registered_id_ = buffer_sequence.id(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + registered_buffer_id registered_id() const + { + return registered_id_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty( + const asio::const_registered_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate( + const asio::const_registered_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first( + const asio::const_registered_buffer& buffer_sequence) + { + return Buffer(buffer_sequence.buffer()); + } + + enum { linearisation_storage_size = 1 }; + + static Buffer linearise( + const asio::const_registered_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence.buffer()); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; + registered_buffer_id registered_id_; +}; + template <typename Buffer, typename Elem> -class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> > +class buffer_sequence_adapter<Buffer, boost::array<Elem, 2>> : buffer_sequence_adapter_base { public: + enum { is_single_buffer = false }; + enum { is_registered_buffer = false }; + explicit buffer_sequence_adapter( const boost::array<Elem, 2>& buffer_sequence) { @@ -446,6 +704,11 @@ public: return total_buffer_size_; } + registered_buffer_id registered_id() const + { + return registered_buffer_id(); + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -468,18 +731,32 @@ public: ? buffer_sequence[0] : buffer_sequence[1]); } + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence, + const asio::mutable_buffer& storage) + { + if (buffer_sequence[0].size() == 0) + return Buffer(buffer_sequence[1]); + if (buffer_sequence[1].size() == 0) + return Buffer(buffer_sequence[0]); + return Buffer(storage.data(), + asio::buffer_copy(storage, buffer_sequence)); + } + private: native_buffer_type buffers_[2]; std::size_t total_buffer_size_; }; -#if defined(ASIO_HAS_STD_ARRAY) - template <typename Buffer, typename Elem> -class buffer_sequence_adapter<Buffer, std::array<Elem, 2> > +class buffer_sequence_adapter<Buffer, std::array<Elem, 2>> : buffer_sequence_adapter_base { public: + enum { is_single_buffer = false }; + enum { is_registered_buffer = false }; + explicit buffer_sequence_adapter( const std::array<Elem, 2>& buffer_sequence) { @@ -503,6 +780,11 @@ public: return total_buffer_size_; } + registered_buffer_id registered_id() const + { + return registered_buffer_id(); + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -525,13 +807,24 @@ public: ? buffer_sequence[0] : buffer_sequence[1]); } + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const std::array<Elem, 2>& buffer_sequence, + const asio::mutable_buffer& storage) + { + if (buffer_sequence[0].size() == 0) + return Buffer(buffer_sequence[1]); + if (buffer_sequence[1].size() == 0) + return Buffer(buffer_sequence[0]); + return Buffer(storage.data(), + asio::buffer_copy(storage, buffer_sequence)); + } + private: native_buffer_type buffers_[2]; std::size_t total_buffer_size_; }; -#endif // defined(ASIO_HAS_STD_ARRAY) - } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/buffered_stream_storage.hpp b/3rdparty/asio/include/asio/detail/buffered_stream_storage.hpp index a71120dca41..afe5cadffda 100644 --- a/3rdparty/asio/include/asio/detail/buffered_stream_storage.hpp +++ b/3rdparty/asio/include/asio/detail/buffered_stream_storage.hpp @@ -2,7 +2,7 @@ // detail/buffered_stream_storage.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/call_stack.hpp b/3rdparty/asio/include/asio/detail/call_stack.hpp index 9835e64aa18..c287c57e2c6 100644 --- a/3rdparty/asio/include/asio/detail/call_stack.hpp +++ b/3rdparty/asio/include/asio/detail/call_stack.hpp @@ -2,7 +2,7 @@ // detail/call_stack.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/chrono.hpp b/3rdparty/asio/include/asio/detail/chrono.hpp index 31d6c6e7dfd..45490dde02e 100644 --- a/3rdparty/asio/include/asio/detail/chrono.hpp +++ b/3rdparty/asio/include/asio/detail/chrono.hpp @@ -2,7 +2,7 @@ // detail/chrono.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,17 +16,11 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_CHRONO) -# include <chrono> -#elif defined(ASIO_HAS_BOOST_CHRONO) -# include <boost/chrono/system_clocks.hpp> -#endif // defined(ASIO_HAS_BOOST_CHRONO) +#include <chrono> namespace asio { namespace chrono { -#if defined(ASIO_HAS_STD_CHRONO) using std::chrono::duration; using std::chrono::time_point; using std::chrono::duration_cast; @@ -44,21 +38,6 @@ using std::chrono::steady_clock; #endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) using std::chrono::system_clock; using std::chrono::high_resolution_clock; -#elif defined(ASIO_HAS_BOOST_CHRONO) -using boost::chrono::duration; -using boost::chrono::time_point; -using boost::chrono::duration_cast; -using boost::chrono::nanoseconds; -using boost::chrono::microseconds; -using boost::chrono::milliseconds; -using boost::chrono::seconds; -using boost::chrono::minutes; -using boost::chrono::hours; -using boost::chrono::time_point_cast; -using boost::chrono::system_clock; -using boost::chrono::steady_clock; -using boost::chrono::high_resolution_clock; -#endif // defined(ASIO_HAS_BOOST_CHRONO) } // namespace chrono } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/chrono_time_traits.hpp b/3rdparty/asio/include/asio/detail/chrono_time_traits.hpp index b6236a5001f..de7b7d69929 100644 --- a/3rdparty/asio/include/asio/detail/chrono_time_traits.hpp +++ b/3rdparty/asio/include/asio/detail/chrono_time_traits.hpp @@ -2,7 +2,7 @@ // detail/chrono_time_traits.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/completion_handler.hpp b/3rdparty/asio/include/asio/detail/completion_handler.hpp index e510dedfbcb..c6f98b36c38 100644 --- a/3rdparty/asio/include/asio/detail/completion_handler.hpp +++ b/3rdparty/asio/include/asio/detail/completion_handler.hpp @@ -2,7 +2,7 @@ // detail/completion_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -27,17 +27,17 @@ namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class completion_handler : public operation { public: ASIO_DEFINE_HANDLER_PTR(completion_handler); - completion_handler(Handler& h) + completion_handler(Handler& h, const IoExecutor& io_ex) : operation(&completion_handler::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(h)) + handler_(static_cast<Handler&&>(h)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -47,17 +47,21 @@ public: // Take ownership of the handler object. completion_handler* h(static_cast<completion_handler*>(base)); ptr p = { asio::detail::addressof(h->handler_), h, h }; - handler_work<Handler> w(h->handler_); ASIO_HANDLER_COMPLETION((*h)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + h->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. - Handler handler(ASIO_MOVE_CAST(Handler)(h->handler_)); + Handler handler(static_cast<Handler&&>(h->handler_)); p.h = asio::detail::addressof(handler); p.reset(); @@ -73,6 +77,7 @@ public: private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/composed_work.hpp b/3rdparty/asio/include/asio/detail/composed_work.hpp new file mode 100644 index 00000000000..8076f8508d6 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/composed_work.hpp @@ -0,0 +1,252 @@ +// +// detail/composed_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_COMPOSED_WORK_HPP +#define ASIO_DETAIL_COMPOSED_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/is_executor.hpp" +#include "asio/system_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Executor, typename = void> +class composed_work_guard +{ +public: + typedef decay_t< + prefer_result_t<Executor, execution::outstanding_work_t::tracked_t> + > executor_type; + + composed_work_guard(const Executor& ex) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + void reset() + { + } + + executor_type get_executor() const noexcept + { + return executor_; + } + +private: + executor_type executor_; +}; + +template <> +struct composed_work_guard<system_executor> +{ +public: + typedef system_executor executor_type; + + composed_work_guard(const system_executor&) + { + } + + void reset() + { + } + + executor_type get_executor() const noexcept + { + return system_executor(); + } +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor> +struct composed_work_guard<Executor, + enable_if_t< + !execution::is_executor<Executor>::value + > + > : executor_work_guard<Executor> +{ + composed_work_guard(const Executor& ex) + : executor_work_guard<Executor>(ex) + { + } +}; + +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +template <typename> +struct composed_io_executors; + +template <> +struct composed_io_executors<void()> +{ + composed_io_executors() noexcept + : head_(system_executor()) + { + } + + typedef system_executor head_type; + system_executor head_; +}; + +inline composed_io_executors<void()> make_composed_io_executors() +{ + return composed_io_executors<void()>(); +} + +template <typename Head> +struct composed_io_executors<void(Head)> +{ + explicit composed_io_executors(const Head& ex) noexcept + : head_(ex) + { + } + + typedef Head head_type; + Head head_; +}; + +template <typename Head> +inline composed_io_executors<void(Head)> +make_composed_io_executors(const Head& head) +{ + return composed_io_executors<void(Head)>(head); +} + +template <typename Head, typename... Tail> +struct composed_io_executors<void(Head, Tail...)> +{ + explicit composed_io_executors(const Head& head, + const Tail&... tail) noexcept + : head_(head), + tail_(tail...) + { + } + + void reset() + { + head_.reset(); + tail_.reset(); + } + + typedef Head head_type; + Head head_; + composed_io_executors<void(Tail...)> tail_; +}; + +template <typename Head, typename... Tail> +inline composed_io_executors<void(Head, Tail...)> +make_composed_io_executors(const Head& head, const Tail&... tail) +{ + return composed_io_executors<void(Head, Tail...)>(head, tail...); +} + +template <typename> +struct composed_work; + +template <> +struct composed_work<void()> +{ + typedef composed_io_executors<void()> executors_type; + + composed_work(const executors_type&) noexcept + : head_(system_executor()) + { + } + + void reset() + { + head_.reset(); + } + + typedef system_executor head_type; + composed_work_guard<system_executor> head_; +}; + +template <typename Head> +struct composed_work<void(Head)> +{ + typedef composed_io_executors<void(Head)> executors_type; + + explicit composed_work(const executors_type& ex) noexcept + : head_(ex.head_) + { + } + + void reset() + { + head_.reset(); + } + + typedef Head head_type; + composed_work_guard<Head> head_; +}; + +template <typename Head, typename... Tail> +struct composed_work<void(Head, Tail...)> +{ + typedef composed_io_executors<void(Head, Tail...)> executors_type; + + explicit composed_work(const executors_type& ex) noexcept + : head_(ex.head_), + tail_(ex.tail_) + { + } + + void reset() + { + head_.reset(); + tail_.reset(); + } + + typedef Head head_type; + composed_work_guard<Head> head_; + composed_work<void(Tail...)> tail_; +}; + +template <typename IoObject> +inline typename IoObject::executor_type +get_composed_io_executor(IoObject& io_object, + enable_if_t< + !is_executor<IoObject>::value + >* = 0, + enable_if_t< + !execution::is_executor<IoObject>::value + >* = 0) +{ + return io_object.get_executor(); +} + +template <typename Executor> +inline const Executor& get_composed_io_executor(const Executor& ex, + enable_if_t< + is_executor<Executor>::value + || execution::is_executor<Executor>::value + >* = 0) +{ + return ex; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_COMPOSED_WORK_HPP diff --git a/3rdparty/asio/include/asio/detail/concurrency_hint.hpp b/3rdparty/asio/include/asio/detail/concurrency_hint.hpp index 75480932577..43e81a4c22d 100644 --- a/3rdparty/asio/include/asio/detail/concurrency_hint.hpp +++ b/3rdparty/asio/include/asio/detail/concurrency_hint.hpp @@ -2,7 +2,7 @@ // detail/concurrency_hint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -26,8 +26,12 @@ // If set, this bit indicates that the scheduler should perform locking. #define ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u -// If set, this bit indicates that the reactor should perform locking. -#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR 0x2u +// If set, this bit indicates that the reactor should perform locking when +// managing descriptor registrations. +#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u + +// If set, this bit indicates that the reactor should perform locking for I/O. +#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u // Helper macro to determine if we have a special concurrency hint. #define ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \ @@ -64,13 +68,15 @@ // timers), occur in only one thread at a time. #define ASIO_CONCURRENCY_HINT_UNSAFE_IO \ static_cast<int>(ASIO_CONCURRENCY_HINT_ID \ - | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER) + | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION) // The special concurrency hint provides full thread safety. #define ASIO_CONCURRENCY_HINT_SAFE \ static_cast<int>(ASIO_CONCURRENCY_HINT_ID \ | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ - | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR) + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \ + | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO) // This #define may be overridden at compile time to specify a program-wide // default concurrency hint, used by the zero-argument io_context constructor. diff --git a/3rdparty/asio/include/asio/detail/conditionally_enabled_event.hpp b/3rdparty/asio/include/asio/detail/conditionally_enabled_event.hpp index 7ce806a2358..af68dde32c0 100644 --- a/3rdparty/asio/include/asio/detail/conditionally_enabled_event.hpp +++ b/3rdparty/asio/include/asio/detail/conditionally_enabled_event.hpp @@ -2,7 +2,7 @@ // detail/conditionally_enabled_event.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -64,6 +64,14 @@ public: event_.unlock_and_signal_one(lock); } + // Unlock the mutex and signal one waiter who may destroy us. + void unlock_and_signal_one_for_destruction( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.unlock_and_signal_one(lock); + } + // If there's a waiter, unlock the mutex and signal it. bool maybe_unlock_and_signal_one( conditionally_enabled_mutex::scoped_lock& lock) diff --git a/3rdparty/asio/include/asio/detail/conditionally_enabled_mutex.hpp b/3rdparty/asio/include/asio/detail/conditionally_enabled_mutex.hpp index 39c168764b3..27fc30ecbb2 100644 --- a/3rdparty/asio/include/asio/detail/conditionally_enabled_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/conditionally_enabled_mutex.hpp @@ -2,7 +2,7 @@ // detail/conditionally_enabled_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/config.hpp b/3rdparty/asio/include/asio/detail/config.hpp index 0c651bed71d..cd345eac2cd 100644 --- a/3rdparty/asio/include/asio/detail/config.hpp +++ b/3rdparty/asio/include/asio/detail/config.hpp @@ -2,7 +2,7 @@ // detail/config.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -11,7 +11,33 @@ #ifndef ASIO_DETAIL_CONFIG_HPP #define ASIO_DETAIL_CONFIG_HPP +// boostify: non-boost code starts here +#if !defined(ASIO_STANDALONE) +# if !defined(ASIO_ENABLE_BOOST) +# if (__cplusplus >= 201103) +# define ASIO_STANDALONE 1 +# elif defined(_MSC_VER) && defined(_MSVC_LANG) +# if (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103) +# define ASIO_STANDALONE 1 +# endif // (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103) +# endif // defined(_MSC_VER) && defined(_MSVC_LANG) +# endif // !defined(ASIO_ENABLE_BOOST) +#endif // !defined(ASIO_STANDALONE) + +// Make standard library feature macros available. +#if defined(__has_include) +# if __has_include(<version>) +# include <version> +# else // __has_include(<version>) +# include <cstddef> +# endif // __has_include(<version>) +#else // defined(__has_include) +# include <cstddef> +#endif // defined(__has_include) + +// boostify: non-boost code ends here #if defined(ASIO_STANDALONE) +# define ASIO_DISABLE_BOOST_ALIGN 1 # define ASIO_DISABLE_BOOST_ARRAY 1 # define ASIO_DISABLE_BOOST_ASSERT 1 # define ASIO_DISABLE_BOOST_BIND 1 @@ -23,6 +49,7 @@ # define ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 # define ASIO_DISABLE_BOOST_WORKAROUND 1 #else // defined(ASIO_STANDALONE) +// Boost.Config library is available. # include <boost/config.hpp> # include <boost/version.hpp> # define ASIO_HAS_BOOST_CONFIG 1 @@ -61,6 +88,9 @@ # define ASIO_DECL #endif // !defined(ASIO_DECL) +// Helper macro for documentation. +#define ASIO_UNSPECIFIED(e) e + // Microsoft Visual C++ detection. #if !defined(ASIO_MSVC) # if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) @@ -69,7 +99,7 @@ || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) # define ASIO_MSVC _MSC_VER # endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) -#endif // defined(ASIO_MSVC) +#endif // !defined(ASIO_MSVC) // Clang / libc++ detection. #if defined(__clang__) @@ -83,375 +113,323 @@ # endif // (__cplusplus >= 201103) #endif // defined(__clang__) -// Support move construction and assignment on compilers known to allow it. -#if !defined(ASIO_HAS_MOVE) -# if !defined(ASIO_DISABLE_MOVE) -# if defined(__clang__) -# if __has_feature(__cxx_rvalue_references__) -# define ASIO_HAS_MOVE 1 -# endif // __has_feature(__cxx_rvalue_references__) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_MOVE 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_MOVE 1 -# endif // (_MSC_VER >= 1700) -# endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_MOVE) -#endif // !defined(ASIO_HAS_MOVE) +// Android platform detection. +#if defined(__ANDROID__) +# include <android/api-level.h> +#endif // defined(__ANDROID__) -// If ASIO_MOVE_CAST isn't defined, and move support is available, define -// ASIO_MOVE_ARG and ASIO_MOVE_CAST to take advantage of rvalue -// references and perfect forwarding. -#if defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST) +// Always enabled. Retained for backwards compatibility in user code. +#if !defined(ASIO_DISABLE_CXX11_MACROS) +# define ASIO_HAS_MOVE 1 # define ASIO_MOVE_ARG(type) type&& # define ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define ASIO_NONDEDUCED_MOVE_ARG(type) type& # define ASIO_MOVE_CAST(type) static_cast<type&&> # define ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&> -#endif // defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST) - -// If ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible -// implementation. Note that older g++ and MSVC versions don't like it when you -// pass a non-member function through a const reference, so for most compilers -// we'll play it safe and stick with the old approach of passing the handler by -// value. -#if !defined(ASIO_MOVE_CAST) +# define ASIO_MOVE_OR_LVALUE(type) static_cast<type&&> +# define ASIO_MOVE_OR_LVALUE_ARG(type) type&& +# define ASIO_MOVE_OR_LVALUE_TYPE(type) type +# define ASIO_DELETED = delete +# define ASIO_HAS_VARIADIC_TEMPLATES 1 +# define ASIO_HAS_CONSTEXPR 1 +# define ASIO_STATIC_CONSTEXPR(type, assignment) \ + static constexpr type assignment +# define ASIO_HAS_NOEXCEPT 1 +# define ASIO_NOEXCEPT noexcept(true) +# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# define ASIO_NOEXCEPT_IF(c) noexcept(c) +# define ASIO_HAS_DECLTYPE 1 +# define ASIO_AUTO_RETURN_TYPE_PREFIX(t) auto +# define ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) auto +# define ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) auto +# define ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) -> decltype expr +# define ASIO_HAS_ALIAS_TEMPLATES 1 +# define ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# define ASIO_HAS_ENUM_CLASS 1 +# define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# define ASIO_LVALUE_REF_QUAL & +# define ASIO_RVALUE_REF_QUAL && +# define ASIO_HAS_USER_DEFINED_LITERALS 1 +# define ASIO_HAS_ALIGNOF 1 +# define ASIO_ALIGNOF(T) alignof(T) +# define ASIO_HAS_STD_ALIGN 1 +# define ASIO_HAS_STD_SYSTEM_ERROR 1 +# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# define ASIO_HAS_STD_ARRAY 1 +# define ASIO_HAS_STD_SHARED_PTR 1 +# define ASIO_HAS_STD_ALLOCATOR_ARG 1 +# define ASIO_HAS_STD_ATOMIC 1 +# define ASIO_HAS_STD_CHRONO 1 +# define ASIO_HAS_STD_ADDRESSOF 1 +# define ASIO_HAS_STD_FUNCTION 1 +# define ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# define ASIO_HAS_STD_TYPE_TRAITS 1 +# define ASIO_HAS_NULLPTR 1 +# define ASIO_HAS_CXX11_ALLOCATORS 1 +# define ASIO_HAS_CSTDINT 1 +# define ASIO_HAS_STD_THREAD 1 +# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# define ASIO_HAS_STD_CALL_ONCE 1 +# define ASIO_HAS_STD_FUTURE 1 +# define ASIO_HAS_STD_TUPLE 1 +# define ASIO_HAS_STD_IOSTREAM_MOVE 1 +# define ASIO_HAS_STD_EXCEPTION_PTR 1 +# define ASIO_HAS_STD_NESTED_EXCEPTION 1 +# define ASIO_HAS_STD_HASH 1 +#endif // !defined(ASIO_DISABLE_CXX11_MACROS) + +// Support for static constexpr with default initialisation. +#if !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) # if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) -# define ASIO_MOVE_ARG(type) const type& -# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) -# define ASIO_MOVE_ARG(type) type -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# if (__GNUC__ >= 8) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# else // (__GNUC__ >= 8) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // (__GNUC__ >= 8) # elif defined(ASIO_MSVC) -# if (_MSC_VER >= 1400) -# define ASIO_MOVE_ARG(type) const type& -# else // (_MSC_VER >= 1400) -# define ASIO_MOVE_ARG(type) type -# endif // (_MSC_VER >= 1400) -# else -# define ASIO_MOVE_ARG(type) type -# endif -# define ASIO_MOVE_CAST(type) static_cast<const type&> -# define ASIO_MOVE_CAST2(type1, type2) static_cast<const type1, type2&> -#endif // !defined(ASIO_MOVE_CAST) - -// Support variadic templates on compilers known to allow it. -#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) -# if !defined(ASIO_DISABLE_VARIADIC_TEMPLATES) -# if defined(__clang__) -# if __has_feature(__cxx_variadic_templates__) -# define ASIO_HAS_VARIADIC_TEMPLATES 1 -# endif // __has_feature(__cxx_variadic_templates__) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_VARIADIC_TEMPLATES 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# endif // !defined(ASIO_DISABLE_VARIADIC_TEMPLATES) -#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# else // defined(ASIO_MSVC) +# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# endif // defined(ASIO_MSVC) +#endif // !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) -// Support deleted functions on compilers known to allow it. -#if !defined(ASIO_DELETED) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_DELETED = delete -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(__clang__) -# if __has_feature(__cxx_deleted_functions__) -# define ASIO_DELETED = delete -# endif // __has_feature(__cxx_deleted_functions__) -# endif // defined(__clang__) -# if !defined(ASIO_DELETED) -# define ASIO_DELETED -# endif // !defined(ASIO_DELETED) -#endif // !defined(ASIO_DELETED) - -// Support constexpr on compilers known to allow it. -#if !defined(ASIO_HAS_CONSTEXPR) -# if !defined(ASIO_DISABLE_CONSTEXPR) +// Support noexcept on function types on compilers known to allow it. +#if !defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) +# if !defined(ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) # if defined(__clang__) -# if __has_feature(__cxx_constexpr__) -# define ASIO_HAS_CONSTEXPR 1 -# endif // __has_feature(__cxx_constexr__) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_CONSTEXPR 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# endif // !defined(ASIO_DISABLE_CONSTEXPR) -#endif // !defined(ASIO_HAS_CONSTEXPR) -#if !defined(ASIO_CONSTEXPR) -# if defined(ASIO_HAS_CONSTEXPR) -# define ASIO_CONSTEXPR constexpr -# else // defined(ASIO_HAS_CONSTEXPR) -# define ASIO_CONSTEXPR -# endif // defined(ASIO_HAS_CONSTEXPR) -#endif // !defined(ASIO_CONSTEXPR) - -// Support noexcept on compilers known to allow it. -#if !defined(ASIO_NOEXCEPT) -# if !defined(ASIO_DISABLE_NOEXCEPT) -# if (BOOST_VERSION >= 105300) -# define ASIO_NOEXCEPT BOOST_NOEXCEPT -# define ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW -# elif defined(__clang__) -# if __has_feature(__cxx_noexcept__) -# define ASIO_NOEXCEPT noexcept(true) -# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) -# endif // __has_feature(__cxx_noexcept__) +# if (__cplusplus >= 202002) +# define ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) # elif defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_NOEXCEPT noexcept(true) -# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 202002) +# define ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) # elif defined(ASIO_MSVC) -# if (_MSC_VER >= 1900) -# define ASIO_NOEXCEPT noexcept(true) -# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) -# endif // (_MSC_VER >= 1900) -# endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_NOEXCEPT) -# if !defined(ASIO_NOEXCEPT) -# define ASIO_NOEXCEPT -# endif // !defined(ASIO_NOEXCEPT) -# if !defined(ASIO_NOEXCEPT_OR_NOTHROW) -# define ASIO_NOEXCEPT_OR_NOTHROW throw() -# endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW) -#endif // !defined(ASIO_NOEXCEPT) - -// Support automatic type deduction on compilers known to support it. -#if !defined(ASIO_HAS_DECLTYPE) -# if !defined(ASIO_DISABLE_DECLTYPE) -# if defined(__clang__) -# if __has_feature(__cxx_decltype__) -# define ASIO_HAS_DECLTYPE 1 -# endif // __has_feature(__cxx_decltype__) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_DECLTYPE 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_DECLTYPE 1 -# endif // (_MSC_VER >= 1700) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# define ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_DECLTYPE) -#endif // !defined(ASIO_HAS_DECLTYPE) +# endif // !defined(ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +#endif // !defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) -// Standard library support for system errors. -#if !defined(ASIO_HAS_STD_SYSTEM_ERROR) -# if !defined(ASIO_DISABLE_STD_SYSTEM_ERROR) +// Support return type deduction on compilers known to allow it. +#if !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION) +# if !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_SYSTEM_ERROR 1 -# elif (__cplusplus >= 201103) -# if __has_include(<system_error>) -# define ASIO_HAS_STD_SYSTEM_ERROR 1 -# endif // __has_include(<system_error>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_SYSTEM_ERROR 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_SYSTEM_ERROR 1 -# endif // (_MSC_VER >= 1700) +# if __has_feature(__cxx_return_type_deduction__) +# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // __has_feature(__cxx_return_type_deduction__) +# elif (__cplusplus >= 201402) +# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# elif defined(__cpp_return_type_deduction) +# if (__cpp_return_type_deduction >= 201304) +# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (__cpp_return_type_deduction >= 201304) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_SYSTEM_ERROR) -#endif // !defined(ASIO_HAS_STD_SYSTEM_ERROR) - -// Compliant C++11 compilers put noexcept specifiers on error_category members. -#if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) -# if (BOOST_VERSION >= 105300) -# define ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT -# elif defined(__clang__) -# if __has_feature(__cxx_noexcept__) -# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) -# endif // __has_feature(__cxx_noexcept__) -# elif defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# elif defined(ASIO_MSVC) -# if (_MSC_VER >= 1900) -# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) -# endif // (_MSC_VER >= 1900) -# endif // defined(ASIO_MSVC) -# if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) -# define ASIO_ERROR_CATEGORY_NOEXCEPT -# endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) -#endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT) - -// Standard library support for arrays. -#if !defined(ASIO_HAS_STD_ARRAY) -# if !defined(ASIO_DISABLE_STD_ARRAY) +# endif // !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +#endif // !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION) + +// Support concepts on compilers known to allow them. +#if !defined(ASIO_HAS_CONCEPTS) +# if !defined(ASIO_DISABLE_CONCEPTS) +# if defined(__cpp_concepts) +# define ASIO_HAS_CONCEPTS 1 +# if (__cpp_concepts >= 201707) +# define ASIO_CONCEPT concept +# else // (__cpp_concepts >= 201707) +# define ASIO_CONCEPT concept bool +# endif // (__cpp_concepts >= 201707) +# endif // defined(__cpp_concepts) +# endif // !defined(ASIO_DISABLE_CONCEPTS) +#endif // !defined(ASIO_HAS_CONCEPTS) + +// Support concepts on compilers known to allow them. +#if !defined(ASIO_HAS_STD_CONCEPTS) +# if !defined(ASIO_DISABLE_STD_CONCEPTS) +# if defined(ASIO_HAS_CONCEPTS) +# if (__cpp_lib_concepts >= 202002L) +# define ASIO_HAS_STD_CONCEPTS 1 +# endif // (__cpp_concepts >= 202002L) +# endif // defined(ASIO_HAS_CONCEPTS) +# endif // !defined(ASIO_DISABLE_STD_CONCEPTS) +#endif // !defined(ASIO_HAS_STD_CONCEPTS) + +// Support template variables on compilers known to allow it. +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) +# if !defined(ASIO_DISABLE_VARIABLE_TEMPLATES) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_ARRAY 1 -# elif (__cplusplus >= 201103) -# if __has_include(<array>) -# define ASIO_HAS_STD_ARRAY 1 -# endif // __has_include(<array>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_ARRAY 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) +# if (__cplusplus >= 201402) +# if __has_feature(__cxx_variable_templates__) +# define ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201402) +# define ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1600) -# define ASIO_HAS_STD_ARRAY 1 -# endif // (_MSC_VER >= 1600) +# if (_MSC_VER >= 1901) +# define ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_ARRAY) -#endif // !defined(ASIO_HAS_STD_ARRAY) +# endif // !defined(ASIO_DISABLE_VARIABLE_TEMPLATES) +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) -// Standard library support for shared_ptr and weak_ptr. -#if !defined(ASIO_HAS_STD_SHARED_PTR) -# if !defined(ASIO_DISABLE_STD_SHARED_PTR) +// Support SFINAEd template variables on compilers known to allow it. +#if !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +# if !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_SHARED_PTR 1 -# elif (__cplusplus >= 201103) -# define ASIO_HAS_STD_SHARED_PTR 1 -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_SHARED_PTR 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if (__cplusplus >= 201703) +# if __has_feature(__cxx_variable_templates__) +# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# if (__cplusplus >= 201402) +# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) # endif // defined(__GNUC__) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1600) -# define ASIO_HAS_STD_SHARED_PTR 1 -# endif // (_MSC_VER >= 1600) +# if (_MSC_VER >= 1901) +# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_SHARED_PTR) -#endif // !defined(ASIO_HAS_STD_SHARED_PTR) +# endif // !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +#endif // !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) -// Standard library support for allocator_arg_t. -#if !defined(ASIO_HAS_STD_ALLOCATOR_ARG) -# if !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG) +// Support SFINAE use of constant expressions on compilers known to allow it. +#if !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) +# if !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_ALLOCATOR_ARG 1 -# elif (__cplusplus >= 201103) -# define ASIO_HAS_STD_ALLOCATOR_ARG 1 -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_ALLOCATOR_ARG 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) +# if (__cplusplus >= 201402) +# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1600) -# define ASIO_HAS_STD_ALLOCATOR_ARG 1 -# endif // (_MSC_VER >= 1600) +# if (_MSC_VER >= 1901) +# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (_MSC_VER >= 1901) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG) -#endif // !defined(ASIO_HAS_STD_ALLOCATOR_ARG) +# endif // !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +#endif // !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) -// Standard library support for atomic operations. -#if !defined(ASIO_HAS_STD_ATOMIC) -# if !defined(ASIO_DISABLE_STD_ATOMIC) -# if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_ATOMIC 1 -# elif (__cplusplus >= 201103) -# if __has_include(<atomic>) -# define ASIO_HAS_STD_ATOMIC 1 -# endif // __has_include(<atomic>) +// Enable workarounds for lack of working expression SFINAE. +#if !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# if !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +# if !defined(ASIO_MSVC) && !defined(__INTEL_COMPILER) +# if (__cplusplus >= 201103) +# define ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 # endif // (__cplusplus >= 201103) -# endif // defined(__clang__) +# elif defined(ASIO_MSVC) && (_MSC_VER >= 1929) +# if (_MSVC_LANG >= 202000) +# define ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (_MSVC_LANG >= 202000) +# endif // defined(ASIO_MSVC) && (_MSC_VER >= 1929) +# endif // !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +#endif // !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +// Support for capturing parameter packs in lambdas. +#if !defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) +# if !defined(ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) # if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_ATOMIC 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_ATOMIC 1 -# endif // (_MSC_VER >= 1700) -# endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_ATOMIC) -#endif // !defined(ASIO_HAS_STD_ATOMIC) - -// Standard library support for chrono. Some standard libraries (such as the -// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x -// drafts, rather than the eventually standardised name of steady_clock. -#if !defined(ASIO_HAS_STD_CHRONO) -# if !defined(ASIO_DISABLE_STD_CHRONO) -# if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_CHRONO 1 -# elif (__cplusplus >= 201103) -# if __has_include(<chrono>) -# define ASIO_HAS_STD_CHRONO 1 -# endif // __has_include(<chrono>) +# if (__GNUC__ >= 6) +# define ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__GNUC__ >= 6) +# elif defined(ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (_MSC_LANG >= 201103) +# else // defined(ASIO_MSVC) +# if (__cplusplus >= 201103) +# define ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 # endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_CHRONO 1 -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) -# define ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_CHRONO 1 -# endif // (_MSC_VER >= 1700) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_CHRONO) -#endif // !defined(ASIO_HAS_STD_CHRONO) +# endif // !defined(ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +#endif // !defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) + +// Default alignment. +#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) +# define ASIO_DEFAULT_ALIGN __STDCPP_DEFAULT_NEW_ALIGNMENT__ +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define ASIO_DEFAULT_ALIGN alignof(max_align_t) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +#else // defined(__GNUC__) +# define ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +#endif // defined(__GNUC__) + +// Standard library support for aligned allocation. +#if !defined(ASIO_HAS_STD_ALIGNED_ALLOC) +# if !defined(ASIO_DISABLE_STD_ALIGNED_ALLOC) +# if (__cplusplus >= 201703) +# if defined(__clang__) +# if defined(ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) \ + && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# if defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# define ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +# if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# define ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__TV_OS_VERSION_MIN_REQUIRED) +# if (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# define ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__WATCH_OS_VERSION_MIN_REQUIRED) +# if (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# define ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# endif // defined(__WATCH_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__APPLE__) +# define ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(__APPLE__) +# endif // (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) + // && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# elif defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# elif defined(__GNUC__) +# if ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# if defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# endif // ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# endif // defined(__GNUC__) +# endif // (__cplusplus >= 201703) +# endif // !defined(ASIO_DISABLE_STD_ALIGNED_ALLOC) +#endif // !defined(ASIO_HAS_STD_ALIGNED_ALLOC) // Boost support for chrono. #if !defined(ASIO_HAS_BOOST_CHRONO) # if !defined(ASIO_DISABLE_BOOST_CHRONO) -# if (BOOST_VERSION >= 104700) +# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) # define ASIO_HAS_BOOST_CHRONO 1 -# endif // (BOOST_VERSION >= 104700) +# endif // defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) # endif // !defined(ASIO_DISABLE_BOOST_CHRONO) #endif // !defined(ASIO_HAS_BOOST_CHRONO) @@ -471,276 +449,250 @@ # endif // !defined(ASIO_DISABLE_BOOST_DATE_TIME) #endif // !defined(ASIO_HAS_BOOST_DATE_TIME) -// Standard library support for addressof. -#if !defined(ASIO_HAS_STD_ADDRESSOF) -# if !defined(ASIO_DISABLE_STD_ADDRESSOF) -# if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_ADDRESSOF 1 -# elif (__cplusplus >= 201103) -# define ASIO_HAS_STD_ADDRESSOF 1 -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_ADDRESSOF 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_ADDRESSOF 1 -# endif // (_MSC_VER >= 1700) -# endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_ADDRESSOF) -#endif // !defined(ASIO_HAS_STD_ADDRESSOF) +// Boost support for the Coroutine library. +#if !defined(ASIO_HAS_BOOST_COROUTINE) +# if !defined(ASIO_DISABLE_BOOST_COROUTINE) +# define ASIO_HAS_BOOST_COROUTINE 1 +# endif // !defined(ASIO_DISABLE_BOOST_COROUTINE) +#endif // !defined(ASIO_HAS_BOOST_COROUTINE) -// Standard library support for the function class. -#if !defined(ASIO_HAS_STD_FUNCTION) -# if !defined(ASIO_DISABLE_STD_FUNCTION) +// Boost support for the Context library's fibers. +#if !defined(ASIO_HAS_BOOST_CONTEXT_FIBER) +# if !defined(ASIO_DISABLE_BOOST_CONTEXT_FIBER) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_FUNCTION 1 -# elif (__cplusplus >= 201103) -# define ASIO_HAS_STD_FUNCTION 1 +# if (__cplusplus >= 201103) +# define ASIO_HAS_BOOST_CONTEXT_FIBER 1 # endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_FUNCTION 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) # endif // defined(__GNUC__) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_FUNCTION 1 -# endif // (_MSC_VER >= 1700) +# if (_MSVC_LANG >= 201103) +# define ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (_MSC_LANG >= 201103) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_FUNCTION) -#endif // !defined(ASIO_HAS_STD_FUNCTION) +# endif // !defined(ASIO_DISABLE_BOOST_CONTEXT_FIBER) +#endif // !defined(ASIO_HAS_BOOST_CONTEXT_FIBER) -// Standard library support for type traits. -#if !defined(ASIO_HAS_STD_TYPE_TRAITS) -# if !defined(ASIO_DISABLE_STD_TYPE_TRAITS) +// Standard library support for std::string_view. +#if !defined(ASIO_HAS_STD_STRING_VIEW) +# if !defined(ASIO_DISABLE_STD_STRING_VIEW) # if defined(__clang__) # if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_TYPE_TRAITS 1 -# elif (__cplusplus >= 201103) -# if __has_include(<type_traits>) -# define ASIO_HAS_STD_TYPE_TRAITS 1 -# endif // __has_include(<type_traits>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_TYPE_TRAITS 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_TYPE_TRAITS 1 -# endif // (_MSC_VER >= 1700) -# endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_TYPE_TRAITS) -#endif // !defined(ASIO_HAS_STD_TYPE_TRAITS) - -// Standard library support for the nullptr_t type. -#if !defined(ASIO_HAS_NULLPTR) -# if !defined(ASIO_DISABLE_NULLPTR) -# if defined(__clang__) -# if __has_feature(__cxx_nullptr__) -# define ASIO_HAS_NULLPTR 1 -# endif // __has_feature(__cxx_rvalue_references__) +# if (__cplusplus >= 201402) +# if __has_include(<string_view>) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include(<string_view>) +# endif // (__cplusplus >= 201402) +# else // defined(ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201703) +# if __has_include(<string_view>) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include(<string_view>) +# endif // (__cplusplus >= 201703) +# endif // defined(ASIO_HAS_CLANG_LIBCXX) # elif defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_NULLPTR 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_NULLPTR 1 -# endif // (_MSC_VER >= 1700) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# elif defined(ASIO_MSVC) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define ASIO_HAS_STD_STRING_VIEW 1 +# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_NULLPTR) -#endif // !defined(ASIO_HAS_NULLPTR) +# endif // !defined(ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(ASIO_HAS_STD_STRING_VIEW) -// Standard library support for the cstdint header. -#if !defined(ASIO_HAS_CSTDINT) -# if !defined(ASIO_DISABLE_CSTDINT) +// Standard library support for std::experimental::string_view. +#if !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) # if defined(__clang__) # if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_CSTDINT 1 -# elif (__cplusplus >= 201103) -# define ASIO_HAS_CSTDINT 1 -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_CSTDINT 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (_LIBCPP_VERSION < 7000) +# if (__cplusplus >= 201402) +# if __has_include(<experimental/string_view>) +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include(<experimental/string_view>) +# endif // (__cplusplus >= 201402) +# endif // (_LIBCPP_VERSION < 7000) +# else // defined(ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include(<experimental/string_view>) +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include(<experimental/string_view>) +# endif // (__cplusplus >= 201402) +# endif // // defined(ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) # endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(ASIO_HAS_STRING_VIEW) +# if !defined(ASIO_DISABLE_STRING_VIEW) +# if defined(ASIO_HAS_STD_STRING_VIEW) +# define ASIO_HAS_STRING_VIEW 1 +# elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define ASIO_HAS_STRING_VIEW 1 +# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(ASIO_DISABLE_STRING_VIEW) +#endif // !defined(ASIO_HAS_STRING_VIEW) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(ASIO_DISABLE_STD_INVOKE_RESULT) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_CSTDINT 1 -# endif // (_MSC_VER >= 1700) +# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# define ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# else // defined(ASIO_MSVC) +# if (__cplusplus >= 201703) +# define ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (__cplusplus >= 201703) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_CSTDINT) -#endif // !defined(ASIO_HAS_CSTDINT) +# endif // !defined(ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(ASIO_HAS_STD_INVOKE_RESULT) -// Standard library support for the thread class. -#if !defined(ASIO_HAS_STD_THREAD) -# if !defined(ASIO_DISABLE_STD_THREAD) +// Standard library support for std::any. +#if !defined(ASIO_HAS_STD_ANY) +# if !defined(ASIO_DISABLE_STD_ANY) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_THREAD 1 -# elif (__cplusplus >= 201103) -# if __has_include(<thread>) -# define ASIO_HAS_STD_THREAD 1 -# endif // __has_include(<thread>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_THREAD 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201703) +# if __has_include(<any>) +# define ASIO_HAS_STD_ANY 1 +# endif // __has_include(<any>) +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define ASIO_HAS_STD_ANY 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) # endif // defined(__GNUC__) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_THREAD 1 -# endif // (_MSC_VER >= 1700) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define ASIO_HAS_STD_ANY 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_THREAD) -#endif // !defined(ASIO_HAS_STD_THREAD) +# endif // !defined(ASIO_DISABLE_STD_ANY) +#endif // !defined(ASIO_HAS_STD_ANY) -// Standard library support for the mutex and condition variable classes. -#if !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) -# if !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +// Standard library support for std::variant. +#if !defined(ASIO_HAS_STD_VARIANT) +# if !defined(ASIO_DISABLE_STD_VARIANT) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 -# elif (__cplusplus >= 201103) -# if __has_include(<mutex>) -# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 -# endif // __has_include(<mutex>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201703) +# if __has_include(<variant>) +# define ASIO_HAS_STD_VARIANT 1 +# endif // __has_include(<variant>) +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define ASIO_HAS_STD_VARIANT 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) # endif // defined(__GNUC__) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 -# endif // (_MSC_VER >= 1700) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define ASIO_HAS_STD_VARIANT 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) -#endif // !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) - -// Standard library support for the call_once function. -#if !defined(ASIO_HAS_STD_CALL_ONCE) -# if !defined(ASIO_DISABLE_STD_CALL_ONCE) -# if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_CALL_ONCE 1 -# elif (__cplusplus >= 201103) -# if __has_include(<mutex>) -# define ASIO_HAS_STD_CALL_ONCE 1 -# endif // __has_include(<mutex>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) +# endif // !defined(ASIO_DISABLE_STD_VARIANT) +#endif // !defined(ASIO_HAS_STD_VARIANT) + +// Standard library support for std::source_location. +#if !defined(ASIO_HAS_STD_SOURCE_LOCATION) +# if !defined(ASIO_DISABLE_STD_SOURCE_LOCATION) +// ... +# endif // !defined(ASIO_DISABLE_STD_SOURCE_LOCATION) +#endif // !defined(ASIO_HAS_STD_SOURCE_LOCATION) + +// Standard library support for std::experimental::source_location. +#if !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) # if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_CALL_ONCE 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201709) +# if __has_include(<experimental/source_location>) +# define ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 +# endif // __has_include(<experimental/source_location>) +# endif // (__cplusplus >= 201709) # endif // defined(__GNUC__) -# if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_CALL_ONCE 1 -# endif // (_MSC_VER >= 1700) -# endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_CALL_ONCE) -#endif // !defined(ASIO_HAS_STD_CALL_ONCE) - -// Standard library support for futures. -#if !defined(ASIO_HAS_STD_FUTURE) -# if !defined(ASIO_DISABLE_STD_FUTURE) +# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +// Standard library has a source_location that we can use. +#if !defined(ASIO_HAS_SOURCE_LOCATION) +# if !defined(ASIO_DISABLE_SOURCE_LOCATION) +# if defined(ASIO_HAS_STD_SOURCE_LOCATION) +# define ASIO_HAS_SOURCE_LOCATION 1 +# elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# define ASIO_HAS_SOURCE_LOCATION 1 +# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# endif // !defined(ASIO_DISABLE_SOURCE_LOCATION) +#endif // !defined(ASIO_HAS_SOURCE_LOCATION) + +// Boost support for source_location and system errors. +#if !defined(ASIO_HAS_BOOST_SOURCE_LOCATION) +# if !defined(ASIO_DISABLE_BOOST_SOURCE_LOCATION) +# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# define ASIO_HAS_BOOST_SOURCE_LOCATION 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# endif // !defined(ASIO_DISABLE_BOOST_SOURCE_LOCATION) +#endif // !defined(ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Helper macros for working with Boost source locations. +#if defined(ASIO_HAS_BOOST_SOURCE_LOCATION) +# define ASIO_SOURCE_LOCATION_PARAM \ + , const boost::source_location& loc +# define ASIO_SOURCE_LOCATION_DEFAULTED_PARAM \ + , const boost::source_location& loc = BOOST_CURRENT_LOCATION +# define ASIO_SOURCE_LOCATION_ARG , loc +#else // if defined(ASIO_HAS_BOOST_SOURCE_LOCATION) +# define ASIO_SOURCE_LOCATION_PARAM +# define ASIO_SOURCE_LOCATION_DEFAULTED_PARAM +# define ASIO_SOURCE_LOCATION_ARG +#endif // if defined(ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Standard library support for std::index_sequence. +#if !defined(ASIO_HAS_STD_INDEX_SEQUENCE) +# if !defined(ASIO_DISABLE_STD_INDEX_SEQUENCE) # if defined(__clang__) -# if defined(ASIO_HAS_CLANG_LIBCXX) -# define ASIO_HAS_STD_FUTURE 1 -# elif (__cplusplus >= 201103) -# if __has_include(<future>) -# define ASIO_HAS_STD_FUTURE 1 -# endif // __has_include(<mutex>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ASIO_HAS_STD_FUTURE 1 -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) # endif // defined(__GNUC__) # if defined(ASIO_MSVC) -# if (_MSC_VER >= 1700) -# define ASIO_HAS_STD_FUTURE 1 -# endif // (_MSC_VER >= 1700) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# define ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) # endif // defined(ASIO_MSVC) -# endif // !defined(ASIO_DISABLE_STD_FUTURE) -#endif // !defined(ASIO_HAS_STD_FUTURE) - -// Standard library support for experimental::string_view. -#if !defined(ASIO_HAS_STD_STRING_VIEW) -# if !defined(ASIO_DISABLE_STD_STRING_VIEW) -# if defined(__clang__) -# if (__cplusplus >= 201103) -# ifdef _LIBCPP_VERSION -# if _LIBCPP_VERSION >= 8000 -# define ASIO_HAS_STD_STRING_VIEW 1 -# endif -# endif -# if !defined(ASIO_HAS_STD_STRING_VIEW) && __has_include(<experimental/string_view>) -# define ASIO_HAS_STD_STRING_VIEW 1 -# if defined(__APPLE__) -# if ((__clang_major__ < 10) || ((__clang_major__ == 10) && (__clang_minor__ == 0) && (__clang_patchlevel__ < 1))) -# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 -# endif // clang < 10.0.1 -# else // for non-Xcode Clang -# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 -# endif -# endif // __has_include(<experimental/string_view>) -# endif // (__cplusplus >= 201103) -# endif // defined(__clang__) -# if defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) -# if (__cplusplus >= 201300) -# define ASIO_HAS_STD_STRING_VIEW 1 -# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 -# endif // (__cplusplus >= 201300) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) -# endif // defined(__GNUC__) -# endif // !defined(ASIO_DISABLE_STD_STRING_VIEW) -#endif // !defined(ASIO_HAS_STD_STRING_VIEW) +# endif // !defined(ASIO_DISABLE_STD_INDEX_SEQUENCE) +#endif // !defined(ASIO_HAS_STD_INDEX_SEQUENCE) // Windows App target. Windows but with a limited API. #if !defined(ASIO_WINDOWS_APP) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) # include <winapifamily.h> -# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # define ASIO_WINDOWS_APP 1 # endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) @@ -778,18 +730,18 @@ // Windows: target OS version. #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) # if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) || defined(__BORLANDC__) +# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) # pragma message( \ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ - "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ - "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ - "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") -# else // defined(_MSC_VER) || defined(__BORLANDC__) + "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") +# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) # warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. -# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. -# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). -# endif // defined(_MSC_VER) || defined(__BORLANDC__) -# define _WIN32_WINNT 0x0501 +# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). +# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# define _WIN32_WINNT 0x0601 # endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # if defined(_MSC_VER) # if defined(_WIN32) && !defined(WIN32) @@ -860,7 +812,8 @@ || defined(__FreeBSD__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ - || defined(__linux__) + || defined(__linux__) \ + || defined(__HAIKU__) # define ASIO_HAS_UNISTD_H 1 # endif # endif // !defined(ASIO_HAS_BOOST_CONFIG) @@ -869,7 +822,7 @@ # include <unistd.h> #endif // defined(ASIO_HAS_UNISTD_H) -// Linux: epoll, eventfd and timerfd. +// Linux: epoll, eventfd, timerfd and io_uring. #if defined(__linux__) # include <linux/version.h> # if !defined(ASIO_HAS_EPOLL) @@ -893,8 +846,20 @@ # endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) # endif // defined(ASIO_HAS_EPOLL) # endif // !defined(ASIO_HAS_TIMERFD) +# if defined(ASIO_HAS_IO_URING) +# if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +# error Linux kernel 5.10 or later is required to support io_uring +# endif // LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +# endif // defined(ASIO_HAS_IO_URING) #endif // defined(__linux__) +// Linux: io_uring is used instead of epoll. +#if !defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# if !defined(ASIO_HAS_EPOLL) && defined(ASIO_HAS_IO_URING) +# define ASIO_HAS_IO_URING_AS_DEFAULT 1 +# endif // !defined(ASIO_HAS_EPOLL) && defined(ASIO_HAS_IO_URING) +#endif // !defined(ASIO_HAS_IO_URING_AS_DEFAULT) + // Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. #if (defined(__MACH__) && defined(__APPLE__)) \ || defined(__FreeBSD__) \ @@ -990,16 +955,40 @@ // UNIX domain sockets. #if !defined(ASIO_HAS_LOCAL_SOCKETS) # if !defined(ASIO_DISABLE_LOCAL_SOCKETS) -# if !defined(ASIO_WINDOWS) \ - && !defined(ASIO_WINDOWS_RUNTIME) \ - && !defined(__CYGWIN__) +# if !defined(ASIO_WINDOWS_RUNTIME) # define ASIO_HAS_LOCAL_SOCKETS 1 -# endif // !defined(ASIO_WINDOWS) - // && !defined(ASIO_WINDOWS_RUNTIME) - // && !defined(__CYGWIN__) +# endif // !defined(ASIO_WINDOWS_RUNTIME) # endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS) #endif // !defined(ASIO_HAS_LOCAL_SOCKETS) +// Files. +#if !defined(ASIO_HAS_FILE) +# if !defined(ASIO_DISABLE_FILE) +# if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# define ASIO_HAS_FILE 1 +# elif defined(ASIO_HAS_IO_URING) +# define ASIO_HAS_FILE 1 +# endif // defined(ASIO_HAS_IO_URING) +# endif // !defined(ASIO_DISABLE_FILE) +#endif // !defined(ASIO_HAS_FILE) + +// Pipes. +#if !defined(ASIO_HAS_PIPE) +# if defined(ASIO_HAS_IOCP) \ + || !defined(ASIO_WINDOWS) \ + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(ASIO_DISABLE_PIPE) +# define ASIO_HAS_PIPE 1 +# endif // !defined(ASIO_DISABLE_PIPE) +# endif // !defined(__SYMBIAN32__) +# endif // defined(ASIO_HAS_IOCP) + // || !defined(ASIO_WINDOWS) + // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(ASIO_HAS_PIPE) + // Can use sigaction() instead of signal(). #if !defined(ASIO_HAS_SIGACTION) # if !defined(ASIO_DISABLE_SIGACTION) @@ -1080,6 +1069,8 @@ # define ASIO_HAS_THREADS 1 # elif defined(__APPLE__) # define ASIO_HAS_THREADS 1 +# elif defined(__HAIKU__) +# define ASIO_HAS_THREADS 1 # elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) # define ASIO_HAS_THREADS 1 # elif defined(_PTHREADS) @@ -1095,6 +1086,8 @@ # define ASIO_HAS_PTHREADS 1 # elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) # define ASIO_HAS_PTHREADS 1 +# elif defined(__HAIKU__) +# define ASIO_HAS_PTHREADS 1 # endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) # endif // defined(ASIO_HAS_THREADS) #endif // !defined(ASIO_HAS_PTHREADS) @@ -1113,6 +1106,15 @@ # endif // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT) #endif // !defined(ASIO_STATIC_CONSTANT) +// Boost align library. +#if !defined(ASIO_HAS_BOOST_ALIGN) +# if !defined(ASIO_DISABLE_BOOST_ALIGN) +# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# define ASIO_HAS_BOOST_ALIGN 1 +# endif // defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# endif // !defined(ASIO_DISABLE_BOOST_ALIGN) +#endif // !defined(ASIO_HAS_BOOST_ALIGN) + // Boost array library. #if !defined(ASIO_HAS_BOOST_ARRAY) # if !defined(ASIO_DISABLE_BOOST_ARRAY) @@ -1182,13 +1184,13 @@ # if (__GNUC__ >= 3) # define ASIO_HAS_HANDLER_HOOKS 1 # endif // (__GNUC__ >= 3) -# elif !defined(__BORLANDC__) +# elif !defined(__BORLANDC__) || defined(__clang__) # define ASIO_HAS_HANDLER_HOOKS 1 -# endif // !defined(__BORLANDC__) +# endif // !defined(__BORLANDC__) || defined(__clang__) # endif // !defined(ASIO_DISABLE_HANDLER_HOOKS) #endif // !defined(ASIO_HAS_HANDLER_HOOKS) -// Support for the __thread keyword extension. +// Support for the __thread keyword extension, or equivalent. #if !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) # if defined(__linux__) # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) @@ -1210,6 +1212,22 @@ # define ASIO_THREAD_KEYWORD __declspec(thread) # endif // (_MSC_VER >= 1700) # endif // defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME) +# if defined(__APPLE__) +# if defined(__clang__) +# if defined(__apple_build_version__) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define ASIO_THREAD_KEYWORD __thread +# endif // defined(__apple_build_version__) +# endif // defined(__clang__) +# endif // defined(__APPLE__) +# if !defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) +# if defined(ASIO_HAS_BOOST_CONFIG) +# if !defined(BOOST_NO_CXX11_THREAD_LOCAL) +# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define ASIO_THREAD_KEYWORD thread_local +# endif // !defined(BOOST_NO_CXX11_THREAD_LOCAL) +# endif // defined(ASIO_HAS_BOOST_CONFIG) +# endif // !defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION) #endif // !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) #if !defined(ASIO_THREAD_KEYWORD) # define ASIO_THREAD_KEYWORD __thread @@ -1224,33 +1242,6 @@ // || (defined(__MACH__) && defined(__APPLE__)) #endif // !defined(ASIO_DISABLE_SSIZE_T) -// Helper macros to manage the transition away from the old services-based API. -#if defined(ASIO_ENABLE_OLD_SERVICES) -# define ASIO_SVC_TPARAM , typename Service -# define ASIO_SVC_TPARAM_DEF1(d1) , typename Service d1 -# define ASIO_SVC_TPARAM_DEF2(d1, d2) , typename Service d1, d2 -# define ASIO_SVC_TARG , Service -# define ASIO_SVC_T Service -# define ASIO_SVC_TPARAM1 , typename Service1 -# define ASIO_SVC_TPARAM1_DEF1(d1) , typename Service1 d1 -# define ASIO_SVC_TPARAM1_DEF2(d1, d2) , typename Service1 d1, d2 -# define ASIO_SVC_TARG1 , Service1 -# define ASIO_SVC_T1 Service1 -# define ASIO_SVC_ACCESS public -#else // defined(ASIO_ENABLE_OLD_SERVICES) -# define ASIO_SVC_TPARAM -# define ASIO_SVC_TPARAM_DEF1(d1) -# define ASIO_SVC_TPARAM_DEF2(d1, d2) -# define ASIO_SVC_TARG -// ASIO_SVC_T is defined at each point of use. -# define ASIO_SVC_TPARAM1 -# define ASIO_SVC_TPARAM1_DEF1(d1) -# define ASIO_SVC_TPARAM1_DEF2(d1, d2) -# define ASIO_SVC_TARG1 -// ASIO_SVC_T1 is defined at each point of use. -# define ASIO_SVC_ACCESS protected -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - // Helper macros to manage transition away from error_code return values. #if defined(ASIO_NO_DEPRECATED) # define ASIO_SYNC_OP_VOID void @@ -1260,4 +1251,172 @@ # define ASIO_SYNC_OP_VOID_RETURN(e) return e #endif // defined(ASIO_NO_DEPRECATED) +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(ASIO_UNUSED_TYPEDEF) +# define ASIO_UNUSED_TYPEDEF +#endif // !defined(ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(ASIO_UNUSED_VARIABLE) +# define ASIO_UNUSED_VARIABLE +#endif // !defined(ASIO_UNUSED_VARIABLE) + +// Helper macro to tell the optimiser what may be assumed to be true. +#if defined(ASIO_MSVC) +# define ASIO_ASSUME(expr) __assume(expr) +#elif defined(__clang__) +# if __has_builtin(__builtin_assume) +# define ASIO_ASSUME(expr) __builtin_assume(expr) +# endif // __has_builtin(__builtin_assume) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# define ASIO_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(ASIO_ASSUME) +# define ASIO_ASSUME(expr) (void)0 +#endif // !defined(ASIO_ASSUME) + +// Support the co_await keyword on compilers known to allow it. +#if !defined(ASIO_HAS_CO_AWAIT) +# if !defined(ASIO_DISABLE_CO_AWAIT) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) && !defined(__clang__) +# define ASIO_HAS_CO_AWAIT 1 +# elif (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include(<coroutine>) +# define ASIO_HAS_CO_AWAIT 1 +# endif // __has_include(<coroutine>) +# elif (__cplusplus >= 201703) && defined(__cpp_coroutines) && (__cpp_coroutines >= 201703) +# if __has_include(<experimental/coroutine>) +# define ASIO_HAS_CO_AWAIT 1 +# endif // __has_include(<experimental/coroutine>) +# endif // (__cplusplus >= 201703) && defined(__cpp_coroutines) && (__cpp_coroutines >= 201703) +# else // (__clang_major__ >= 14) +# if (__cplusplus >= 201703) && defined(__cpp_coroutines) && (__cpp_coroutines >= 201703) +# if __has_include(<experimental/coroutine>) +# define ASIO_HAS_CO_AWAIT 1 +# endif // __has_include(<experimental/coroutine>) +# endif // (__cplusplus >= 201703) && defined(__cpp_coroutines) && (__cpp_coroutines >= 201703) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include(<coroutine>) +# define ASIO_HAS_CO_AWAIT 1 +# endif // __has_include(<coroutine>) +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_CO_AWAIT) +#endif // !defined(ASIO_HAS_CO_AWAIT) + +// Standard library support for coroutines. +#if !defined(ASIO_HAS_STD_COROUTINE) +# if !defined(ASIO_DISABLE_STD_COROUTINE) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# define ASIO_HAS_STD_COROUTINE 1 +# endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include(<coroutine>) +# define ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include(<coroutine>) +# endif // (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include(<coroutine>) +# define ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include(<coroutine>) +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(ASIO_DISABLE_STD_COROUTINE) +#endif // !defined(ASIO_HAS_STD_COROUTINE) + +// Compiler support for the the [[nodiscard]] attribute. +#if !defined(ASIO_NODISCARD) +# if defined(__has_cpp_attribute) +# if __has_cpp_attribute(nodiscard) +# if (__cplusplus >= 201703) +# define ASIO_NODISCARD [[nodiscard]] +# endif // (__cplusplus >= 201703) +# endif // __has_cpp_attribute(nodiscard) +# endif // defined(__has_cpp_attribute) +#endif // !defined(ASIO_NODISCARD) +#if !defined(ASIO_NODISCARD) +# define ASIO_NODISCARD +#endif // !defined(ASIO_NODISCARD) + +// Kernel support for MSG_NOSIGNAL. +#if !defined(ASIO_HAS_MSG_NOSIGNAL) +# if defined(__linux__) +# define ASIO_HAS_MSG_NOSIGNAL 1 +# elif defined(_POSIX_VERSION) +# if (_POSIX_VERSION >= 200809L) +# define ASIO_HAS_MSG_NOSIGNAL 1 +# endif // _POSIX_VERSION >= 200809L +# endif // defined(_POSIX_VERSION) +#endif // !defined(ASIO_HAS_MSG_NOSIGNAL) + +// Standard library support for std::to_address. +#if !defined(ASIO_HAS_STD_TO_ADDRESS) +# if !defined(ASIO_DISABLE_STD_TO_ADDRESS) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__GNUC__ >= 8) +# if (__cplusplus >= 202002) +# define ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# endif // (__GNUC__ >= 8) +# endif // defined(__GNUC__) +# if defined(ASIO_MSVC) +# if (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# define ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# endif // defined(ASIO_MSVC) +# endif // !defined(ASIO_DISABLE_STD_TO_ADDRESS) +#endif // !defined(ASIO_HAS_STD_TO_ADDRESS) + +// Standard library support for snprintf. +#if !defined(ASIO_HAS_SNPRINTF) +# if !defined(ASIO_DISABLE_SNPRINTF) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 14) +# define ASIO_HAS_SNPRINTF 1 +# endif // (__clang_major__ >= 14) +# endif // defined(__apple_build_version__) +# endif // !defined(ASIO_DISABLE_SNPRINTF) +#endif // !defined(ASIO_HAS_SNPRINTF) + #endif // ASIO_DETAIL_CONFIG_HPP diff --git a/3rdparty/asio/include/asio/detail/consuming_buffers.hpp b/3rdparty/asio/include/asio/detail/consuming_buffers.hpp index b1d656770fd..8af95aab769 100644 --- a/3rdparty/asio/include/asio/detail/consuming_buffers.hpp +++ b/3rdparty/asio/include/asio/detail/consuming_buffers.hpp @@ -2,7 +2,7 @@ // detail/consuming_buffers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,25 +20,40 @@ #include "asio/buffer.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/limits.hpp" +#include "asio/registered_buffer.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +// Helper template to determine the maximum number of prepared buffers. +template <typename Buffers> +struct prepared_buffers_max +{ + enum { value = buffer_sequence_adapter_base::max_buffers }; +}; + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<boost::array<Elem, N>> +{ + enum { value = N }; +}; + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<std::array<Elem, N>> +{ + enum { value = N }; +}; // A buffer sequence used to represent a subsequence of the buffers. -template <typename Buffer> +template <typename Buffer, std::size_t MaxBuffers> struct prepared_buffers { typedef Buffer value_type; typedef const Buffer* const_iterator; - enum - { - max_buffers = buffer_sequence_adapter_base::max_buffers < 8 - ? buffer_sequence_adapter_base::max_buffers : 8 - }; + enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 }; prepared_buffers() : count(0) {} const_iterator begin() const { return elems; } @@ -53,14 +68,18 @@ template <typename Buffer, typename Buffers, typename Buffer_Iterator> class consuming_buffers { public: + typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value> + prepared_buffers_type; + // Construct to represent the entire list of buffers. explicit consuming_buffers(const Buffers& buffers) : buffers_(buffers), - total_size_(asio::buffer_size(buffers)), total_consumed_(0), next_elem_(0), next_elem_offset_(0) { + using asio::buffer_size; + total_size_ = buffer_size(buffers); } // Determine if we are at the end of the buffers. @@ -70,16 +89,16 @@ public: } // Get the buffer for a single transfer, with a size. - prepared_buffers<Buffer> prepare(std::size_t max_size) + prepared_buffers_type prepare(std::size_t max_size) { - prepared_buffers<Buffer> result; + prepared_buffers_type result; Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); Buffer_Iterator end = asio::buffer_sequence_end(buffers_); std::advance(next, next_elem_); std::size_t elem_offset = next_elem_offset_; - while (next != end && max_size > 0 && result.count < result.max_buffers) + while (next != end && max_size > 0 && (result.count) < result.max_buffers) { Buffer next_buf = Buffer(*next) + elem_offset; result.elems[result.count] = asio::buffer(next_buf, max_size); @@ -247,6 +266,42 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) +template <> +class consuming_buffers<mutable_buffer, + mutable_registered_buffer, const mutable_buffer*> + : public consuming_single_buffer<mutable_registered_buffer> +{ +public: + explicit consuming_buffers(const mutable_registered_buffer& buffer) + : consuming_single_buffer<mutable_registered_buffer>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, + mutable_registered_buffer, const mutable_buffer*> + : public consuming_single_buffer<mutable_registered_buffer> +{ +public: + explicit consuming_buffers(const mutable_registered_buffer& buffer) + : consuming_single_buffer<mutable_registered_buffer>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, + const_registered_buffer, const const_buffer*> + : public consuming_single_buffer<const_registered_buffer> +{ +public: + explicit consuming_buffers(const const_registered_buffer& buffer) + : consuming_single_buffer<const_registered_buffer>(buffer) + { + } +}; + template <typename Buffer, typename Elem> class consuming_buffers<Buffer, boost::array<Elem, 2>, typename boost::array<Elem, 2>::const_iterator> @@ -297,8 +352,6 @@ private: std::size_t total_consumed_; }; -#if defined(ASIO_HAS_STD_ARRAY) - template <typename Buffer, typename Elem> class consuming_buffers<Buffer, std::array<Elem, 2>, typename std::array<Elem, 2>::const_iterator> @@ -349,8 +402,6 @@ private: std::size_t total_consumed_; }; -#endif // defined(ASIO_HAS_STD_ARRAY) - // Specialisation for null_buffers to ensure that the null_buffers type is // always passed through to the underlying read or write operation. template <typename Buffer> @@ -378,7 +429,7 @@ public: // No-op. } - std::size_t total_consume() const + std::size_t total_consumed() const { return 0; } diff --git a/3rdparty/asio/include/asio/detail/cstddef.hpp b/3rdparty/asio/include/asio/detail/cstddef.hpp index a5092ce53b0..15ec42df5f3 100644 --- a/3rdparty/asio/include/asio/detail/cstddef.hpp +++ b/3rdparty/asio/include/asio/detail/cstddef.hpp @@ -2,7 +2,7 @@ // detail/cstddef.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,11 +20,7 @@ namespace asio { -#if defined(ASIO_HAS_NULLPTR) using std::nullptr_t; -#else // defined(ASIO_HAS_NULLPTR) -struct nullptr_t {}; -#endif // defined(ASIO_HAS_NULLPTR) } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/cstdint.hpp b/3rdparty/asio/include/asio/detail/cstdint.hpp index 2c0641421c3..a696e34c8ae 100644 --- a/3rdparty/asio/include/asio/detail/cstdint.hpp +++ b/3rdparty/asio/include/asio/detail/cstdint.hpp @@ -2,7 +2,7 @@ // detail/cstdint.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,16 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_CSTDINT) -# include <cstdint> -#else // defined(ASIO_HAS_CSTDINT) -# include <boost/cstdint.hpp> -#endif // defined(ASIO_HAS_CSTDINT) +#include <cstdint> namespace asio { -#if defined(ASIO_HAS_CSTDINT) using std::int16_t; using std::int_least16_t; using std::uint16_t; @@ -38,22 +32,8 @@ using std::int64_t; using std::int_least64_t; using std::uint64_t; using std::uint_least64_t; +using std::uintptr_t; using std::uintmax_t; -#else // defined(ASIO_HAS_CSTDINT) -using boost::int16_t; -using boost::int_least16_t; -using boost::uint16_t; -using boost::uint_least16_t; -using boost::int32_t; -using boost::int_least32_t; -using boost::uint32_t; -using boost::uint_least32_t; -using boost::int64_t; -using boost::int_least64_t; -using boost::uint64_t; -using boost::uint_least64_t; -using boost::uintmax_t; -#endif // defined(ASIO_HAS_CSTDINT) } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/date_time_fwd.hpp b/3rdparty/asio/include/asio/detail/date_time_fwd.hpp index 918bb7bdbc6..a586fbea713 100644 --- a/3rdparty/asio/include/asio/detail/date_time_fwd.hpp +++ b/3rdparty/asio/include/asio/detail/date_time_fwd.hpp @@ -2,7 +2,7 @@ // detail/date_time_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/deadline_timer_service.hpp b/3rdparty/asio/include/asio/detail/deadline_timer_service.hpp index 816f16f1e5b..bd99a6e910c 100644 --- a/3rdparty/asio/include/asio/detail/deadline_timer_service.hpp +++ b/3rdparty/asio/include/asio/detail/deadline_timer_service.hpp @@ -2,7 +2,7 @@ // detail/deadline_timer_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,8 +17,10 @@ #include "asio/detail/config.hpp" #include <cstddef> +#include "asio/associated_cancellation_slot.hpp" +#include "asio/cancellation_type.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/memory.hpp" @@ -43,7 +45,7 @@ namespace detail { template <typename Time_Traits> class deadline_timer_service - : public service_base<deadline_timer_service<Time_Traits> > + : public execution_context_service_base<deadline_timer_service<Time_Traits>> { public: // The time type. @@ -63,9 +65,10 @@ public: }; // Constructor. - deadline_timer_service(asio::io_context& io_context) - : service_base<deadline_timer_service<Time_Traits> >(io_context), - scheduler_(asio::use_service<timer_scheduler>(io_context)) + deadline_timer_service(execution_context& context) + : execution_context_service_base< + deadline_timer_service<Time_Traits>>(context), + scheduler_(asio::use_service<timer_scheduler>(context)) { scheduler_.init_task(); scheduler_.add_timer_queue(timer_queue_); @@ -96,7 +99,7 @@ public: cancel(impl, ec); } - // Move-construct a new serial port implementation. + // Move-construct a new timer implementation. void move_construct(implementation_type& impl, implementation_type& other_impl) { @@ -109,7 +112,7 @@ public: other_impl.might_have_pending_waits = false; } - // Move-assign from another serial port implementation. + // Move-assign from another timer implementation. void move_assign(implementation_type& impl, deadline_timer_service& other_service, implementation_type& other_impl) @@ -128,6 +131,21 @@ public: other_impl.might_have_pending_waits = false; } + // Move-construct a new timer implementation. + void converting_move_construct(implementation_type& impl, + deadline_timer_service&, implementation_type& other_impl) + { + move_construct(impl, other_impl); + } + + // Move-assign from another timer implementation. + void converting_move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + move_assign(impl, other_service, other_impl); + } + // Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, asio::error_code& ec) { @@ -225,14 +243,25 @@ public: } // Start an asynchronous wait on the timer. - template <typename Handler> - void async_wait(implementation_type& impl, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef wait_handler<Handler> op; + typedef wait_handler<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<op_cancellation>(this, &impl.timer_data); + } impl.might_have_pending_waits = true; @@ -263,6 +292,34 @@ private: #endif // defined(ASIO_WINDOWS_RUNTIME) } + // Helper class used to implement per-operation cancellation. + class op_cancellation + { + public: + op_cancellation(deadline_timer_service* s, + typename timer_queue<Time_Traits>::per_timer_data* p) + : service_(s), + timer_data_(p) + { + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + service_->scheduler_.cancel_timer_by_key( + service_->timer_queue_, timer_data_, this); + } + } + + private: + deadline_timer_service* service_; + typename timer_queue<Time_Traits>::per_timer_data* timer_data_; + }; + // The queue of timers. timer_queue<Time_Traits> timer_queue_; diff --git a/3rdparty/asio/include/asio/detail/dependent_type.hpp b/3rdparty/asio/include/asio/detail/dependent_type.hpp index a4737e2e7b6..fde0e4a6eb5 100644 --- a/3rdparty/asio/include/asio/detail/dependent_type.hpp +++ b/3rdparty/asio/include/asio/detail/dependent_type.hpp @@ -2,7 +2,7 @@ // detail/dependent_type.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/descriptor_ops.hpp b/3rdparty/asio/include/asio/detail/descriptor_ops.hpp index 677f010ca50..c001696a9fd 100644 --- a/3rdparty/asio/include/asio/detail/descriptor_ops.hpp +++ b/3rdparty/asio/include/asio/detail/descriptor_ops.hpp @@ -2,7 +2,7 @@ // detail/descriptor_ops.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -24,6 +24,7 @@ #include <cstddef> #include "asio/error.hpp" #include "asio/error_code.hpp" +#include "asio/detail/cstdint.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" @@ -50,18 +51,26 @@ enum typedef unsigned char state_type; -template <typename ReturnType> -inline ReturnType error_wrapper(ReturnType return_value, - asio::error_code& ec) +inline void get_last_error( + asio::error_code& ec, bool is_error_condition) { - ec = asio::error_code(errno, - asio::error::get_system_category()); - return return_value; + if (!is_error_condition) + { + asio::error::clear(ec); + } + else + { + ec = asio::error_code(errno, + asio::error::get_system_category()); + } } ASIO_DECL int open(const char* path, int flags, asio::error_code& ec); +ASIO_DECL int open(const char* path, int flags, unsigned mode, + asio::error_code& ec); + ASIO_DECL int close(int d, state_type& state, asio::error_code& ec); @@ -76,17 +85,66 @@ typedef iovec buf; ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec); +ASIO_DECL std::size_t sync_read1(int d, state_type state, void* data, + std::size_t size, asio::error_code& ec); + ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, asio::error_code& ec, std::size_t& bytes_transferred); +ASIO_DECL bool non_blocking_read1(int d, void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred); + ASIO_DECL std::size_t sync_write(int d, state_type state, const buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec); +ASIO_DECL std::size_t sync_write1(int d, state_type state, + const void* data, std::size_t size, asio::error_code& ec); + ASIO_DECL bool non_blocking_write(int d, const buf* bufs, std::size_t count, asio::error_code& ec, std::size_t& bytes_transferred); +ASIO_DECL bool non_blocking_write1(int d, + const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred); + +#if defined(ASIO_HAS_FILE) + +ASIO_DECL std::size_t sync_read_at(int d, state_type state, + uint64_t offset, buf* bufs, std::size_t count, bool all_empty, + asio::error_code& ec); + +ASIO_DECL std::size_t sync_read_at1(int d, state_type state, + uint64_t offset, void* data, std::size_t size, + asio::error_code& ec); + +ASIO_DECL bool non_blocking_read_at(int d, uint64_t offset, + buf* bufs, std::size_t count, asio::error_code& ec, + std::size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_read_at1(int d, uint64_t offset, + void* data, std::size_t size, asio::error_code& ec, + std::size_t& bytes_transferred); + +ASIO_DECL std::size_t sync_write_at(int d, state_type state, + uint64_t offset, const buf* bufs, std::size_t count, bool all_empty, + asio::error_code& ec); + +ASIO_DECL std::size_t sync_write_at1(int d, state_type state, + uint64_t offset, const void* data, std::size_t size, + asio::error_code& ec); + +ASIO_DECL bool non_blocking_write_at(int d, + uint64_t offset, const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_write_at1(int d, + uint64_t offset, const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred); + +#endif // defined(ASIO_HAS_FILE) + ASIO_DECL int ioctl(int d, state_type& state, long cmd, ioctl_arg_type* arg, asio::error_code& ec); diff --git a/3rdparty/asio/include/asio/detail/descriptor_read_op.hpp b/3rdparty/asio/include/asio/detail/descriptor_read_op.hpp index f1027b004eb..415490cb8a5 100644 --- a/3rdparty/asio/include/asio/detail/descriptor_read_op.hpp +++ b/3rdparty/asio/include/asio/detail/descriptor_read_op.hpp @@ -2,7 +2,7 @@ // detail/descriptor_read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -26,6 +26,7 @@ #include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" +#include "asio/dispatch.hpp" #include "asio/detail/push_options.hpp" @@ -36,9 +37,11 @@ template <typename MutableBufferSequence> class descriptor_read_op_base : public reactor_op { public: - descriptor_read_op_base(int descriptor, - const MutableBufferSequence& buffers, func_type complete_func) - : reactor_op(&descriptor_read_op_base::do_perform, complete_func), + descriptor_read_op_base(const asio::error_code& success_ec, + int descriptor, const MutableBufferSequence& buffers, + func_type complete_func) + : reactor_op(success_ec, + &descriptor_read_op_base::do_perform, complete_func), descriptor_(descriptor), buffers_(buffers) { @@ -46,14 +49,27 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base)); - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(o->buffers_); + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; - status result = descriptor_ops::non_blocking_read(o->descriptor_, - bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) - ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = descriptor_ops::non_blocking_read1(o->descriptor_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + } ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read", o->ec_, o->bytes_transferred_)); @@ -66,20 +82,24 @@ private: MutableBufferSequence buffers_; }; -template <typename MutableBufferSequence, typename Handler> +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class descriptor_read_op : public descriptor_read_op_base<MutableBufferSequence> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); - descriptor_read_op(int descriptor, - const MutableBufferSequence& buffers, Handler& handler) - : descriptor_read_op_base<MutableBufferSequence>( + descriptor_read_op(const asio::error_code& success_ec, + int descriptor, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : descriptor_read_op_base<MutableBufferSequence>(success_ec, descriptor, buffers, &descriptor_read_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -87,12 +107,19 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); descriptor_read_op* o(static_cast<descriptor_read_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -114,8 +141,41 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + descriptor_read_op* o(static_cast<descriptor_read_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/descriptor_write_op.hpp b/3rdparty/asio/include/asio/detail/descriptor_write_op.hpp index 96d6e5bc8da..ed1814e7e39 100644 --- a/3rdparty/asio/include/asio/detail/descriptor_write_op.hpp +++ b/3rdparty/asio/include/asio/detail/descriptor_write_op.hpp @@ -2,7 +2,7 @@ // detail/descriptor_write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -36,9 +36,11 @@ template <typename ConstBufferSequence> class descriptor_write_op_base : public reactor_op { public: - descriptor_write_op_base(int descriptor, - const ConstBufferSequence& buffers, func_type complete_func) - : reactor_op(&descriptor_write_op_base::do_perform, complete_func), + descriptor_write_op_base(const asio::error_code& success_ec, + int descriptor, const ConstBufferSequence& buffers, + func_type complete_func) + : reactor_op(success_ec, + &descriptor_write_op_base::do_perform, complete_func), descriptor_(descriptor), buffers_(buffers) { @@ -46,14 +48,27 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base)); - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(o->buffers_); + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; - status result = descriptor_ops::non_blocking_write(o->descriptor_, - bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) - ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = descriptor_ops::non_blocking_write1(o->descriptor_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + } ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write", o->ec_, o->bytes_transferred_)); @@ -66,20 +81,24 @@ private: ConstBufferSequence buffers_; }; -template <typename ConstBufferSequence, typename Handler> +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> class descriptor_write_op : public descriptor_write_op_base<ConstBufferSequence> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); - descriptor_write_op(int descriptor, - const ConstBufferSequence& buffers, Handler& handler) - : descriptor_write_op_base<ConstBufferSequence>( + descriptor_write_op(const asio::error_code& success_ec, + int descriptor, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : descriptor_write_op_base<ConstBufferSequence>(success_ec, descriptor, buffers, &descriptor_write_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -87,12 +106,19 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); descriptor_write_op* o(static_cast<descriptor_write_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -114,8 +140,41 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + descriptor_write_op* o(static_cast<descriptor_write_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/dev_poll_reactor.hpp b/3rdparty/asio/include/asio/detail/dev_poll_reactor.hpp index 1f59cf30995..720fd6b54e8 100644 --- a/3rdparty/asio/include/asio/detail/dev_poll_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/dev_poll_reactor.hpp @@ -2,7 +2,7 @@ // detail/dev_poll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -28,6 +28,7 @@ #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/scheduler_task.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_queue_base.hpp" @@ -41,7 +42,8 @@ namespace asio { namespace detail { class dev_poll_reactor - : public execution_context_service_base<dev_poll_reactor> + : public execution_context_service_base<dev_poll_reactor>, + public scheduler_task { public: enum op_types { read_op = 0, write_op = 1, @@ -84,32 +86,59 @@ public: per_descriptor_data& source_descriptor_data); // Post a reactor operation for immediate completion. - void post_immediate_completion(reactor_op* op, bool is_continuation) - { - scheduler_.post_immediate_completion(op, is_continuation); - } + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data&, reactor_op* op, - bool is_continuation, bool allow_speculative); + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &dev_poll_reactor::call_post_immediate_completion, this); + } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + // Cancel all operations associated with the given descriptor and key. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops_by_key(socket_type descriptor, + per_descriptor_data& descriptor_data, + int op_type, void* cancellation_key); + // Cancel any operations that are running against the descriptor and remove - // its registration from the reactor. + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. ASIO_DECL void deregister_descriptor(socket_type descriptor, per_descriptor_data&, bool closing); - // Cancel any operations that are running against the descriptor and remove - // its registration from the reactor. + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. ASIO_DECL void deregister_internal_descriptor( socket_type descriptor, per_descriptor_data&); + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); + // Add a new timer queue to the reactor. template <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& queue); @@ -132,6 +161,12 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Cancel the timer operations associated with the given key. + template <typename Time_Traits> + void cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key); + // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, @@ -139,7 +174,7 @@ public: typename timer_queue<Time_Traits>::per_timer_data& source); // Run /dev/poll once until interrupted or events are ready to be dispatched. - ASIO_DECL void run(bool block, op_queue<operation>& ops); + ASIO_DECL void run(long usec, op_queue<operation>& ops); // Interrupt the select loop. ASIO_DECL void interrupt(); diff --git a/3rdparty/asio/include/asio/detail/epoll_reactor.hpp b/3rdparty/asio/include/asio/detail/epoll_reactor.hpp index ba8b2a15420..212767a760f 100644 --- a/3rdparty/asio/include/asio/detail/epoll_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/epoll_reactor.hpp @@ -2,7 +2,7 @@ // detail/epoll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -25,6 +25,7 @@ #include "asio/detail/object_pool.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" +#include "asio/detail/scheduler_task.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_queue_base.hpp" @@ -32,13 +33,18 @@ #include "asio/detail/wait_op.hpp" #include "asio/execution_context.hpp" +#if defined(ASIO_HAS_TIMERFD) +# include <sys/timerfd.h> +#endif // defined(ASIO_HAS_TIMERFD) + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class epoll_reactor - : public execution_context_service_base<epoll_reactor> + : public execution_context_service_base<epoll_reactor>, + public scheduler_task { private: // The mutex type used by this reactor. @@ -67,6 +73,7 @@ public: ASIO_DECL descriptor_state(bool locking); void set_ready_events(uint32_t events) { task_result_ = events; } + void add_ready_events(uint32_t events) { task_result_ |= events; } ASIO_DECL operation* perform_io(uint32_t events); ASIO_DECL static void do_complete( void* owner, operation* base, @@ -109,16 +116,30 @@ public: per_descriptor_data& source_descriptor_data); // Post a reactor operation for immediate completion. - void post_immediate_completion(reactor_op* op, bool is_continuation) - { - scheduler_.post_immediate_completion(op, is_continuation); - } + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative); + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &epoll_reactor::call_post_immediate_completion, this); + } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the @@ -126,15 +147,30 @@ public: ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data); + // Cancel all operations associated with the given descriptor and key. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops_by_key(socket_type descriptor, + per_descriptor_data& descriptor_data, + int op_type, void* cancellation_key); + // Cancel any operations that are running against the descriptor and remove - // its registration from the reactor. + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. ASIO_DECL void deregister_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data, bool closing); - // Remote the descriptor's registration from the reactor. + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. ASIO_DECL void deregister_internal_descriptor( socket_type descriptor, per_descriptor_data& descriptor_data); + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + // Add a new timer queue to the reactor. template <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& timer_queue); @@ -157,6 +193,12 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Cancel the timer operations associated with the given key. + template <typename Time_Traits> + void cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key); + // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, diff --git a/3rdparty/asio/include/asio/detail/event.hpp b/3rdparty/asio/include/asio/detail/event.hpp index bb07fcdd18c..19e458cdf05 100644 --- a/3rdparty/asio/include/asio/detail/event.hpp +++ b/3rdparty/asio/include/asio/detail/event.hpp @@ -2,7 +2,7 @@ // detail/event.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,10 +23,8 @@ # include "asio/detail/win_event.hpp" #elif defined(ASIO_HAS_PTHREADS) # include "asio/detail/posix_event.hpp" -#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) -# include "asio/detail/std_event.hpp" #else -# error Only Windows, POSIX and std::condition_variable are supported! +# include "asio/detail/std_event.hpp" #endif namespace asio { @@ -38,7 +36,7 @@ typedef null_event event; typedef win_event event; #elif defined(ASIO_HAS_PTHREADS) typedef posix_event event; -#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +#else typedef std_event event; #endif diff --git a/3rdparty/asio/include/asio/detail/eventfd_select_interrupter.hpp b/3rdparty/asio/include/asio/detail/eventfd_select_interrupter.hpp index fcc86637ad6..0eb8843dd56 100644 --- a/3rdparty/asio/include/asio/detail/eventfd_select_interrupter.hpp +++ b/3rdparty/asio/include/asio/detail/eventfd_select_interrupter.hpp @@ -2,7 +2,7 @@ // detail/eventfd_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -40,7 +40,7 @@ public: // Interrupt the select call. ASIO_DECL void interrupt(); - // Reset the select interrupt. Returns true if the call was interrupted. + // Reset the select interrupter. Returns true if the reset was successful. ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. diff --git a/3rdparty/asio/include/asio/detail/exception.hpp b/3rdparty/asio/include/asio/detail/exception.hpp new file mode 100644 index 00000000000..28c7cffb5d8 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/exception.hpp @@ -0,0 +1,29 @@ +// +// detail/exception.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_EXCEPTION_HPP +#define ASIO_DETAIL_EXCEPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <exception> + +namespace asio { + +using std::exception_ptr; +using std::current_exception; +using std::rethrow_exception; + +} // namespace asio + +#endif // ASIO_DETAIL_EXCEPTION_HPP diff --git a/3rdparty/asio/include/asio/detail/executor_function.hpp b/3rdparty/asio/include/asio/detail/executor_function.hpp new file mode 100644 index 00000000000..cccf31bf3af --- /dev/null +++ b/3rdparty/asio/include/asio/detail/executor_function.hpp @@ -0,0 +1,152 @@ +// +// detail/executor_function.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_EXECUTOR_FUNCTION_HPP +#define ASIO_DETAIL_EXECUTOR_FUNCTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Lightweight, move-only function object wrapper. +class executor_function +{ +public: + template <typename F, typename Alloc> + explicit executor_function(F f, const Alloc& a) + { + // Allocate and construct an object to wrap the function. + typedef impl<F, Alloc> impl_type; + typename impl_type::ptr p = { + detail::addressof(a), impl_type::ptr::allocate(a), 0 }; + impl_ = new (p.v) impl_type(static_cast<F&&>(f), a); + p.v = 0; + } + + executor_function(executor_function&& other) noexcept + : impl_(other.impl_) + { + other.impl_ = 0; + } + + ~executor_function() + { + if (impl_) + impl_->complete_(impl_, false); + } + + void operator()() + { + if (impl_) + { + impl_base* i = impl_; + impl_ = 0; + i->complete_(i, true); + } + } + +private: + // Base class for polymorphic function implementations. + struct impl_base + { + void (*complete_)(impl_base*, bool); + }; + + // Polymorphic function implementation. + template <typename Function, typename Alloc> + struct impl : impl_base + { + ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( + thread_info_base::executor_function_tag, impl); + + template <typename F> + impl(F&& f, const Alloc& a) + : function_(static_cast<F&&>(f)), + allocator_(a) + { + complete_ = &executor_function::complete<Function, Alloc>; + } + + Function function_; + Alloc allocator_; + }; + + // Helper to complete function invocation. + template <typename Function, typename Alloc> + static void complete(impl_base* base, bool call) + { + // Take ownership of the function object. + impl<Function, Alloc>* i(static_cast<impl<Function, Alloc>*>(base)); + Alloc allocator(i->allocator_); + typename impl<Function, Alloc>::ptr p = { + detail::addressof(allocator), i, i }; + + // Make a copy of the function so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the function may be the true owner of the memory + // associated with the function. Consequently, a local copy of the function + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Function function(static_cast<Function&&>(i->function_)); + p.reset(); + + // Make the upcall if required. + if (call) + { + static_cast<Function&&>(function)(); + } + } + + impl_base* impl_; +}; + +// Lightweight, non-owning, copyable function object wrapper. +class executor_function_view +{ +public: + template <typename F> + explicit executor_function_view(F& f) noexcept + : complete_(&executor_function_view::complete<F>), + function_(&f) + { + } + + void operator()() + { + complete_(function_); + } + +private: + // Helper to complete function invocation. + template <typename F> + static void complete(void* f) + { + (*static_cast<F*>(f))(); + } + + void (*complete_)(void*); + void* function_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_EXECUTOR_FUNCTION_HPP diff --git a/3rdparty/asio/include/asio/detail/executor_op.hpp b/3rdparty/asio/include/asio/detail/executor_op.hpp index 31451306a5b..78e781e217b 100644 --- a/3rdparty/asio/include/asio/detail/executor_op.hpp +++ b/3rdparty/asio/include/asio/detail/executor_op.hpp @@ -2,7 +2,7 @@ // detail/executor_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,7 +18,6 @@ #include "asio/detail/config.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/scheduler_operation.hpp" #include "asio/detail/push_options.hpp" @@ -31,11 +30,12 @@ template <typename Handler, typename Alloc, class executor_op : public Operation { public: - ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op, Alloc); + ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); - executor_op(Handler& h, const Alloc& allocator) + template <typename H> + executor_op(H&& h, const Alloc& allocator) : Operation(&executor_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(h)), + handler_(static_cast<H&&>(h)), allocator_(allocator) { } @@ -45,8 +45,10 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); executor_op* o(static_cast<executor_op*>(base)); - ptr p = { o->allocator_, o, o }; + Alloc allocator(o->allocator_); + ptr p = { detail::addressof(allocator), o, o }; ASIO_HANDLER_COMPLETION((*o)); @@ -56,7 +58,7 @@ public: // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. - Handler handler(ASIO_MOVE_CAST(Handler)(o->handler_)); + Handler handler(static_cast<Handler&&>(o->handler_)); p.reset(); // Make the upcall if required. @@ -64,7 +66,7 @@ public: { fenced_block b(fenced_block::half); ASIO_HANDLER_INVOCATION_BEGIN(()); - asio_handler_invoke_helpers::invoke(handler, handler); + static_cast<Handler&&>(handler)(); ASIO_HANDLER_INVOCATION_END; } } diff --git a/3rdparty/asio/include/asio/detail/fd_set_adapter.hpp b/3rdparty/asio/include/asio/detail/fd_set_adapter.hpp index 44c4c46ddf5..80b8974a417 100644 --- a/3rdparty/asio/include/asio/detail/fd_set_adapter.hpp +++ b/3rdparty/asio/include/asio/detail/fd_set_adapter.hpp @@ -2,7 +2,7 @@ // detail/fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/fenced_block.hpp b/3rdparty/asio/include/asio/detail/fenced_block.hpp index c07c85f1483..ff096dc8486 100644 --- a/3rdparty/asio/include/asio/detail/fenced_block.hpp +++ b/3rdparty/asio/include/asio/detail/fenced_block.hpp @@ -2,7 +2,7 @@ // detail/fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,26 +20,8 @@ #if !defined(ASIO_HAS_THREADS) \ || defined(ASIO_DISABLE_FENCED_BLOCK) # include "asio/detail/null_fenced_block.hpp" -#elif defined(__MACH__) && defined(__APPLE__) -# include "asio/detail/macos_fenced_block.hpp" -#elif defined(__sun) -# include "asio/detail/solaris_fenced_block.hpp" -#elif defined(__GNUC__) && defined(__arm__) \ - && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) -# include "asio/detail/gcc_arm_fenced_block.hpp" -#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) -# include "asio/detail/gcc_hppa_fenced_block.hpp" -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -# include "asio/detail/gcc_x86_fenced_block.hpp" -#elif defined(__GNUC__) \ - && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ - && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) -# include "asio/detail/gcc_sync_fenced_block.hpp" -#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE) -# include "asio/detail/win_fenced_block.hpp" #else -# include "asio/detail/null_fenced_block.hpp" +# include "asio/detail/std_fenced_block.hpp" #endif namespace asio { @@ -48,26 +30,8 @@ namespace detail { #if !defined(ASIO_HAS_THREADS) \ || defined(ASIO_DISABLE_FENCED_BLOCK) typedef null_fenced_block fenced_block; -#elif defined(__MACH__) && defined(__APPLE__) -typedef macos_fenced_block fenced_block; -#elif defined(__sun) -typedef solaris_fenced_block fenced_block; -#elif defined(__GNUC__) && defined(__arm__) \ - && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) -typedef gcc_arm_fenced_block fenced_block; -#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) -typedef gcc_hppa_fenced_block fenced_block; -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -typedef gcc_x86_fenced_block fenced_block; -#elif defined(__GNUC__) \ - && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ - && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) -typedef gcc_sync_fenced_block fenced_block; -#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE) -typedef win_fenced_block fenced_block; #else -typedef null_fenced_block fenced_block; +typedef std_fenced_block fenced_block; #endif } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/functional.hpp b/3rdparty/asio/include/asio/detail/functional.hpp index a72a5fc69fa..145f9d2a9e1 100644 --- a/3rdparty/asio/include/asio/detail/functional.hpp +++ b/3rdparty/asio/include/asio/detail/functional.hpp @@ -2,7 +2,7 @@ // detail/functional.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,23 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - #include <functional> -#if !defined(ASIO_HAS_STD_FUNCTION) -# include <boost/function.hpp> -#endif // !defined(ASIO_HAS_STD_FUNCTION) - namespace asio { namespace detail { -#if defined(ASIO_HAS_STD_FUNCTION) using std::function; -#else // defined(ASIO_HAS_STD_FUNCTION) -using boost::function; -#endif // defined(ASIO_HAS_STD_FUNCTION) } // namespace detail + +using std::ref; +using std::reference_wrapper; + } // namespace asio #endif // ASIO_DETAIL_FUNCTIONAL_HPP diff --git a/3rdparty/asio/include/asio/detail/future.hpp b/3rdparty/asio/include/asio/detail/future.hpp new file mode 100644 index 00000000000..f33136cbef2 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/future.hpp @@ -0,0 +1,32 @@ +// +// detail/future.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_FUTURE_HPP +#define ASIO_DETAIL_FUTURE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <future> + +// Even though the future header is available, libstdc++ may not implement the +// std::future class itself. However, we need to have already included the +// future header to reliably test for _GLIBCXX_HAS_GTHREADS. +#if defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX) +# if defined(_GLIBCXX_HAS_GTHREADS) +# define ASIO_HAS_STD_FUTURE_CLASS 1 +# endif // defined(_GLIBCXX_HAS_GTHREADS) +#else // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX) +# define ASIO_HAS_STD_FUTURE_CLASS 1 +#endif // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX) + +#endif // ASIO_DETAIL_FUTURE_HPP diff --git a/3rdparty/asio/include/asio/detail/gcc_arm_fenced_block.hpp b/3rdparty/asio/include/asio/detail/gcc_arm_fenced_block.hpp deleted file mode 100644 index debdd3c9f1a..00000000000 --- a/3rdparty/asio/include/asio/detail/gcc_arm_fenced_block.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// -// detail/gcc_arm_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_GCC_ARM_FENCED_BLOCK_HPP -#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(__GNUC__) && defined(__arm__) - -#include "asio/detail/noncopyable.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace detail { - -class gcc_arm_fenced_block - : private noncopyable -{ -public: - enum half_t { half }; - enum full_t { full }; - - // Constructor for a half fenced block. - explicit gcc_arm_fenced_block(half_t) - { - } - - // Constructor for a full fenced block. - explicit gcc_arm_fenced_block(full_t) - { - barrier(); - } - - // Destructor. - ~gcc_arm_fenced_block() - { - barrier(); - } - -private: - static void barrier() - { -#if defined(__ARM_ARCH_4__) \ - || defined(__ARM_ARCH_4T__) \ - || defined(__ARM_ARCH_5__) \ - || defined(__ARM_ARCH_5E__) \ - || defined(__ARM_ARCH_5T__) \ - || defined(__ARM_ARCH_5TE__) \ - || defined(__ARM_ARCH_5TEJ__) \ - || defined(__ARM_ARCH_6__) \ - || defined(__ARM_ARCH_6J__) \ - || defined(__ARM_ARCH_6K__) \ - || defined(__ARM_ARCH_6Z__) \ - || defined(__ARM_ARCH_6ZK__) \ - || defined(__ARM_ARCH_6T2__) -# if defined(__thumb__) - // This is just a placeholder and almost certainly not sufficient. - __asm__ __volatile__ ("" : : : "memory"); -# else // defined(__thumb__) - int a = 0, b = 0; - __asm__ __volatile__ ("swp %0, %1, [%2]" - : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc"); -# endif // defined(__thumb__) -#else - // ARMv7 and later. - __asm__ __volatile__ ("dmb" : : : "memory"); -#endif - } -}; - -} // namespace detail -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(__GNUC__) && defined(__arm__) - -#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP diff --git a/3rdparty/asio/include/asio/detail/gcc_hppa_fenced_block.hpp b/3rdparty/asio/include/asio/detail/gcc_hppa_fenced_block.hpp deleted file mode 100644 index cd41eb28655..00000000000 --- a/3rdparty/asio/include/asio/detail/gcc_hppa_fenced_block.hpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// detail/gcc_hppa_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP -#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) - -#include "asio/detail/noncopyable.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace detail { - -class gcc_hppa_fenced_block - : private noncopyable -{ -public: - enum half_t { half }; - enum full_t { full }; - - // Constructor for a half fenced block. - explicit gcc_hppa_fenced_block(half_t) - { - } - - // Constructor for a full fenced block. - explicit gcc_hppa_fenced_block(full_t) - { - barrier(); - } - - // Destructor. - ~gcc_hppa_fenced_block() - { - barrier(); - } - -private: - static void barrier() - { - // This is just a placeholder and almost certainly not sufficient. - __asm__ __volatile__ ("" : : : "memory"); - } -}; - -} // namespace detail -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) - -#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP diff --git a/3rdparty/asio/include/asio/detail/gcc_sync_fenced_block.hpp b/3rdparty/asio/include/asio/detail/gcc_sync_fenced_block.hpp deleted file mode 100644 index 19330990bee..00000000000 --- a/3rdparty/asio/include/asio/detail/gcc_sync_fenced_block.hpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// detail/gcc_sync_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP -#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(__GNUC__) \ - && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ - && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) - -#include "asio/detail/noncopyable.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace detail { - -class gcc_sync_fenced_block - : private noncopyable -{ -public: - enum half_or_full_t { half, full }; - - // Constructor. - explicit gcc_sync_fenced_block(half_or_full_t) - : value_(0) - { - __sync_lock_test_and_set(&value_, 1); - } - - // Destructor. - ~gcc_sync_fenced_block() - { - __sync_lock_release(&value_); - } - -private: - int value_; -}; - -} // namespace detail -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(__GNUC__) - // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) - // && !defined(__INTEL_COMPILER) && !defined(__ICL) - // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) - -#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP diff --git a/3rdparty/asio/include/asio/detail/gcc_x86_fenced_block.hpp b/3rdparty/asio/include/asio/detail/gcc_x86_fenced_block.hpp deleted file mode 100644 index 0ec66c54ab6..00000000000 --- a/3rdparty/asio/include/asio/detail/gcc_x86_fenced_block.hpp +++ /dev/null @@ -1,99 +0,0 @@ -// -// detail/gcc_x86_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_GCC_X86_FENCED_BLOCK_HPP -#define ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -#include "asio/detail/noncopyable.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace detail { - -class gcc_x86_fenced_block - : private noncopyable -{ -public: - enum half_t { half }; - enum full_t { full }; - - // Constructor for a half fenced block. - explicit gcc_x86_fenced_block(half_t) - { - } - - // Constructor for a full fenced block. - explicit gcc_x86_fenced_block(full_t) - { - lbarrier(); - } - - // Destructor. - ~gcc_x86_fenced_block() - { - sbarrier(); - } - -private: - static int barrier() - { - int r = 0, m = 1; - __asm__ __volatile__ ( - "xchgl %0, %1" : - "=r"(r), "=m"(m) : - "0"(1), "m"(m) : - "memory", "cc"); - return r; - } - - static void lbarrier() - { -#if defined(__SSE2__) -# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) - __builtin_ia32_lfence(); -# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) - __asm__ __volatile__ ("lfence" ::: "memory"); -# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) -#else // defined(__SSE2__) - barrier(); -#endif // defined(__SSE2__) - } - - static void sbarrier() - { -#if defined(__SSE2__) -# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) - __builtin_ia32_sfence(); -# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) - __asm__ __volatile__ ("sfence" ::: "memory"); -# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) -#else // defined(__SSE2__) - barrier(); -#endif // defined(__SSE2__) - } -}; - -} // namespace detail -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/3rdparty/asio/include/asio/detail/global.hpp b/3rdparty/asio/include/asio/detail/global.hpp index 87c57a008e9..59de23a4884 100644 --- a/3rdparty/asio/include/asio/detail/global.hpp +++ b/3rdparty/asio/include/asio/detail/global.hpp @@ -2,7 +2,7 @@ // detail/global.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,10 +23,8 @@ # include "asio/detail/win_global.hpp" #elif defined(ASIO_HAS_PTHREADS) # include "asio/detail/posix_global.hpp" -#elif defined(ASIO_HAS_STD_CALL_ONCE) -# include "asio/detail/std_global.hpp" #else -# error Only Windows, POSIX and std::call_once are supported! +# include "asio/detail/std_global.hpp" #endif namespace asio { @@ -41,7 +39,7 @@ inline T& global() return win_global<T>(); #elif defined(ASIO_HAS_PTHREADS) return posix_global<T>(); -#elif defined(ASIO_HAS_STD_CALL_ONCE) +#else return std_global<T>(); #endif } diff --git a/3rdparty/asio/include/asio/detail/handler_alloc_helpers.hpp b/3rdparty/asio/include/asio/detail/handler_alloc_helpers.hpp index 0658b9883f1..c14d542e48c 100644 --- a/3rdparty/asio/include/asio/detail/handler_alloc_helpers.hpp +++ b/3rdparty/asio/include/asio/detail/handler_alloc_helpers.hpp @@ -2,7 +2,7 @@ // detail/handler_alloc_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,102 +18,112 @@ #include "asio/detail/config.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/thread_info_base.hpp" #include "asio/associated_allocator.hpp" -#include "asio/handler_alloc_hook.hpp" #include "asio/detail/push_options.hpp" -// Calls to asio_handler_allocate and asio_handler_deallocate must be made from -// a namespace that does not contain any overloads of these functions. The -// asio_handler_alloc_helpers namespace is defined here for that purpose. -namespace asio_handler_alloc_helpers { +namespace asio { +namespace detail { -template <typename Handler> -inline void* allocate(std::size_t s, Handler& h) +inline void* default_allocate(std::size_t s, + std::size_t align = ASIO_DEFAULT_ALIGN) { -#if !defined(ASIO_HAS_HANDLER_HOOKS) - return ::operator new(s); -#else - using asio::asio_handler_allocate; - return asio_handler_allocate(s, asio::detail::addressof(h)); -#endif +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return asio::detail::thread_info_base::allocate( + asio::detail::thread_context::top_of_thread_call_stack(), + s, align); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return asio::aligned_new(align, s); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) } -template <typename Handler> -inline void deallocate(void* p, std::size_t s, Handler& h) +inline void default_deallocate(void* p, std::size_t s) { -#if !defined(ASIO_HAS_HANDLER_HOOKS) - ::operator delete(p); -#else - using asio::asio_handler_deallocate; - asio_handler_deallocate(p, s, asio::detail::addressof(h)); -#endif +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + asio::detail::thread_info_base::deallocate( + asio::detail::thread_context::top_of_thread_call_stack(), p, s); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + (void)s; + asio::aligned_delete(p); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) } -} // namespace asio_handler_alloc_helpers - -namespace asio { -namespace detail { - -template <typename Handler, typename T> -class hook_allocator +template <typename T> +class default_allocator { public: + typedef T value_type; + template <typename U> struct rebind { - typedef hook_allocator<Handler, U> other; + typedef default_allocator<U> other; }; - explicit hook_allocator(Handler& h) - : handler_(h) + default_allocator() noexcept { } template <typename U> - hook_allocator(const hook_allocator<Handler, U>& a) - : handler_(a.handler_) + default_allocator(const default_allocator<U>&) noexcept { } T* allocate(std::size_t n) { - return static_cast<T*>( - asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_)); + return static_cast<T*>(default_allocate(sizeof(T) * n, alignof(T))); } void deallocate(T* p, std::size_t n) { - asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_); + default_deallocate(p, sizeof(T) * n); } - -//private: - Handler& handler_; }; -template <typename Handler> -class hook_allocator<Handler, void> +template <> +class default_allocator<void> { public: + typedef void value_type; + template <typename U> struct rebind { - typedef hook_allocator<Handler, U> other; + typedef default_allocator<U> other; }; - explicit hook_allocator(Handler& h) - : handler_(h) + default_allocator() noexcept { } template <typename U> - hook_allocator(const hook_allocator<Handler, U>& a) - : handler_(a.handler_) + default_allocator(const default_allocator<U>&) noexcept { } +}; -//private: - Handler& handler_; +template <typename Allocator> +struct get_default_allocator +{ + typedef Allocator type; + + static type get(const Allocator& a) + { + return a; + } +}; + +template <typename T> +struct get_default_allocator<std::allocator<T>> +{ + typedef default_allocator<T> type; + + static type get(const std::allocator<T>&) + { + return type(); + } }; } // namespace detail @@ -122,9 +132,6 @@ public: #define ASIO_DEFINE_HANDLER_PTR(op) \ struct ptr \ { \ - typedef typename ::asio::associated_allocator<Handler, \ - ::asio::detail::hook_allocator<Handler, \ - void> >::type::template rebind<op>::other allocator_type; \ Handler* h; \ op* v; \ op* p; \ @@ -134,16 +141,18 @@ public: } \ static op* allocate(Handler& handler) \ { \ - allocator_type a(::asio::associated_allocator<Handler, \ - ::asio::detail::hook_allocator<Handler, void> >::get(handler, \ - ::asio::detail::hook_allocator<Handler, void>(handler))); \ + typedef typename ::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::asio::detail::get_default_allocator< \ + associated_allocator_type>::type default_allocator_type; \ + ASIO_REBIND_ALLOC(default_allocator_type, op) a( \ + ::asio::detail::get_default_allocator< \ + associated_allocator_type>::get( \ + ::asio::get_associated_allocator(handler))); \ return a.allocate(1); \ } \ void reset() \ { \ - allocator_type a(::asio::associated_allocator<Handler, \ - ::asio::detail::hook_allocator<Handler, void> >::get(*h, \ - ::asio::detail::hook_allocator<Handler, void>(*h))); \ if (p) \ { \ p->~op(); \ @@ -151,6 +160,14 @@ public: } \ if (v) \ { \ + typedef typename ::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::asio::detail::get_default_allocator< \ + associated_allocator_type>::type default_allocator_type; \ + ASIO_REBIND_ALLOC(default_allocator_type, op) a( \ + ::asio::detail::get_default_allocator< \ + associated_allocator_type>::get( \ + ::asio::get_associated_allocator(*h))); \ a.deallocate(static_cast<op*>(v), 1); \ v = 0; \ } \ @@ -158,16 +175,25 @@ public: } \ /**/ -#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op, alloc) \ +#define ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(purpose, op) \ struct ptr \ { \ - typename alloc::template rebind<op>::other a; \ + const Alloc* a; \ void* v; \ op* p; \ ~ptr() \ { \ reset(); \ } \ + static op* allocate(const Alloc& a) \ + { \ + typedef typename ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::type recycling_allocator_type; \ + ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::get(a)); \ + return a1.allocate(1); \ + } \ void reset() \ { \ if (p) \ @@ -177,13 +203,23 @@ public: } \ if (v) \ { \ - a.deallocate(static_cast<op*>(v), 1); \ + typedef typename ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::type recycling_allocator_type; \ + ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::get(*a)); \ + a1.deallocate(static_cast<op*>(v), 1); \ v = 0; \ } \ } \ } \ /**/ +#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \ + ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( \ + ::asio::detail::thread_info_base::default_tag, op ) \ + /**/ + #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP diff --git a/3rdparty/asio/include/asio/detail/handler_cont_helpers.hpp b/3rdparty/asio/include/asio/detail/handler_cont_helpers.hpp index defdf26525d..9f8f971984f 100644 --- a/3rdparty/asio/include/asio/detail/handler_cont_helpers.hpp +++ b/3rdparty/asio/include/asio/detail/handler_cont_helpers.hpp @@ -2,7 +2,7 @@ // detail/handler_cont_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/handler_invoke_helpers.hpp b/3rdparty/asio/include/asio/detail/handler_invoke_helpers.hpp deleted file mode 100644 index 91325ee9e98..00000000000 --- a/3rdparty/asio/include/asio/detail/handler_invoke_helpers.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// -// detail/handler_invoke_helpers.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_HANDLER_INVOKE_HELPERS_HPP -#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include "asio/detail/memory.hpp" -#include "asio/handler_invoke_hook.hpp" - -#include "asio/detail/push_options.hpp" - -// Calls to asio_handler_invoke must be made from a namespace that does not -// contain overloads of this function. The asio_handler_invoke_helpers -// namespace is defined here for that purpose. -namespace asio_handler_invoke_helpers { - -template <typename Function, typename Context> -inline void invoke(Function& function, Context& context) -{ -#if !defined(ASIO_HAS_HANDLER_HOOKS) - Function tmp(function); - tmp(); -#else - using asio::asio_handler_invoke; - asio_handler_invoke(function, asio::detail::addressof(context)); -#endif -} - -template <typename Function, typename Context> -inline void invoke(const Function& function, Context& context) -{ -#if !defined(ASIO_HAS_HANDLER_HOOKS) - Function tmp(function); - tmp(); -#else - using asio::asio_handler_invoke; - asio_handler_invoke(function, asio::detail::addressof(context)); -#endif -} - -} // namespace asio_handler_invoke_helpers - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP diff --git a/3rdparty/asio/include/asio/detail/handler_tracking.hpp b/3rdparty/asio/include/asio/detail/handler_tracking.hpp index 6ea19a3f10c..f47c777a2d6 100644 --- a/3rdparty/asio/include/asio/detail/handler_tracking.hpp +++ b/3rdparty/asio/include/asio/detail/handler_tracking.hpp @@ -2,7 +2,7 @@ // detail/handler_tracking.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -87,6 +87,28 @@ public: // Initialise the tracking system. ASIO_DECL static void init(); + class location + { + public: + // Constructor adds a location to the stack. + ASIO_DECL explicit location(const char* file, + int line, const char* func); + + // Destructor removes a location from the stack. + ASIO_DECL ~location(); + + private: + // Disallow copying and assignment. + location(const location&) = delete; + location& operator=(const location&) = delete; + + friend class handler_tracking; + const char* file_; + int line_; + const char* func_; + location* next_; + }; + // Record the creation of a tracked handler. ASIO_DECL static void creation( execution_context& context, tracked_handler& h, @@ -175,6 +197,9 @@ private: # define ASIO_HANDLER_TRACKING_INIT \ asio::detail::handler_tracking::init() +# define ASIO_HANDLER_LOCATION(args) \ + asio::detail::handler_tracking::location tracked_location args + # define ASIO_HANDLER_CREATION(args) \ asio::detail::handler_tracking::creation args @@ -211,6 +236,7 @@ private: # define ASIO_INHERIT_TRACKED_HANDLER # define ASIO_ALSO_INHERIT_TRACKED_HANDLER # define ASIO_HANDLER_TRACKING_INIT (void)0 +# define ASIO_HANDLER_LOCATION(loc) (void)0 # define ASIO_HANDLER_CREATION(args) (void)0 # define ASIO_HANDLER_COMPLETION(args) (void)0 # define ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0 diff --git a/3rdparty/asio/include/asio/detail/handler_type_requirements.hpp b/3rdparty/asio/include/asio/detail/handler_type_requirements.hpp index aaa473dd082..54c53b9b6e3 100644 --- a/3rdparty/asio/include/asio/detail/handler_type_requirements.hpp +++ b/3rdparty/asio/include/asio/detail/handler_type_requirements.hpp @@ -2,7 +2,7 @@ // detail/handler_type_requirements.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -53,18 +53,6 @@ # include "asio/async_result.hpp" #endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) -// Newer gcc, clang need special treatment to suppress unused typedef warnings. -#if defined(__clang__) && (__clang_major__ >= 7) -# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) -#elif defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) -# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) -#endif // defined(__GNUC__) -#if !defined(ASIO_UNUSED_TYPEDEF) -# define ASIO_UNUSED_TYPEDEF -#endif // !defined(ASIO_UNUSED_TYPEDEF) - namespace asio { namespace detail { @@ -76,7 +64,7 @@ template <typename Handler> auto zero_arg_copyable_handler_test(Handler h, void*) -> decltype( sizeof(Handler(static_cast<const Handler&>(h))), - ((h)()), + (static_cast<Handler&&>(h)()), char(0)); template <typename Handler> @@ -85,8 +73,8 @@ char (&zero_arg_copyable_handler_test(Handler, ...))[2]; template <typename Handler, typename Arg1> auto one_arg_handler_test(Handler h, Arg1* a1) -> decltype( - sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), - ((h)(*a1)), + sizeof(Handler(static_cast<Handler&&>(h))), + (static_cast<Handler&&>(h)(*a1)), char(0)); template <typename Handler> @@ -95,8 +83,8 @@ char (&one_arg_handler_test(Handler h, ...))[2]; template <typename Handler, typename Arg1, typename Arg2> auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2) -> decltype( - sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), - ((h)(*a1, *a2)), + sizeof(Handler(static_cast<Handler&&>(h))), + (static_cast<Handler&&>(h)(*a1, *a2)), char(0)); template <typename Handler> @@ -105,8 +93,9 @@ char (&two_arg_handler_test(Handler, ...))[2]; template <typename Handler, typename Arg1, typename Arg2> auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2) -> decltype( - sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), - ((h)(*a1, ASIO_MOVE_CAST(Arg2)(*a2))), + sizeof(Handler(static_cast<Handler&&>(h))), + (static_cast<Handler&&>(h)( + *a1, static_cast<Arg2&&>(*a2))), char(0)); template <typename Handler> @@ -125,13 +114,9 @@ template <typename T> T& lvref(); template <typename T> T& lvref(T); template <typename T> const T& clvref(); template <typename T> const T& clvref(T); -#if defined(ASIO_HAS_MOVE) template <typename T> T rvref(); template <typename T> T rvref(T); -#else // defined(ASIO_HAS_MOVE) -template <typename T> const T& rvref(); -template <typename T> const T& rvref(T); -#endif // defined(ASIO_HAS_MOVE) +template <typename T> T rorlvref(); template <typename T> char argbyv(T); template <int> @@ -139,7 +124,7 @@ struct handler_type_requirements { }; -#define ASIO_COMPLETION_HANDLER_CHECK( \ +#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ handler_type, handler) \ \ typedef ASIO_HANDLER_TYPE(handler_type, \ @@ -157,7 +142,7 @@ struct handler_type_requirements asio::detail::clvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()(), \ char(0))> ASIO_UNUSED_TYPEDEF @@ -182,7 +167,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::lvref<const std::size_t>()), \ @@ -209,7 +194,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::lvref<const std::size_t>()), \ @@ -235,7 +220,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>()), \ char(0))> ASIO_UNUSED_TYPEDEF @@ -261,7 +246,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::rvref<socket_type>()), \ @@ -287,7 +272,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>()), \ char(0))> ASIO_UNUSED_TYPEDEF @@ -313,7 +298,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::lvref<const endpoint_type>()), \ @@ -340,7 +325,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::lvref<const iter_type>()), \ @@ -367,7 +352,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::lvref<const range_type>()), \ @@ -393,7 +378,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>()), \ char(0))> ASIO_UNUSED_TYPEDEF @@ -419,7 +404,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::lvref<const int>()), \ @@ -445,7 +430,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>()), \ char(0))> ASIO_UNUSED_TYPEDEF @@ -471,7 +456,7 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>(), \ asio::detail::lvref<const std::size_t>()), \ @@ -497,14 +482,14 @@ struct handler_type_requirements asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ - asio::detail::lvref< \ + asio::detail::rorlvref< \ asio_true_handler_type>()( \ asio::detail::lvref<const asio::error_code>()), \ char(0))> ASIO_UNUSED_TYPEDEF #else // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) -#define ASIO_COMPLETION_HANDLER_CHECK( \ +#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ handler_type, handler) \ typedef int ASIO_UNUSED_TYPEDEF @@ -520,6 +505,10 @@ struct handler_type_requirements handler_type, handler) \ typedef int ASIO_UNUSED_TYPEDEF +#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + typedef int ASIO_UNUSED_TYPEDEF + #define ASIO_CONNECT_HANDLER_CHECK( \ handler_type, handler) \ typedef int ASIO_UNUSED_TYPEDEF diff --git a/3rdparty/asio/include/asio/detail/handler_work.hpp b/3rdparty/asio/include/asio/detail/handler_work.hpp index 327c552434b..596d076327a 100644 --- a/3rdparty/asio/include/asio/detail/handler_work.hpp +++ b/3rdparty/asio/include/asio/detail/handler_work.hpp @@ -2,7 +2,7 @@ // detail/handler_work.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,75 +16,491 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" #include "asio/associated_executor.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/associated_immediate_executor.hpp" +#include "asio/detail/initiate_dispatch.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/work_dispatcher.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/prefer.hpp" #include "asio/detail/push_options.hpp" namespace asio { + +class executor; +class io_context; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +class any_completion_executor; +class any_io_executor; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +namespace execution { + +template <typename...> class any_executor; + +} // namespace execution namespace detail { -// A helper class template to allow completion handlers to be dispatched -// through either the new executors framework or the old invocaton hook. The -// primary template uses the new executors framework. -template <typename Handler, typename Executor - = typename associated_executor<Handler>::type> -class handler_work +template <typename Executor, typename CandidateExecutor = void, + typename IoContext = io_context, + typename PolymorphicExecutor = executor, typename = void> +class handler_work_base { public: - explicit handler_work(Handler& handler) ASIO_NOEXCEPT - : executor_(associated_executor<Handler>::get(handler)) + explicit handler_work_base(int, int, const Executor& ex) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) { } - static void start(Handler& handler) ASIO_NOEXCEPT + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) { - Executor ex(associated_executor<Handler>::get(handler)); - ex.on_work_started(); } - ~handler_work() + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) { - executor_.on_work_finished(); } - template <typename Function> - void complete(Function& function, Handler& handler) + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + bool owns_work() const noexcept + { + return true; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) { - executor_.dispatch(ASIO_MOVE_CAST(Function)(function), - associated_allocator<Handler>::get(handler)); + asio::prefer(executor_, + execution::allocator((get_associated_allocator)(handler)) + ).execute(static_cast<Function&&>(function)); } private: - // Disallow copying and assignment. - handler_work(const handler_work&); - handler_work& operator=(const handler_work&); + typedef decay_t< + prefer_result_t<Executor, execution::outstanding_work_t::tracked_t> + > executor_type; + + executor_type executor_; +}; + +template <typename Executor, typename CandidateExecutor, + typename IoContext, typename PolymorphicExecutor> +class handler_work_base<Executor, CandidateExecutor, + IoContext, PolymorphicExecutor, + enable_if_t< + !execution::is_executor<Executor>::value + && (!is_same<Executor, PolymorphicExecutor>::value + || !is_same<CandidateExecutor, void>::value) + > + > +{ +public: + explicit handler_work_base(int, int, const Executor& ex) noexcept + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const Executor& candidate) noexcept + : executor_(ex), + owns_work_(ex != candidate) + { + if (owns_work_) + executor_.on_work_started(); + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_), + owns_work_(other.owns_work_) + { + if (owns_work_) + executor_.on_work_started(); + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)), + owns_work_(other.owns_work_) + { + other.owns_work_ = false; + } + + ~handler_work_base() + { + if (owns_work_) + executor_.on_work_finished(); + } + + bool owns_work() const noexcept + { + return owns_work_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + executor_.dispatch(static_cast<Function&&>(function), + asio::get_associated_allocator(handler)); + } - typename associated_executor<Handler>::type executor_; +private: + Executor executor_; + bool owns_work_; +}; + +template <typename Executor, typename IoContext, typename PolymorphicExecutor> +class handler_work_base<Executor, void, IoContext, PolymorphicExecutor, + enable_if_t< + is_same< + Executor, + typename IoContext::executor_type + >::value + > + > +{ +public: + explicit handler_work_base(int, int, const Executor&) + { + } + + bool owns_work() const noexcept + { + return false; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + static_cast<Function&&>(function)(); + } +}; + +template <typename Executor, typename IoContext> +class handler_work_base<Executor, void, IoContext, Executor> +{ +public: + explicit handler_work_base(int, int, const Executor& ex) noexcept +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? Executor() : ex) +#else // !defined(ASIO_NO_TYPEID) + : executor_(ex) +#endif // !defined(ASIO_NO_TYPEID) + { + if (executor_) + executor_.on_work_started(); + } + + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const Executor& candidate) noexcept + : executor_(ex != candidate ? ex : Executor()) + { + if (executor_) + executor_.on_work_started(); + } + + template <typename OtherExecutor> + handler_work_base(const Executor& ex, + const OtherExecutor&) noexcept + : executor_(ex) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) + { + if (executor_) + executor_.on_work_started(); + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)) + { + } + + ~handler_work_base() + { + if (executor_) + executor_.on_work_finished(); + } + + bool owns_work() const noexcept + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + executor_.dispatch(static_cast<Function&&>(function), + asio::get_associated_allocator(handler)); + } + +private: + Executor executor_; }; -// This specialisation dispatches a handler through the old invocation hook. -// The specialisation is not strictly required for correctness, as the -// system_executor will dispatch through the hook anyway. However, by doing -// this we avoid an extra copy of the handler. -template <typename Handler> -class handler_work<Handler, system_executor> +template <typename... SupportableProperties, typename CandidateExecutor, + typename IoContext, typename PolymorphicExecutor> +class handler_work_base<execution::any_executor<SupportableProperties...>, + CandidateExecutor, IoContext, PolymorphicExecutor> { public: - explicit handler_work(Handler&) ASIO_NOEXCEPT {} - static void start(Handler&) ASIO_NOEXCEPT {} - ~handler_work() {} + typedef execution::any_executor<SupportableProperties...> executor_type; + + explicit handler_work_base(int, int, const executor_type& ex) noexcept +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(bool base1_owns_work, const executor_type& ex, + const executor_type& candidate) noexcept + : executor_( + !base1_owns_work && ex == candidate + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) + { + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + bool owns_work() const noexcept + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + executor_.execute(static_cast<Function&&>(function)); + } + +private: + executor_type executor_; +}; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template <typename Executor, typename CandidateExecutor, + typename IoContext, typename PolymorphicExecutor> +class handler_work_base< + Executor, CandidateExecutor, + IoContext, PolymorphicExecutor, + enable_if_t< + is_same<Executor, any_completion_executor>::value + || is_same<Executor, any_io_executor>::value + > + > +{ +public: + typedef Executor executor_type; + + explicit handler_work_base(int, int, + const executor_type& ex) noexcept +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(bool base1_owns_work, const executor_type& ex, + const executor_type& candidate) noexcept + : executor_( + !base1_owns_work && ex == candidate + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) + { + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + bool owns_work() const noexcept + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + executor_.execute(static_cast<Function&&>(function)); + } + +private: + executor_type executor_; +}; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template <typename Handler, typename IoExecutor, typename = void> +class handler_work : + handler_work_base<IoExecutor>, + handler_work_base<associated_executor_t<Handler, IoExecutor>, IoExecutor> +{ +public: + typedef handler_work_base<IoExecutor> base1_type; + typedef handler_work_base<associated_executor_t<Handler, IoExecutor>, + IoExecutor> base2_type; + + handler_work(Handler& handler, const IoExecutor& io_ex) noexcept + : base1_type(0, 0, io_ex), + base2_type(base1_type::owns_work(), + asio::get_associated_executor(handler, io_ex), io_ex) + { + } + + template <typename Function> + void complete(Function& function, Handler& handler) + { + if (!base1_type::owns_work() && !base2_type::owns_work()) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + static_cast<Function&&>(function)(); + } + else + { + base2_type::dispatch(function, handler); + } + } +}; + +template <typename Handler, typename IoExecutor> +class handler_work< + Handler, IoExecutor, + enable_if_t< + is_same< + typename associated_executor<Handler, + IoExecutor>::asio_associated_executor_is_unspecialised, + void + >::value + > + > : handler_work_base<IoExecutor> +{ +public: + typedef handler_work_base<IoExecutor> base1_type; + + handler_work(Handler&, const IoExecutor& io_ex) noexcept + : base1_type(0, 0, io_ex) + { + } template <typename Function> void complete(Function& function, Handler& handler) { - asio_handler_invoke_helpers::invoke(function, handler); + if (!base1_type::owns_work()) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + static_cast<Function&&>(function)(); + } + else + { + base1_type::dispatch(function, handler); + } + } +}; + +template <typename Handler, typename IoExecutor> +class immediate_handler_work +{ +public: + typedef handler_work<Handler, IoExecutor> handler_work_type; + + explicit immediate_handler_work(handler_work_type&& w) + : handler_work_(static_cast<handler_work_type&&>(w)) + { + } + + template <typename Function> + void complete(Function& function, Handler& handler, const void* io_ex) + { + typedef associated_immediate_executor_t<Handler, IoExecutor> + immediate_ex_type; + + immediate_ex_type immediate_ex = (get_associated_immediate_executor)( + handler, *static_cast<const IoExecutor*>(io_ex)); + + (initiate_dispatch_with_executor<immediate_ex_type>(immediate_ex))( + static_cast<Function&&>(function)); } private: - // Disallow copying and assignment. - handler_work(const handler_work&); - handler_work& operator=(const handler_work&); + handler_work_type handler_work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/hash_map.hpp b/3rdparty/asio/include/asio/detail/hash_map.hpp index 8c52edcd3f1..e23de914a18 100644 --- a/3rdparty/asio/include/asio/detail/hash_map.hpp +++ b/3rdparty/asio/include/asio/detail/hash_map.hpp @@ -2,7 +2,7 @@ // detail/hash_map.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp b/3rdparty/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp index 9bf955f917c..372ce426e57 100644 --- a/3rdparty/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp +++ b/3rdparty/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp @@ -2,7 +2,7 @@ // detail/impl/buffer_sequence_adapter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp b/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp index 07355e83eae..c56a512e462 100644 --- a/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp +++ b/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp @@ -2,7 +2,7 @@ // detail/impl/descriptor_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -32,10 +32,16 @@ namespace descriptor_ops { int open(const char* path, int flags, asio::error_code& ec) { - errno = 0; - int result = error_wrapper(::open(path, flags), ec); - if (result >= 0) - ec = asio::error_code(); + int result = ::open(path, flags); + get_last_error(ec, result < 0); + return result; +} + +int open(const char* path, int flags, + unsigned mode, asio::error_code& ec) +{ + int result = ::open(path, flags, mode); + get_last_error(ec, result < 0); return result; } @@ -44,8 +50,8 @@ int close(int d, state_type& state, asio::error_code& ec) int result = 0; if (d != -1) { - errno = 0; - result = error_wrapper(::close(d), ec); + result = ::close(d); + get_last_error(ec, result < 0); if (result != 0 && (ec == asio::error::would_block @@ -57,23 +63,39 @@ int close(int d, state_type& state, asio::error_code& ec) // current OS where this behaviour is seen, Windows, says that the socket // remains open. Therefore we'll put the descriptor back into blocking // mode and have another attempt at closing it. -#if defined(__SYMBIAN32__) +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int flags = ::fcntl(d, F_GETFL, 0); if (flags >= 0) ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); -#else // defined(__SYMBIAN32__) +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = 0; +# if defined(ENOTTY) || defined(ENOTCAPABLE) + result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + int flags = ::fcntl(d, F_GETFL, 0); + if (flags >= 0) + ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); + } +# else // defined(ENOTTY) || defined(ENOTCAPABLE) ::ioctl(d, FIONBIO, &arg); -#endif // defined(__SYMBIAN32__) +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) state &= ~non_blocking; - errno = 0; - result = error_wrapper(::close(d), ec); + result = ::close(d); + get_last_error(ec, result < 0); } } - if (result == 0) - ec = asio::error_code(); return result; } @@ -86,23 +108,43 @@ bool set_user_non_blocking(int d, state_type& state, return false; } - errno = 0; -#if defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - errno = 0; int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); } -#else // defined(__SYMBIAN32__) +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); -#endif // defined(__SYMBIAN32__) + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); +# if defined(ENOTTY) || defined(ENOTCAPABLE) + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); + } + } +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = asio::error_code(); if (value) state |= user_set_non_blocking; else @@ -136,23 +178,43 @@ bool set_internal_non_blocking(int d, state_type& state, return false; } - errno = 0; -#if defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - errno = 0; int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); } -#else // defined(__SYMBIAN32__) +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); -#endif // defined(__SYMBIAN32__) + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); +# if defined(ENOTTY) || defined(ENOTCAPABLE) + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); + } + } +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = asio::error_code(); if (value) state |= internal_non_blocking; else @@ -175,7 +237,53 @@ std::size_t sync_read(int d, state_type state, buf* bufs, // A request to read 0 bytes on a stream is a no-op. if (all_empty) { - ec = asio::error_code(); + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_read1(int d, state_type state, void* data, + std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); return 0; } @@ -183,9 +291,8 @@ std::size_t sync_read(int d, state_type state, buf* bufs, for (;;) { // Try to complete the operation without blocking. - errno = 0; - signed_size_type bytes = error_wrapper(::readv( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes > 0) @@ -216,9 +323,8 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, for (;;) { // Read some data. - errno = 0; - signed_size_type bytes = error_wrapper(::readv( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); // Check for end of stream. if (bytes == 0) @@ -227,6 +333,13 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, return true; } + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -236,15 +349,46 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_read1(int d, void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); + + // Check for end of stream. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. if (bytes > 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -261,7 +405,46 @@ std::size_t sync_write(int d, state_type state, const buf* bufs, // A request to write 0 bytes on a stream is a no-op. if (all_empty) { - ec = asio::error_code(); + asio::error::clear(ec); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_write1(int d, state_type state, const void* data, + std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); return 0; } @@ -269,9 +452,8 @@ std::size_t sync_write(int d, state_type state, const buf* bufs, for (;;) { // Try to complete the operation without blocking. - errno = 0; - signed_size_type bytes = error_wrapper(::writev( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes > 0) @@ -295,9 +477,15 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, for (;;) { // Write some data. - errno = 0; - signed_size_type bytes = error_wrapper(::writev( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) @@ -308,19 +496,360 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_write1(int d, const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } +#if defined(ASIO_HAS_FILE) + +std::size_t sync_read_at(int d, state_type state, uint64_t offset, + buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::preadv(d, bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_read_at1(int d, state_type state, uint64_t offset, + void* data, std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::pread(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_read_at(int d, uint64_t offset, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::preadv(d, bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_read_at1(int d, uint64_t offset, void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::pread(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +std::size_t sync_write_at(int d, state_type state, uint64_t offset, + const buf* bufs, std::size_t count, bool all_empty, + asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + asio::error::clear(ec); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::pwritev(d, + bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_write_at1(int d, state_type state, uint64_t offset, + const void* data, std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::pwrite(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_write_at(int d, uint64_t offset, + const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::pwritev(d, + bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_write_at1(int d, uint64_t offset, + const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::pwrite(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +#endif // defined(ASIO_HAS_FILE) + int ioctl(int d, state_type& state, long cmd, ioctl_arg_type* arg, asio::error_code& ec) { @@ -330,13 +859,11 @@ int ioctl(int d, state_type& state, long cmd, return -1; } - errno = 0; - int result = error_wrapper(::ioctl(d, cmd, arg), ec); + int result = ::ioctl(d, cmd, arg); + get_last_error(ec, result < 0); if (result >= 0) { - ec = asio::error_code(); - // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the descriptor is // already in the correct state. This ensures that the underlying @@ -370,10 +897,8 @@ int fcntl(int d, int cmd, asio::error_code& ec) return -1; } - errno = 0; - int result = error_wrapper(::fcntl(d, cmd), ec); - if (result != -1) - ec = asio::error_code(); + int result = ::fcntl(d, cmd); + get_last_error(ec, result < 0); return result; } @@ -385,10 +910,8 @@ int fcntl(int d, int cmd, long arg, asio::error_code& ec) return -1; } - errno = 0; - int result = error_wrapper(::fcntl(d, cmd, arg), ec); - if (result != -1) - ec = asio::error_code(); + int result = ::fcntl(d, cmd, arg); + get_last_error(ec, result < 0); return result; } @@ -405,13 +928,11 @@ int poll_read(int d, state_type state, asio::error_code& ec) fds.events = POLLIN; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -428,13 +949,11 @@ int poll_write(int d, state_type state, asio::error_code& ec) fds.events = POLLOUT; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -451,13 +970,11 @@ int poll_error(int d, state_type state, asio::error_code& ec) fds.events = POLLPRI | POLLERR | POLLHUP; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } diff --git a/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.hpp b/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.hpp index f6c00a51583..b483e44fd1c 100644 --- a/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.hpp @@ -2,7 +2,7 @@ // detail/impl/dev_poll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,11 +19,19 @@ #if defined(ASIO_HAS_DEV_POLL) +#include "asio/detail/scheduler.hpp" + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +inline void dev_poll_reactor::post_immediate_completion( + operation* op, bool is_continuation) const +{ + scheduler_.post_immediate_completion(op, is_continuation); +} + template <typename Time_Traits> void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { @@ -69,6 +77,18 @@ std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, } template <typename Time_Traits> +void dev_poll_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer_by_key(timer, ops, cancellation_key); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +template <typename Time_Traits> void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) diff --git a/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.ipp b/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.ipp index ac0cedea65b..c9c53fbeafd 100644 --- a/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.ipp +++ b/3rdparty/asio/include/asio/detail/impl/dev_poll_reactor.ipp @@ -2,7 +2,7 @@ // detail/impl/dev_poll_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -21,6 +21,7 @@ #include "asio/detail/dev_poll_reactor.hpp" #include "asio/detail/assert.hpp" +#include "asio/detail/scheduler.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" @@ -67,7 +68,8 @@ void dev_poll_reactor::shutdown() scheduler_.abandon_operations(ops); } -void dev_poll_reactor::notify_fork(asio::io_context::fork_event fork_ev) +void dev_poll_reactor::notify_fork( + asio::execution_context::fork_event fork_ev) { if (fork_ev == asio::execution_context::fork_child) { @@ -146,15 +148,24 @@ void dev_poll_reactor::move_descriptor(socket_type, { } +void dev_poll_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast<const dev_poll_reactor*>(self)->post_immediate_completion( + op, is_continuation); +} + void dev_poll_reactor::start_op(int op_type, socket_type descriptor, dev_poll_reactor::per_descriptor_data&, reactor_op* op, - bool is_continuation, bool allow_speculative) + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -167,7 +178,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor, if (op->perform()) { lock.unlock(); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } @@ -200,6 +211,19 @@ void dev_poll_reactor::cancel_ops(socket_type descriptor, cancel_ops_unlocked(descriptor, asio::error::operation_aborted); } +void dev_poll_reactor::cancel_ops_by_key(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, + int op_type, void* cancellation_key) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + bool need_interrupt = op_queue_[op_type].cancel_operations_by_key( + descriptor, ops, cancellation_key, asio::error::operation_aborted); + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + void dev_poll_reactor::deregister_descriptor(socket_type descriptor, dev_poll_reactor::per_descriptor_data&, bool) { @@ -234,13 +258,18 @@ void dev_poll_reactor::deregister_internal_descriptor( op_queue_[i].cancel_operations(descriptor, ops, ec); } +void dev_poll_reactor::cleanup_descriptor_data( + dev_poll_reactor::per_descriptor_data&) +{ +} + void dev_poll_reactor::run(long usec, op_queue<operation>& ops) { asio::detail::mutex::scoped_lock lock(mutex_); // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() + if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty() && op_queue_[except_op].empty() && timer_queues_.all_empty()) return; diff --git a/3rdparty/asio/include/asio/detail/impl/epoll_reactor.hpp b/3rdparty/asio/include/asio/detail/impl/epoll_reactor.hpp index a90665405b0..4fffeb75924 100644 --- a/3rdparty/asio/include/asio/detail/impl/epoll_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/impl/epoll_reactor.hpp @@ -2,7 +2,7 @@ // detail/impl/epoll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,11 +17,19 @@ #if defined(ASIO_HAS_EPOLL) +#include "asio/detail/scheduler.hpp" + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +inline void epoll_reactor::post_immediate_completion( + operation* op, bool is_continuation) const +{ + scheduler_.post_immediate_completion(op, is_continuation); +} + template <typename Time_Traits> void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { @@ -67,6 +75,18 @@ std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, } template <typename Time_Traits> +void epoll_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer_by_key(timer, ops, cancellation_key); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +template <typename Time_Traits> void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) diff --git a/3rdparty/asio/include/asio/detail/impl/epoll_reactor.ipp b/3rdparty/asio/include/asio/detail/impl/epoll_reactor.ipp index 382061ed90d..51795bda40c 100644 --- a/3rdparty/asio/include/asio/detail/impl/epoll_reactor.ipp +++ b/3rdparty/asio/include/asio/detail/impl/epoll_reactor.ipp @@ -2,7 +2,7 @@ // detail/impl/epoll_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,6 +22,7 @@ #include <cstddef> #include <sys/epoll.h> #include "asio/detail/epoll_reactor.hpp" +#include "asio/detail/scheduler.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" @@ -38,7 +39,7 @@ epoll_reactor::epoll_reactor(asio::execution_context& ctx) : execution_context_service_base<epoll_reactor>(ctx), scheduler_(use_service<scheduler>(ctx)), mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( - SCHEDULER, scheduler_.concurrency_hint())), + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), interrupter_(), epoll_fd_(do_epoll_create()), timer_fd_(do_timerfd_create()), @@ -228,14 +229,23 @@ void epoll_reactor::move_descriptor(socket_type, source_descriptor_data = 0; } +void epoll_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast<const epoll_reactor*>(self)->post_immediate_completion( + op, is_continuation); +} + void epoll_reactor::start_op(int op_type, socket_type descriptor, epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative) + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { if (!descriptor_data) { op->ec_ = asio::error::bad_descriptor; - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -243,7 +253,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -261,7 +271,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->registered_events_ != 0) descriptor_data->try_speculative_[op_type] = false; descriptor_lock.unlock(); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } @@ -269,7 +279,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->registered_events_ == 0) { op->ec_ = asio::error::operation_not_supported; - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -288,7 +298,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, { op->ec_ = asio::error_code(errno, asio::error::get_system_category()); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } @@ -297,7 +307,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, else if (descriptor_data->registered_events_ == 0) { op->ec_ = asio::error::operation_not_supported; - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } else @@ -342,6 +352,35 @@ void epoll_reactor::cancel_ops(socket_type, scheduler_.post_deferred_completions(ops); } +void epoll_reactor::cancel_ops_by_key(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data, + int op_type, void* cancellation_key) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue<operation> ops; + op_queue<reactor_op> other_ops; + while (reactor_op* op = descriptor_data->op_queue_[op_type].front()) + { + descriptor_data->op_queue_[op_type].pop(); + if (op->cancellation_key_ == cancellation_key) + { + op->ec_ = asio::error::operation_aborted; + ops.push(op); + } + else + other_ops.push(op); + } + descriptor_data->op_queue_[op_type].push(other_ops); + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + void epoll_reactor::deregister_descriptor(socket_type descriptor, epoll_reactor::per_descriptor_data& descriptor_data, bool closing) { @@ -383,10 +422,16 @@ void epoll_reactor::deregister_descriptor(socket_type descriptor, context(), static_cast<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(descriptor_data))); - free_descriptor_state(descriptor_data); - descriptor_data = 0; - scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; } } @@ -416,6 +461,22 @@ void epoll_reactor::deregister_internal_descriptor(socket_type descriptor, context(), static_cast<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(descriptor_data))); + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void epoll_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { free_descriptor_state(descriptor_data); descriptor_data = 0; } @@ -462,6 +523,7 @@ void epoll_reactor::run(long usec, op_queue<operation>& ops) // Ignore. } # endif // defined(ASIO_HAS_TIMERFD) + else { unsigned event_mask = 0; if ((events[i].events & EPOLLIN) != 0) @@ -512,8 +574,15 @@ void epoll_reactor::run(long usec, op_queue<operation>& ops) // don't call work_started() here. This still allows the scheduler to // stop if the only remaining operations are descriptor operations. descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); - descriptor_data->set_ready_events(events[i].events); - ops.push(descriptor_data); + if (!ops.is_enqueued(descriptor_data)) + { + descriptor_data->set_ready_events(events[i].events); + ops.push(descriptor_data); + } + else + { + descriptor_data->add_ready_events(events[i].events); + } } } @@ -594,7 +663,8 @@ int epoll_reactor::do_timerfd_create() epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state() { mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - return registered_descriptors_.alloc(registered_descriptors_mutex_.enabled()); + return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); } void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s) diff --git a/3rdparty/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp b/3rdparty/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp index 152bffd213a..2e970d8850b 100644 --- a/3rdparty/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp +++ b/3rdparty/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp @@ -2,7 +2,7 @@ // detail/impl/eventfd_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -23,11 +23,11 @@ #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) # include <asm/unistd.h> -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) # include <sys/eventfd.h> -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) #include "asio/detail/cstdint.hpp" #include "asio/detail/eventfd_select_interrupter.hpp" #include "asio/detail/throw_error.hpp" @@ -45,14 +45,14 @@ eventfd_select_interrupter::eventfd_select_interrupter() void eventfd_select_interrupter::open_descriptors() { -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); if (read_descriptor_ != -1) { ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); } -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) # if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) write_descriptor_ = read_descriptor_ = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); @@ -69,7 +69,7 @@ void eventfd_select_interrupter::open_descriptors() ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); } } -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) if (read_descriptor_ == -1) { @@ -134,8 +134,7 @@ bool eventfd_select_interrupter::reset() int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); if (bytes_read < 0 && errno == EINTR) continue; - bool was_interrupted = (bytes_read > 0); - return was_interrupted; + return true; } } else @@ -145,12 +144,19 @@ bool eventfd_select_interrupter::reset() // Clear all data from the pipe. char data[1024]; int bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) + if (bytes_read == sizeof(data)) + continue; + if (bytes_read > 0) + return true; + if (bytes_read == 0) + return false; + if (errno == EINTR) continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; + if (errno == EWOULDBLOCK) + return true; + if (errno == EAGAIN) + return true; + return false; } } } diff --git a/3rdparty/asio/include/asio/detail/impl/handler_tracking.ipp b/3rdparty/asio/include/asio/detail/impl/handler_tracking.ipp index 7e628d0b5f1..f4e3e3b501a 100644 --- a/3rdparty/asio/include/asio/detail/impl/handler_tracking.ipp +++ b/3rdparty/asio/include/asio/detail/impl/handler_tracking.ipp @@ -2,7 +2,7 @@ // detail/impl/handler_tracking.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -29,7 +29,7 @@ #if defined(ASIO_HAS_BOOST_DATE_TIME) # include "asio/time_traits.hpp" -#elif defined(ASIO_HAS_CHRONO) +#else // defined(ASIO_HAS_BOOST_DATE_TIME) # include "asio/detail/chrono.hpp" # include "asio/detail/chrono_time_traits.hpp" # include "asio/wait_traits.hpp" @@ -57,12 +57,12 @@ struct handler_tracking_timestamp boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); boost::posix_time::time_duration now = boost::posix_time::microsec_clock::universal_time() - epoch; -#elif defined(ASIO_HAS_CHRONO) +#else // defined(ASIO_HAS_BOOST_DATE_TIME) typedef chrono_time_traits<chrono::system_clock, - asio::wait_traits<chrono::system_clock> > traits_helper; + asio::wait_traits<chrono::system_clock>> traits_helper; traits_helper::posix_time_duration now( chrono::system_clock::now().time_since_epoch()); -#endif +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) seconds = static_cast<uint64_t>(now.total_seconds()); microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000); } @@ -73,11 +73,12 @@ struct handler_tracking::tracking_state static_mutex mutex_; uint64_t next_id_; tss_ptr<completion>* current_completion_; + tss_ptr<location>* current_location_; }; handler_tracking::tracking_state* handler_tracking::get_state() { - static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0 }; + static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0, 0 }; return &state; } @@ -90,6 +91,25 @@ void handler_tracking::init() static_mutex::scoped_lock lock(state->mutex_); if (state->current_completion_ == 0) state->current_completion_ = new tss_ptr<completion>; + if (state->current_location_ == 0) + state->current_location_ = new tss_ptr<location>; +} + +handler_tracking::location::location( + const char* file, int line, const char* func) + : file_(file), + line_(line), + func_(func), + next_(*get_state()->current_location_) +{ + if (file_) + *get_state()->current_location_ = this; +} + +handler_tracking::location::~location() +{ + if (file_) + *get_state()->current_location_ = next_; } void handler_tracking::creation(execution_context&, @@ -109,6 +129,24 @@ void handler_tracking::creation(execution_context&, if (completion* current_completion = *state->current_completion_) current_id = current_completion->id_; + for (location* current_location = *state->current_location_; + current_location; current_location = current_location->next_) + { + write_line( +#if defined(ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n", +#else // defined(ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n", +#endif // defined(ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, h.id_, + current_location == *state->current_location_ ? "in " : "called from ", + current_location->func_ ? "'" : "", + current_location->func_ ? current_location->func_ : "", + current_location->func_ ? "' " : "", + current_location->file_, current_location->line_); + } + write_line( #if defined(ASIO_WINDOWS) "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n", @@ -327,7 +365,9 @@ void handler_tracking::write_line(const char* format, ...) va_start(args, format); char line[256] = ""; -#if defined(ASIO_HAS_SECURE_RTL) +#if defined(ASIO_HAS_SNPRINTF) + int length = vsnprintf(line, sizeof(line), format, args); +#elif defined(ASIO_HAS_SECURE_RTL) int length = vsprintf_s(line, sizeof(line), format, args); #else // defined(ASIO_HAS_SECURE_RTL) int length = vsprintf(line, format, args); diff --git a/3rdparty/asio/include/asio/detail/impl/io_uring_descriptor_service.ipp b/3rdparty/asio/include/asio/detail/impl/io_uring_descriptor_service.ipp new file mode 100644 index 00000000000..21b9e232cfb --- /dev/null +++ b/3rdparty/asio/include/asio/detail/impl/io_uring_descriptor_service.ipp @@ -0,0 +1,205 @@ +// +// detail/impl/io_uring_descriptor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_IPP +#define ASIO_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/error.hpp" +#include "asio/detail/io_uring_descriptor_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +io_uring_descriptor_service::io_uring_descriptor_service( + execution_context& context) + : execution_context_service_base<io_uring_descriptor_service>(context), + io_uring_service_(asio::use_service<io_uring_service>(context)) +{ + io_uring_service_.init_task(); +} + +void io_uring_descriptor_service::shutdown() +{ +} + +void io_uring_descriptor_service::construct( + io_uring_descriptor_service::implementation_type& impl) +{ + impl.descriptor_ = -1; + impl.state_ = 0; + impl.io_object_data_ = 0; +} + +void io_uring_descriptor_service::move_construct( + io_uring_descriptor_service::implementation_type& impl, + io_uring_descriptor_service::implementation_type& other_impl) + noexcept +{ + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.io_object_data_ = other_impl.io_object_data_; + other_impl.io_object_data_ = 0; +} + +void io_uring_descriptor_service::move_assign( + io_uring_descriptor_service::implementation_type& impl, + io_uring_descriptor_service& /*other_service*/, + io_uring_descriptor_service::implementation_type& other_impl) +{ + destroy(impl); + + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.io_object_data_ = other_impl.io_object_data_; + other_impl.io_object_data_ = 0; +} + +void io_uring_descriptor_service::destroy( + io_uring_descriptor_service::implementation_type& impl) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + io_uring_service_.deregister_io_object(impl.io_object_data_); + asio::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); + io_uring_service_.cleanup_io_object(impl.io_object_data_); + } +} + +asio::error_code io_uring_descriptor_service::assign( + io_uring_descriptor_service::implementation_type& impl, + const native_handle_type& native_descriptor, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); + return ec; + } + + io_uring_service_.register_io_object(impl.io_object_data_); + + impl.descriptor_ = native_descriptor; + impl.state_ = descriptor_ops::possible_dup; + ec = success_ec_; + return ec; +} + +asio::error_code io_uring_descriptor_service::close( + io_uring_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + io_uring_service_.deregister_io_object(impl.io_object_data_); + descriptor_ops::close(impl.descriptor_, impl.state_, ec); + io_uring_service_.cleanup_io_object(impl.io_object_data_); + } + else + { + ec = success_ec_; + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + construct(impl); + + ASIO_ERROR_LOCATION(ec); + return ec; +} + +io_uring_descriptor_service::native_handle_type +io_uring_descriptor_service::release( + io_uring_descriptor_service::implementation_type& impl) +{ + native_handle_type descriptor = impl.descriptor_; + + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "descriptor", &impl, impl.descriptor_, "release")); + + io_uring_service_.deregister_io_object(impl.io_object_data_); + io_uring_service_.cleanup_io_object(impl.io_object_data_); + construct(impl); + } + + return descriptor; +} + +asio::error_code io_uring_descriptor_service::cancel( + io_uring_descriptor_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + ASIO_ERROR_LOCATION(ec); + return ec; + } + + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "descriptor", &impl, impl.descriptor_, "cancel")); + + io_uring_service_.cancel_ops(impl.io_object_data_); + ec = success_ec_; + return ec; +} + +void io_uring_descriptor_service::start_op( + io_uring_descriptor_service::implementation_type& impl, + int op_type, io_uring_operation* op, bool is_continuation, bool noop) +{ + if (!noop) + { + io_uring_service_.start_op(op_type, + impl.io_object_data_, op, is_continuation); + } + else + { + io_uring_service_.post_immediate_completion(op, is_continuation); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/io_uring_file_service.ipp b/3rdparty/asio/include/asio/detail/impl/io_uring_file_service.ipp new file mode 100644 index 00000000000..4742a7190d3 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/impl/io_uring_file_service.ipp @@ -0,0 +1,140 @@ +// +// detail/impl/io_uring_file_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_IO_URING_FILE_SERVICE_IPP +#define ASIO_DETAIL_IMPL_IO_URING_FILE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + && defined(ASIO_HAS_IO_URING) + +#include <cstring> +#include <sys/stat.h> +#include "asio/detail/io_uring_file_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +io_uring_file_service::io_uring_file_service( + execution_context& context) + : execution_context_service_base<io_uring_file_service>(context), + descriptor_service_(context) +{ +} + +void io_uring_file_service::shutdown() +{ + descriptor_service_.shutdown(); +} + +asio::error_code io_uring_file_service::open( + io_uring_file_service::implementation_type& impl, + const char* path, file_base::flags open_flags, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); + return ec; + } + + descriptor_ops::state_type state = 0; + int fd = descriptor_ops::open(path, static_cast<int>(open_flags), 0777, ec); + if (fd < 0) + { + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + asio::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + } + + (void)::posix_fadvise(native_handle(impl), 0, 0, + impl.is_stream_ ? POSIX_FADV_SEQUENTIAL : POSIX_FADV_RANDOM); + + ASIO_ERROR_LOCATION(ec); + return ec; +} + +uint64_t io_uring_file_service::size( + const io_uring_file_service::implementation_type& impl, + asio::error_code& ec) const +{ + struct stat s; + int result = ::fstat(native_handle(impl), &s); + descriptor_ops::get_last_error(ec, result != 0); + ASIO_ERROR_LOCATION(ec); + return !ec ? s.st_size : 0; +} + +asio::error_code io_uring_file_service::resize( + io_uring_file_service::implementation_type& impl, + uint64_t n, asio::error_code& ec) +{ + int result = ::ftruncate(native_handle(impl), n); + descriptor_ops::get_last_error(ec, result != 0); + ASIO_ERROR_LOCATION(ec); + return ec; +} + +asio::error_code io_uring_file_service::sync_all( + io_uring_file_service::implementation_type& impl, + asio::error_code& ec) +{ + int result = ::fsync(native_handle(impl)); + descriptor_ops::get_last_error(ec, result != 0); + return ec; +} + +asio::error_code io_uring_file_service::sync_data( + io_uring_file_service::implementation_type& impl, + asio::error_code& ec) +{ +#if defined(_POSIX_SYNCHRONIZED_IO) + int result = ::fdatasync(native_handle(impl)); +#else // defined(_POSIX_SYNCHRONIZED_IO) + int result = ::fsync(native_handle(impl)); +#endif // defined(_POSIX_SYNCHRONIZED_IO) + descriptor_ops::get_last_error(ec, result != 0); + ASIO_ERROR_LOCATION(ec); + return ec; +} + +uint64_t io_uring_file_service::seek( + io_uring_file_service::implementation_type& impl, int64_t offset, + file_base::seek_basis whence, asio::error_code& ec) +{ + int64_t result = ::lseek(native_handle(impl), offset, whence); + descriptor_ops::get_last_error(ec, result < 0); + ASIO_ERROR_LOCATION(ec); + return !ec ? static_cast<uint64_t>(result) : 0; +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_FILE) + // && defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IMPL_IO_URING_FILE_SERVICE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/io_uring_service.hpp b/3rdparty/asio/include/asio/detail/impl/io_uring_service.hpp new file mode 100644 index 00000000000..8dfab1e6d1d --- /dev/null +++ b/3rdparty/asio/include/asio/detail/impl/io_uring_service.hpp @@ -0,0 +1,112 @@ +// +// detail/impl/io_uring_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_IO_URING_SERVICE_HPP +#define ASIO_DETAIL_IMPL_IO_URING_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/scheduler.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +inline void io_uring_service::post_immediate_completion( + operation* op, bool is_continuation) +{ + scheduler_.post_immediate_completion(op, is_continuation); +} + +template <typename Time_Traits> +void io_uring_service::add_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_add_timer_queue(queue); +} + +template <typename Time_Traits> +void io_uring_service::remove_timer_queue(timer_queue<Time_Traits>& queue) +{ + do_remove_timer_queue(queue); +} + +template <typename Time_Traits> +void io_uring_service::schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + { + update_timeout(); + post_submit_sqes_op(lock); + } +} + +template <typename Time_Traits> +std::size_t io_uring_service::cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template <typename Time_Traits> +void io_uring_service::cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer_by_key(timer, ops, cancellation_key); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +template <typename Time_Traits> +void io_uring_service::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IMPL_IO_URING_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/impl/io_uring_service.ipp b/3rdparty/asio/include/asio/detail/impl/io_uring_service.ipp new file mode 100644 index 00000000000..740010cda11 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/impl/io_uring_service.ipp @@ -0,0 +1,914 @@ +// +// detail/impl/io_uring_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_IO_URING_SERVICE_IPP +#define ASIO_DETAIL_IMPL_IO_URING_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include <cstddef> +#include <sys/eventfd.h> +#include "asio/detail/io_uring_service.hpp" +#include "asio/detail/reactor_op.hpp" +#include "asio/detail/scheduler.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +io_uring_service::io_uring_service(asio::execution_context& ctx) + : execution_context_service_base<io_uring_service>(ctx), + scheduler_(use_service<scheduler>(ctx)), + mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), + outstanding_work_(0), + submit_sqes_op_(this), + pending_sqes_(0), + pending_submit_sqes_op_(false), + shutdown_(false), + timeout_(), + registration_mutex_(mutex_.enabled()), + reactor_(use_service<reactor>(ctx)), + reactor_data_(), + event_fd_(-1) +{ + reactor_.init_task(); + init_ring(); + register_with_reactor(); +} + +io_uring_service::~io_uring_service() +{ + if (ring_.ring_fd != -1) + ::io_uring_queue_exit(&ring_); + if (event_fd_ != -1) + ::close(event_fd_); +} + +void io_uring_service::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue<operation> ops; + + // Cancel all outstanding operations. + while (io_object* io_obj = registered_io_objects_.first()) + { + for (int i = 0; i < max_ops; ++i) + { + if (!io_obj->queues_[i].op_queue_.empty()) + { + ops.push(io_obj->queues_[i].op_queue_); + if (::io_uring_sqe* sqe = get_sqe()) + ::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0); + } + } + io_obj->shutdown_ = true; + registered_io_objects_.free(io_obj); + } + + // Cancel the timeout operation. + if (::io_uring_sqe* sqe = get_sqe()) + ::io_uring_prep_cancel(sqe, &timeout_, IOSQE_IO_DRAIN); + submit_sqes(); + + // Wait for all completions to come back. + for (; outstanding_work_ > 0; --outstanding_work_) + { + ::io_uring_cqe* cqe = 0; + if (::io_uring_wait_cqe(&ring_, &cqe) != 0) + break; + } + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void io_uring_service::notify_fork( + asio::execution_context::fork_event fork_ev) +{ + switch (fork_ev) + { + case asio::execution_context::fork_prepare: + { + // Cancel all outstanding operations. They will be restarted + // after the fork completes. + mutex::scoped_lock registration_lock(registration_mutex_); + for (io_object* io_obj = registered_io_objects_.first(); + io_obj != 0; io_obj = io_obj->next_) + { + mutex::scoped_lock io_object_lock(io_obj->mutex_); + for (int i = 0; i < max_ops; ++i) + { + if (!io_obj->queues_[i].op_queue_.empty() + && !io_obj->queues_[i].cancel_requested_) + { + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + ::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0); + } + } + } + + // Cancel the timeout operation. + { + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + ::io_uring_prep_cancel(sqe, &timeout_, IOSQE_IO_DRAIN); + submit_sqes(); + } + + // Wait for all completions to come back, and post all completed I/O + // queues to the scheduler. Note that some operations may have already + // completed, or were explicitly cancelled. All others will be + // automatically restarted. + op_queue<operation> ops; + for (; outstanding_work_ > 0; --outstanding_work_) + { + ::io_uring_cqe* cqe = 0; + if (::io_uring_wait_cqe(&ring_, &cqe) != 0) + break; + if (void* ptr = ::io_uring_cqe_get_data(cqe)) + { + if (ptr != this && ptr != &timer_queues_ && ptr != &timeout_) + { + io_queue* io_q = static_cast<io_queue*>(ptr); + io_q->set_result(cqe->res); + ops.push(io_q); + } + } + } + scheduler_.post_deferred_completions(ops); + + // Restart and eventfd operation. + register_with_reactor(); + } + break; + + case asio::execution_context::fork_parent: + // Restart the timeout and eventfd operations. + update_timeout(); + register_with_reactor(); + break; + + case asio::execution_context::fork_child: + { + // The child process gets a new io_uring instance. + ::io_uring_queue_exit(&ring_); + init_ring(); + register_with_reactor(); + } + break; + default: + break; + } +} + +void io_uring_service::init_task() +{ + scheduler_.init_task(); +} + +void io_uring_service::register_io_object( + io_uring_service::per_io_object_data& io_obj) +{ + io_obj = allocate_io_object(); + + mutex::scoped_lock io_object_lock(io_obj->mutex_); + + io_obj->service_ = this; + io_obj->shutdown_ = false; + for (int i = 0; i < max_ops; ++i) + { + io_obj->queues_[i].io_object_ = io_obj; + io_obj->queues_[i].cancel_requested_ = false; + } +} + +void io_uring_service::register_internal_io_object( + io_uring_service::per_io_object_data& io_obj, + int op_type, io_uring_operation* op) +{ + io_obj = allocate_io_object(); + + mutex::scoped_lock io_object_lock(io_obj->mutex_); + + io_obj->service_ = this; + io_obj->shutdown_ = false; + for (int i = 0; i < max_ops; ++i) + { + io_obj->queues_[i].io_object_ = io_obj; + io_obj->queues_[i].cancel_requested_ = false; + } + + io_obj->queues_[op_type].op_queue_.push(op); + io_object_lock.unlock(); + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + { + op->prepare(sqe); + ::io_uring_sqe_set_data(sqe, &io_obj->queues_[op_type]); + post_submit_sqes_op(lock); + } + else + { + asio::error_code ec(ENOBUFS, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "io_uring_get_sqe"); + } +} + +void io_uring_service::register_buffers(const ::iovec* v, unsigned n) +{ + int result = ::io_uring_register_buffers(&ring_, v, n); + if (result < 0) + { + asio::error_code ec(-result, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "io_uring_register_buffers"); + } +} + +void io_uring_service::unregister_buffers() +{ + (void)::io_uring_unregister_buffers(&ring_); +} + +void io_uring_service::start_op(int op_type, + io_uring_service::per_io_object_data& io_obj, + io_uring_operation* op, bool is_continuation) +{ + if (!io_obj) + { + op->ec_ = asio::error::bad_descriptor; + post_immediate_completion(op, is_continuation); + return; + } + + mutex::scoped_lock io_object_lock(io_obj->mutex_); + + if (io_obj->shutdown_) + { + io_object_lock.unlock(); + post_immediate_completion(op, is_continuation); + return; + } + + if (io_obj->queues_[op_type].op_queue_.empty()) + { + if (op->perform(false)) + { + io_object_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + } + else + { + io_obj->queues_[op_type].op_queue_.push(op); + io_object_lock.unlock(); + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + { + op->prepare(sqe); + ::io_uring_sqe_set_data(sqe, &io_obj->queues_[op_type]); + scheduler_.work_started(); + post_submit_sqes_op(lock); + } + else + { + lock.unlock(); + io_obj->queues_[op_type].set_result(-ENOBUFS); + post_immediate_completion(&io_obj->queues_[op_type], is_continuation); + } + } + } + else + { + io_obj->queues_[op_type].op_queue_.push(op); + scheduler_.work_started(); + } +} + +void io_uring_service::cancel_ops(io_uring_service::per_io_object_data& io_obj) +{ + if (!io_obj) + return; + + mutex::scoped_lock io_object_lock(io_obj->mutex_); + op_queue<operation> ops; + do_cancel_ops(io_obj, ops); + io_object_lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +void io_uring_service::cancel_ops_by_key( + io_uring_service::per_io_object_data& io_obj, + int op_type, void* cancellation_key) +{ + if (!io_obj) + return; + + mutex::scoped_lock io_object_lock(io_obj->mutex_); + + bool first = true; + op_queue<operation> ops; + op_queue<io_uring_operation> other_ops; + while (io_uring_operation* op = io_obj->queues_[op_type].op_queue_.front()) + { + io_obj->queues_[op_type].op_queue_.pop(); + if (op->cancellation_key_ == cancellation_key) + { + if (first) + { + other_ops.push(op); + if (!io_obj->queues_[op_type].cancel_requested_) + { + io_obj->queues_[op_type].cancel_requested_ = true; + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + { + ::io_uring_prep_cancel(sqe, &io_obj->queues_[op_type], 0); + submit_sqes(); + } + } + } + else + { + op->ec_ = asio::error::operation_aborted; + ops.push(op); + } + } + else + other_ops.push(op); + first = false; + } + io_obj->queues_[op_type].op_queue_.push(other_ops); + + io_object_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + +void io_uring_service::deregister_io_object( + io_uring_service::per_io_object_data& io_obj) +{ + if (!io_obj) + return; + + mutex::scoped_lock io_object_lock(io_obj->mutex_); + if (!io_obj->shutdown_) + { + op_queue<operation> ops; + bool pending_cancelled_ops = do_cancel_ops(io_obj, ops); + io_obj->shutdown_ = true; + io_object_lock.unlock(); + scheduler_.post_deferred_completions(ops); + if (pending_cancelled_ops) + { + // There are still pending operations. Prevent cleanup_io_object from + // freeing the I/O object and let the last operation to complete free it. + io_obj = 0; + } + else + { + // Leave io_obj set so that it will be freed by the subsequent call to + // cleanup_io_object. + } + } + else + { + // We are shutting down, so prevent cleanup_io_object from freeing + // the I/O object and let the destructor free it instead. + io_obj = 0; + } +} + +void io_uring_service::cleanup_io_object( + io_uring_service::per_io_object_data& io_obj) +{ + if (io_obj) + { + free_io_object(io_obj); + io_obj = 0; + } +} + +void io_uring_service::run(long usec, op_queue<operation>& ops) +{ + __kernel_timespec ts; + int local_ops = 0; + + if (usec > 0) + { + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + { + ++local_ops; + ::io_uring_prep_timeout(sqe, &ts, 0, 0); + ::io_uring_sqe_set_data(sqe, &ts); + submit_sqes(); + } + } + + ::io_uring_cqe* cqe = 0; + int result = (usec == 0) + ? ::io_uring_peek_cqe(&ring_, &cqe) + : ::io_uring_wait_cqe(&ring_, &cqe); + + if (local_ops > 0) + { + if (result != 0 || ::io_uring_cqe_get_data(cqe) != &ts) + { + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + { + ++local_ops; + ::io_uring_prep_timeout_remove(sqe, reinterpret_cast<__u64>(&ts), 0); + ::io_uring_sqe_set_data(sqe, &ts); + submit_sqes(); + } + } + } + + bool check_timers = false; + int count = 0; + while (result == 0 || local_ops > 0) + { + if (result == 0) + { + if (void* ptr = ::io_uring_cqe_get_data(cqe)) + { + if (ptr == this) + { + // The io_uring service was interrupted. + } + else if (ptr == &timer_queues_) + { + check_timers = true; + } + else if (ptr == &timeout_) + { + check_timers = true; + timeout_.tv_sec = 0; + timeout_.tv_nsec = 0; + } + else if (ptr == &ts) + { + --local_ops; + } + else + { + io_queue* io_q = static_cast<io_queue*>(ptr); + io_q->set_result(cqe->res); + ops.push(io_q); + } + } + ::io_uring_cqe_seen(&ring_, cqe); + ++count; + } + result = (count < complete_batch_size || local_ops > 0) + ? ::io_uring_peek_cqe(&ring_, &cqe) : -EAGAIN; + } + + decrement(outstanding_work_, count); + + if (check_timers) + { + mutex::scoped_lock lock(mutex_); + timer_queues_.get_ready_timers(ops); + if (timeout_.tv_sec == 0 && timeout_.tv_nsec == 0) + { + timeout_ = get_timeout(); + if (::io_uring_sqe* sqe = get_sqe()) + { + ::io_uring_prep_timeout(sqe, &timeout_, 0, 0); + ::io_uring_sqe_set_data(sqe, &timeout_); + push_submit_sqes_op(ops); + } + } + } +} + +void io_uring_service::interrupt() +{ + mutex::scoped_lock lock(mutex_); + if (::io_uring_sqe* sqe = get_sqe()) + { + ::io_uring_prep_nop(sqe); + ::io_uring_sqe_set_data(sqe, this); + } + submit_sqes(); +} + +void io_uring_service::init_ring() +{ + int result = ::io_uring_queue_init(ring_size, &ring_, 0); + if (result < 0) + { + ring_.ring_fd = -1; + asio::error_code ec(-result, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "io_uring_queue_init"); + } + +#if !defined(ASIO_HAS_IO_URING_AS_DEFAULT) + event_fd_ = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + if (event_fd_ < 0) + { + asio::error_code ec(-result, + asio::error::get_system_category()); + ::io_uring_queue_exit(&ring_); + asio::detail::throw_error(ec, "eventfd"); + } + + result = ::io_uring_register_eventfd(&ring_, event_fd_); + if (result < 0) + { + ::close(event_fd_); + ::io_uring_queue_exit(&ring_); + asio::error_code ec(-result, + asio::error::get_system_category()); + asio::detail::throw_error(ec, "io_uring_queue_init"); + } +#endif // !defined(ASIO_HAS_IO_URING_AS_DEFAULT) +} + +#if !defined(ASIO_HAS_IO_URING_AS_DEFAULT) +class io_uring_service::event_fd_read_op : + public reactor_op +{ +public: + event_fd_read_op(io_uring_service* s) + : reactor_op(asio::error_code(), + &event_fd_read_op::do_perform, event_fd_read_op::do_complete), + service_(s) + { + } + + static status do_perform(reactor_op* base) + { + event_fd_read_op* o(static_cast<event_fd_read_op*>(base)); + + for (;;) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + errno = 0; + int bytes_read = ::read(o->service_->event_fd_, + &counter, sizeof(uint64_t)); + if (bytes_read < 0 && errno == EINTR) + continue; + break; + } + + op_queue<operation> ops; + o->service_->run(0, ops); + o->service_->scheduler_.post_deferred_completions(ops); + + return not_done; + } + + static void do_complete(void* /*owner*/, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + event_fd_read_op* o(static_cast<event_fd_read_op*>(base)); + delete o; + } + +private: + io_uring_service* service_; +}; +#endif // !defined(ASIO_HAS_IO_URING_AS_DEFAULT) + +void io_uring_service::register_with_reactor() +{ +#if !defined(ASIO_HAS_IO_URING_AS_DEFAULT) + reactor_.register_internal_descriptor(reactor::read_op, + event_fd_, reactor_data_, new event_fd_read_op(this)); +#endif // !defined(ASIO_HAS_IO_URING_AS_DEFAULT) +} + +io_uring_service::io_object* io_uring_service::allocate_io_object() +{ + mutex::scoped_lock registration_lock(registration_mutex_); + return registered_io_objects_.alloc( + ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); +} + +void io_uring_service::free_io_object(io_uring_service::io_object* io_obj) +{ + mutex::scoped_lock registration_lock(registration_mutex_); + registered_io_objects_.free(io_obj); +} + +bool io_uring_service::do_cancel_ops( + per_io_object_data& io_obj, op_queue<operation>& ops) +{ + bool cancel_op = false; + + for (int i = 0; i < max_ops; ++i) + { + if (io_uring_operation* first_op = io_obj->queues_[i].op_queue_.front()) + { + cancel_op = true; + io_obj->queues_[i].op_queue_.pop(); + while (io_uring_operation* op = io_obj->queues_[i].op_queue_.front()) + { + op->ec_ = asio::error::operation_aborted; + io_obj->queues_[i].op_queue_.pop(); + ops.push(op); + } + io_obj->queues_[i].op_queue_.push(first_op); + } + } + + if (cancel_op) + { + mutex::scoped_lock lock(mutex_); + for (int i = 0; i < max_ops; ++i) + { + if (!io_obj->queues_[i].op_queue_.empty() + && !io_obj->queues_[i].cancel_requested_) + { + io_obj->queues_[i].cancel_requested_ = true; + if (::io_uring_sqe* sqe = get_sqe()) + ::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0); + } + } + submit_sqes(); + } + + return cancel_op; +} + +void io_uring_service::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void io_uring_service::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +void io_uring_service::update_timeout() +{ + if (::io_uring_sqe* sqe = get_sqe()) + { + ::io_uring_prep_timeout_remove(sqe, reinterpret_cast<__u64>(&timeout_), 0); + ::io_uring_sqe_set_data(sqe, &timer_queues_); + } +} + +__kernel_timespec io_uring_service::get_timeout() const +{ + __kernel_timespec ts; + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + return ts; +} + +::io_uring_sqe* io_uring_service::get_sqe() +{ + ::io_uring_sqe* sqe = ::io_uring_get_sqe(&ring_); + if (!sqe) + { + submit_sqes(); + sqe = ::io_uring_get_sqe(&ring_); + } + if (sqe) + { + ::io_uring_sqe_set_data(sqe, 0); + ++pending_sqes_; + } + return sqe; +} + +void io_uring_service::submit_sqes() +{ + if (pending_sqes_ != 0) + { + int result = ::io_uring_submit(&ring_); + if (result > 0) + { + pending_sqes_ -= result; + increment(outstanding_work_, result); + } + } +} + +void io_uring_service::post_submit_sqes_op(mutex::scoped_lock& lock) +{ + if (pending_sqes_ >= submit_batch_size) + { + submit_sqes(); + } + else if (pending_sqes_ != 0 && !pending_submit_sqes_op_) + { + pending_submit_sqes_op_ = true; + lock.unlock(); + scheduler_.post_immediate_completion(&submit_sqes_op_, false); + } +} + +void io_uring_service::push_submit_sqes_op(op_queue<operation>& ops) +{ + if (pending_sqes_ != 0 && !pending_submit_sqes_op_) + { + pending_submit_sqes_op_ = true; + ops.push(&submit_sqes_op_); + scheduler_.compensating_work_started(); + } +} + +io_uring_service::submit_sqes_op::submit_sqes_op(io_uring_service* s) + : operation(&io_uring_service::submit_sqes_op::do_complete), + service_(s) +{ +} + +void io_uring_service::submit_sqes_op::do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + submit_sqes_op* o = static_cast<submit_sqes_op*>(base); + mutex::scoped_lock lock(o->service_->mutex_); + o->service_->submit_sqes(); + if (o->service_->pending_sqes_ != 0) + o->service_->scheduler_.post_immediate_completion(o, true); + else + o->service_->pending_submit_sqes_op_ = false; + } +} + +io_uring_service::io_queue::io_queue() + : operation(&io_uring_service::io_queue::do_complete) +{ +} + +struct io_uring_service::perform_io_cleanup_on_block_exit +{ + explicit perform_io_cleanup_on_block_exit(io_uring_service* s) + : service_(s), io_object_to_free_(0), first_op_(0) + { + } + + ~perform_io_cleanup_on_block_exit() + { + if (io_object_to_free_) + { + mutex::scoped_lock lock(service_->mutex_); + service_->free_io_object(io_object_to_free_); + } + + if (first_op_) + { + // Post the remaining completed operations for invocation. + if (!ops_.empty()) + service_->scheduler_.post_deferred_completions(ops_); + + // A user-initiated operation has completed, but there's no need to + // explicitly call work_finished() here. Instead, we'll take advantage of + // the fact that the scheduler will call work_finished() once we return. + } + else + { + // No user-initiated operations have completed, so we need to compensate + // for the work_finished() call that the scheduler will make once this + // operation returns. + service_->scheduler_.compensating_work_started(); + } + } + + io_uring_service* service_; + io_object* io_object_to_free_; + op_queue<operation> ops_; + operation* first_op_; +}; + +operation* io_uring_service::io_queue::perform_io(int result) +{ + perform_io_cleanup_on_block_exit io_cleanup(io_object_->service_); + mutex::scoped_lock io_object_lock(io_object_->mutex_); + + if (result != -ECANCELED || cancel_requested_) + { + if (io_uring_operation* op = op_queue_.front()) + { + if (result < 0) + { + op->ec_.assign(-result, asio::error::get_system_category()); + op->bytes_transferred_ = 0; + } + else + { + op->ec_.assign(0, op->ec_.category()); + op->bytes_transferred_ = static_cast<std::size_t>(result); + } + } + + while (io_uring_operation* op = op_queue_.front()) + { + if (op->perform(io_cleanup.ops_.empty())) + { + op_queue_.pop(); + io_cleanup.ops_.push(op); + } + else + break; + } + } + + cancel_requested_ = false; + + if (!op_queue_.empty()) + { + io_uring_service* service = io_object_->service_; + mutex::scoped_lock lock(service->mutex_); + if (::io_uring_sqe* sqe = service->get_sqe()) + { + op_queue_.front()->prepare(sqe); + ::io_uring_sqe_set_data(sqe, this); + service->post_submit_sqes_op(lock); + } + else + { + lock.unlock(); + while (io_uring_operation* op = op_queue_.front()) + { + op->ec_ = asio::error::no_buffer_space; + op_queue_.pop(); + io_cleanup.ops_.push(op); + } + } + } + + // The last operation to complete on a shut down object must free it. + if (io_object_->shutdown_) + { + io_cleanup.io_object_to_free_ = io_object_; + for (int i = 0; i < max_ops; ++i) + if (!io_object_->queues_[i].op_queue_.empty()) + io_cleanup.io_object_to_free_ = 0; + } + + // The first operation will be returned for completion now. The others will + // be posted for later by the io_cleanup object's destructor. + io_cleanup.first_op_ = io_cleanup.ops_.front(); + io_cleanup.ops_.pop(); + return io_cleanup.first_op_; +} + +void io_uring_service::io_queue::do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred) +{ + if (owner) + { + io_queue* io_q = static_cast<io_queue*>(base); + int result = static_cast<int>(bytes_transferred); + if (operation* op = io_q->perform_io(result)) + { + op->complete(owner, ec, 0); + } + } +} + +io_uring_service::io_object::io_object(bool locking) + : mutex_(locking) +{ +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IMPL_IO_URING_SERVICE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/io_uring_socket_service_base.ipp b/3rdparty/asio/include/asio/detail/impl/io_uring_socket_service_base.ipp new file mode 100644 index 00000000000..79302fdc6f6 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/impl/io_uring_socket_service_base.ipp @@ -0,0 +1,249 @@ +// +// detail/io_uring_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_IPP +#define ASIO_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/io_uring_socket_service_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +io_uring_socket_service_base::io_uring_socket_service_base( + execution_context& context) + : io_uring_service_(asio::use_service<io_uring_service>(context)) +{ + io_uring_service_.init_task(); +} + +void io_uring_socket_service_base::base_shutdown() +{ +} + +void io_uring_socket_service_base::construct( + io_uring_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.io_object_data_ = 0; +} + +void io_uring_socket_service_base::base_move_construct( + io_uring_socket_service_base::base_implementation_type& impl, + io_uring_socket_service_base::base_implementation_type& other_impl) + noexcept +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.io_object_data_ = other_impl.io_object_data_; + other_impl.io_object_data_ = 0; +} + +void io_uring_socket_service_base::base_move_assign( + io_uring_socket_service_base::base_implementation_type& impl, + io_uring_socket_service_base& /*other_service*/, + io_uring_socket_service_base::base_implementation_type& other_impl) +{ + destroy(impl); + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.io_object_data_ = other_impl.io_object_data_; + other_impl.io_object_data_ = 0; +} + +void io_uring_socket_service_base::destroy( + io_uring_socket_service_base::base_implementation_type& impl) +{ + if (impl.socket_ != invalid_socket) + { + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "socket", &impl, impl.socket_, "close")); + + io_uring_service_.deregister_io_object(impl.io_object_data_); + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + io_uring_service_.cleanup_io_object(impl.io_object_data_); + } +} + +asio::error_code io_uring_socket_service_base::close( + io_uring_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "socket", &impl, impl.socket_, "close")); + + io_uring_service_.deregister_io_object(impl.io_object_data_); + socket_ops::close(impl.socket_, impl.state_, false, ec); + io_uring_service_.cleanup_io_object(impl.io_object_data_); + } + else + { + ec = success_ec_; + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + construct(impl); + + return ec; +} + +socket_type io_uring_socket_service_base::release( + io_uring_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return invalid_socket; + } + + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "socket", &impl, impl.socket_, "release")); + + io_uring_service_.deregister_io_object(impl.io_object_data_); + io_uring_service_.cleanup_io_object(impl.io_object_data_); + socket_type sock = impl.socket_; + construct(impl); + ec = success_ec_; + return sock; +} + +asio::error_code io_uring_socket_service_base::cancel( + io_uring_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + ASIO_HANDLER_OPERATION((io_uring_service_.context(), + "socket", &impl, impl.socket_, "cancel")); + + io_uring_service_.cancel_ops(impl.io_object_data_); + ec = success_ec_; + return ec; +} + +asio::error_code io_uring_socket_service_base::do_open( + io_uring_socket_service_base::base_implementation_type& impl, + int af, int type, int protocol, asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(af, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + io_uring_service_.register_io_object(impl.io_object_data_); + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = success_ec_; + return ec; +} + +asio::error_code io_uring_socket_service_base::do_assign( + io_uring_socket_service_base::base_implementation_type& impl, int type, + const io_uring_socket_service_base::native_handle_type& native_socket, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + io_uring_service_.register_io_object(impl.io_object_data_); + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.state_ |= socket_ops::possible_dup; + ec = success_ec_; + return ec; +} + +void io_uring_socket_service_base::start_op( + io_uring_socket_service_base::base_implementation_type& impl, + int op_type, io_uring_operation* op, bool is_continuation, bool noop) +{ + if (!noop) + { + io_uring_service_.start_op(op_type, + impl.io_object_data_, op, is_continuation); + } + else + { + io_uring_service_.post_immediate_completion(op, is_continuation); + } +} + +void io_uring_socket_service_base::start_accept_op( + io_uring_socket_service_base::base_implementation_type& impl, + io_uring_operation* op, bool is_continuation, bool peer_is_open) +{ + if (!peer_is_open) + start_op(impl, io_uring_service::read_op, op, is_continuation, false); + else + { + op->ec_ = asio::error::already_open; + io_uring_service_.post_immediate_completion(op, is_continuation); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.hpp b/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.hpp index eaa7a55e299..3f79e9f7217 100644 --- a/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.hpp @@ -2,7 +2,7 @@ // detail/impl/kqueue_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -20,11 +20,19 @@ #if defined(ASIO_HAS_KQUEUE) +#include "asio/detail/scheduler.hpp" + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +inline void kqueue_reactor::post_immediate_completion( + operation* op, bool is_continuation) const +{ + scheduler_.post_immediate_completion(op, is_continuation); +} + template <typename Time_Traits> void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { @@ -71,6 +79,18 @@ std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue, } template <typename Time_Traits> +void kqueue_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer_by_key(timer, ops, cancellation_key); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +template <typename Time_Traits> void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) diff --git a/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.ipp b/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.ipp index 6ba64583ecf..210a89dd49e 100644 --- a/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.ipp +++ b/3rdparty/asio/include/asio/detail/impl/kqueue_reactor.ipp @@ -2,7 +2,7 @@ // detail/impl/kqueue_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -25,9 +25,13 @@ #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" +#if defined(__NetBSD__) +# include <sys/param.h> +#endif + #include "asio/detail/push_options.hpp" -#if defined(__NetBSD__) +#if defined(__NetBSD__) && __NetBSD_Version__ < 999001500 # define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ EV_SET(ev, ident, filt, flags, fflags, data, \ reinterpret_cast<intptr_t>(static_cast<void*>(udata))) @@ -43,7 +47,7 @@ kqueue_reactor::kqueue_reactor(asio::execution_context& ctx) : execution_context_service_base<kqueue_reactor>(ctx), scheduler_(use_service<scheduler>(ctx)), mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( - SCHEDULER, scheduler_.concurrency_hint())), + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), kqueue_fd_(do_kqueue_create()), interrupter_(), shutdown_(false), @@ -186,14 +190,23 @@ void kqueue_reactor::move_descriptor(socket_type, source_descriptor_data = 0; } +void kqueue_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast<const kqueue_reactor*>(self)->post_immediate_completion( + op, is_continuation); +} + void kqueue_reactor::start_op(int op_type, socket_type descriptor, kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative) + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { if (!descriptor_data) { op->ec_ = asio::error::bad_descriptor; - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -201,7 +214,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -216,7 +229,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, if (op->perform()) { descriptor_lock.unlock(); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -235,7 +248,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, { op->ec_ = asio::error_code(errno, asio::error::get_system_category()); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } @@ -282,6 +295,35 @@ void kqueue_reactor::cancel_ops(socket_type, scheduler_.post_deferred_completions(ops); } +void kqueue_reactor::cancel_ops_by_key(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data, + int op_type, void* cancellation_key) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue<operation> ops; + op_queue<reactor_op> other_ops; + while (reactor_op* op = descriptor_data->op_queue_[op_type].front()) + { + descriptor_data->op_queue_[op_type].pop(); + if (op->cancellation_key_ == cancellation_key) + { + op->ec_ = asio::error::operation_aborted; + ops.push(op); + } + else + other_ops.push(op); + } + descriptor_data->op_queue_[op_type].push(other_ops); + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + void kqueue_reactor::deregister_descriptor(socket_type descriptor, kqueue_reactor::per_descriptor_data& descriptor_data, bool closing) { @@ -327,10 +369,16 @@ void kqueue_reactor::deregister_descriptor(socket_type descriptor, context(), static_cast<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(descriptor_data))); - free_descriptor_state(descriptor_data); - descriptor_data = 0; - scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; } } @@ -364,6 +412,22 @@ void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor, context(), static_cast<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(descriptor_data))); + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void kqueue_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { free_descriptor_state(descriptor_data); descriptor_data = 0; } @@ -498,7 +562,8 @@ int kqueue_reactor::do_kqueue_create() kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state() { mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - return registered_descriptors_.alloc(registered_descriptors_mutex_.enabled()); + return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); } void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s) diff --git a/3rdparty/asio/include/asio/detail/impl/null_event.ipp b/3rdparty/asio/include/asio/detail/impl/null_event.ipp index 71b6080c208..1c9f5684298 100644 --- a/3rdparty/asio/include/asio/detail/impl/null_event.ipp +++ b/3rdparty/asio/include/asio/detail/impl/null_event.ipp @@ -2,7 +2,7 @@ // detail/impl/null_event.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -39,7 +39,7 @@ namespace detail { void null_event::do_wait() { #if defined(ASIO_WINDOWS_RUNTIME) - std::this_thread::sleep_until(std::chrono::steady_clock::time_point::max()); + std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)()); #elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) ::Sleep(INFINITE); #else diff --git a/3rdparty/asio/include/asio/detail/impl/pipe_select_interrupter.ipp b/3rdparty/asio/include/asio/detail/impl/pipe_select_interrupter.ipp index 435da014dcb..75138312d9d 100644 --- a/3rdparty/asio/include/asio/detail/impl/pipe_select_interrupter.ipp +++ b/3rdparty/asio/include/asio/detail/impl/pipe_select_interrupter.ipp @@ -2,7 +2,7 @@ // detail/impl/pipe_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -101,12 +101,17 @@ bool pipe_select_interrupter::reset() { char data[1024]; signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) + if (bytes_read == sizeof(data)) continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; + if (bytes_read > 0) + return true; + if (bytes_read == 0) + return false; + if (errno == EINTR) + continue; + if (errno == EWOULDBLOCK || errno == EAGAIN) + return true; + return false; } } diff --git a/3rdparty/asio/include/asio/detail/impl/posix_event.ipp b/3rdparty/asio/include/asio/detail/impl/posix_event.ipp index a62c434edcd..76d5c468cbf 100644 --- a/3rdparty/asio/include/asio/detail/impl/posix_event.ipp +++ b/3rdparty/asio/include/asio/detail/impl/posix_event.ipp @@ -2,7 +2,7 @@ // detail/impl/posix_event.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -31,15 +31,22 @@ namespace detail { posix_event::posix_event() : state_(0) { -#if (defined(__MACH__) && defined(__APPLE__)) +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) int error = ::pthread_cond_init(&cond_, 0); #else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) ::pthread_condattr_t attr; - ::pthread_condattr_init(&attr); - int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + int error = ::pthread_condattr_init(&attr); if (error == 0) - error = ::pthread_cond_init(&cond_, &attr); + { + error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (error == 0) + error = ::pthread_cond_init(&cond_, &attr); + ::pthread_condattr_destroy(&attr); + } #endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) asio::error_code ec(error, asio::error::get_system_category()); diff --git a/3rdparty/asio/include/asio/detail/impl/posix_mutex.ipp b/3rdparty/asio/include/asio/detail/impl/posix_mutex.ipp index c629f6bba7e..5fd832f9821 100644 --- a/3rdparty/asio/include/asio/detail/impl/posix_mutex.ipp +++ b/3rdparty/asio/include/asio/detail/impl/posix_mutex.ipp @@ -2,7 +2,7 @@ // detail/impl/posix_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/reactive_serial_port_service.ipp b/3rdparty/asio/include/asio/detail/impl/posix_serial_port_service.ipp index 7ea37a4b7d9..98ed5822877 100644 --- a/3rdparty/asio/include/asio/detail/impl/reactive_serial_port_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/posix_serial_port_service.ipp @@ -1,16 +1,16 @@ // -// detail/impl/reactive_serial_port_service.ipp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/impl/posix_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP -#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP +#ifndef ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP +#define ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -22,32 +22,33 @@ #if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) #include <cstring> -#include "asio/detail/reactive_serial_port_service.hpp" +#include "asio/detail/posix_serial_port_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -reactive_serial_port_service::reactive_serial_port_service( - asio::io_context& io_context) - : service_base<reactive_serial_port_service>(io_context), - descriptor_service_(io_context) +posix_serial_port_service::posix_serial_port_service( + execution_context& context) + : execution_context_service_base<posix_serial_port_service>(context), + descriptor_service_(context) { } -void reactive_serial_port_service::shutdown() +void posix_serial_port_service::shutdown() { descriptor_service_.shutdown(); } -asio::error_code reactive_serial_port_service::open( - reactive_serial_port_service::implementation_type& impl, +asio::error_code posix_serial_port_service::open( + posix_serial_port_service::implementation_type& impl, const std::string& device, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -55,7 +56,10 @@ asio::error_code reactive_serial_port_service::open( int fd = descriptor_ops::open(device.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY, ec); if (fd < 0) + { + ASIO_ERROR_LOCATION(ec); return ec; + } int s = descriptor_ops::fcntl(fd, F_GETFL, ec); if (s >= 0) @@ -64,16 +68,17 @@ asio::error_code reactive_serial_port_service::open( { asio::error_code ignored_ec; descriptor_ops::close(fd, state, ignored_ec); + ASIO_ERROR_LOCATION(ec); return ec; } // Set up default serial port options. termios ios; - errno = 0; - s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); + s = ::tcgetattr(fd, &ios); + descriptor_ops::get_last_error(ec, s < 0); if (s >= 0) { -#if defined(_BSD_SOURCE) +#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) ::cfmakeraw(&ios); #else ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK @@ -85,13 +90,14 @@ asio::error_code reactive_serial_port_service::open( #endif ios.c_iflag |= IGNPAR; ios.c_cflag |= CREAD | CLOCAL; - errno = 0; - s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + s = ::tcsetattr(fd, TCSANOW, &ios); + descriptor_ops::get_last_error(ec, s < 0); } if (s < 0) { asio::error_code ignored_ec; descriptor_ops::close(fd, state, ignored_ec); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -102,43 +108,53 @@ asio::error_code reactive_serial_port_service::open( descriptor_ops::close(fd, state, ignored_ec); } + ASIO_ERROR_LOCATION(ec); return ec; } -asio::error_code reactive_serial_port_service::do_set_option( - reactive_serial_port_service::implementation_type& impl, - reactive_serial_port_service::store_function_type store, +asio::error_code posix_serial_port_service::do_set_option( + posix_serial_port_service::implementation_type& impl, + posix_serial_port_service::store_function_type store, const void* option, asio::error_code& ec) { termios ios; - errno = 0; - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native_handle(impl), &ios), ec); - if (ec) + int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); + descriptor_ops::get_last_error(ec, s < 0); + if (s < 0) + { + ASIO_ERROR_LOCATION(ec); return ec; + } if (store(option, ios, ec)) + { + ASIO_ERROR_LOCATION(ec); return ec; + } - errno = 0; - descriptor_ops::error_wrapper(::tcsetattr( - descriptor_service_.native_handle(impl), TCSANOW, &ios), ec); + s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios); + descriptor_ops::get_last_error(ec, s < 0); + ASIO_ERROR_LOCATION(ec); return ec; } -asio::error_code reactive_serial_port_service::do_get_option( - const reactive_serial_port_service::implementation_type& impl, - reactive_serial_port_service::load_function_type load, +asio::error_code posix_serial_port_service::do_get_option( + const posix_serial_port_service::implementation_type& impl, + posix_serial_port_service::load_function_type load, void* option, asio::error_code& ec) const { termios ios; - errno = 0; - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native_handle(impl), &ios), ec); - if (ec) + int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); + descriptor_ops::get_last_error(ec, s < 0); + if (s < 0) + { + ASIO_ERROR_LOCATION(ec); return ec; + } - return load(option, ios, ec); + load(option, ios, ec); + ASIO_ERROR_LOCATION(ec); + return ec; } } // namespace detail @@ -149,4 +165,4 @@ asio::error_code reactive_serial_port_service::do_get_option( #endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) #endif // defined(ASIO_HAS_SERIAL_PORT) -#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP +#endif // ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/posix_thread.ipp b/3rdparty/asio/include/asio/detail/impl/posix_thread.ipp index a4eb2a80f96..7602377336e 100644 --- a/3rdparty/asio/include/asio/detail/impl/posix_thread.ipp +++ b/3rdparty/asio/include/asio/detail/impl/posix_thread.ipp @@ -2,7 +2,7 @@ // detail/impl/posix_thread.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/posix_tss_ptr.ipp b/3rdparty/asio/include/asio/detail/impl/posix_tss_ptr.ipp index 4d35ebca1b5..099274b2779 100644 --- a/3rdparty/asio/include/asio/detail/impl/posix_tss_ptr.ipp +++ b/3rdparty/asio/include/asio/detail/impl/posix_tss_ptr.ipp @@ -2,7 +2,7 @@ // detail/impl/posix_tss_ptr.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/reactive_descriptor_service.ipp b/3rdparty/asio/include/asio/detail/impl/reactive_descriptor_service.ipp index 7aaf3620f16..829aefb01bf 100644 --- a/3rdparty/asio/include/asio/detail/impl/reactive_descriptor_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/reactive_descriptor_service.ipp @@ -2,7 +2,7 @@ // detail/impl/reactive_descriptor_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,7 +19,8 @@ #if !defined(ASIO_WINDOWS) \ && !defined(ASIO_WINDOWS_RUNTIME) \ - && !defined(__CYGWIN__) + && !defined(__CYGWIN__) \ + && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #include "asio/error.hpp" #include "asio/detail/reactive_descriptor_service.hpp" @@ -30,9 +31,9 @@ namespace asio { namespace detail { reactive_descriptor_service::reactive_descriptor_service( - asio::io_context& io_context) - : service_base<reactive_descriptor_service>(io_context), - reactor_(asio::use_service<reactor>(io_context)) + execution_context& context) + : execution_context_service_base<reactive_descriptor_service>(context), + reactor_(asio::use_service<reactor>(context)) { reactor_.init_task(); } @@ -46,11 +47,13 @@ void reactive_descriptor_service::construct( { impl.descriptor_ = -1; impl.state_ = 0; + impl.reactor_data_ = reactor::per_descriptor_data(); } void reactive_descriptor_service::move_construct( reactive_descriptor_service::implementation_type& impl, reactive_descriptor_service::implementation_type& other_impl) + noexcept { impl.descriptor_ = other_impl.descriptor_; other_impl.descriptor_ = -1; @@ -89,10 +92,12 @@ void reactive_descriptor_service::destroy( reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, (impl.state_ & descriptor_ops::possible_dup) == 0); - } - asio::error_code ignored_ec; - descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); + asio::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } } asio::error_code reactive_descriptor_service::assign( @@ -102,6 +107,7 @@ asio::error_code reactive_descriptor_service::assign( if (is_open(impl)) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -110,6 +116,7 @@ asio::error_code reactive_descriptor_service::assign( { ec = asio::error_code(err, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -130,9 +137,15 @@ asio::error_code reactive_descriptor_service::close( reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, (impl.state_ & descriptor_ops::possible_dup) == 0); - } - descriptor_ops::close(impl.descriptor_, impl.state_, ec); + descriptor_ops::close(impl.descriptor_, impl.state_, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } // The descriptor is closed by the OS even if close() returns an error. // @@ -142,6 +155,7 @@ asio::error_code reactive_descriptor_service::close( // We'll just have to assume that other OSes follow the same behaviour.) construct(impl); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -157,6 +171,7 @@ reactive_descriptor_service::release( "descriptor", &impl, impl.descriptor_, "release")); reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); construct(impl); } @@ -170,6 +185,7 @@ asio::error_code reactive_descriptor_service::cancel( if (!is_open(impl)) { ec = asio::error::bad_descriptor; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -181,10 +197,10 @@ asio::error_code reactive_descriptor_service::cancel( return ec; } -void reactive_descriptor_service::start_op( - reactive_descriptor_service::implementation_type& impl, - int op_type, reactor_op* op, bool is_continuation, - bool is_non_blocking, bool noop) +void reactive_descriptor_service::do_start_op(implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, bool is_non_blocking, + bool noop, void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if (!noop) { @@ -192,13 +208,13 @@ void reactive_descriptor_service::start_op( descriptor_ops::set_internal_non_blocking( impl.descriptor_, impl.state_, true, op->ec_)) { - reactor_.start_op(op_type, impl.descriptor_, - impl.reactor_data_, op, is_continuation, is_non_blocking); + reactor_.start_op(op_type, impl.descriptor_, impl.reactor_data_, op, + is_continuation, is_non_blocking, on_immediate, immediate_arg); return; } } - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } } // namespace detail @@ -209,5 +225,6 @@ void reactive_descriptor_service::start_op( #endif // !defined(ASIO_WINDOWS) // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) + // && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/reactive_socket_service_base.ipp b/3rdparty/asio/include/asio/detail/impl/reactive_socket_service_base.ipp index f1ed1fa1ea7..a02001b421f 100644 --- a/3rdparty/asio/include/asio/detail/impl/reactive_socket_service_base.ipp +++ b/3rdparty/asio/include/asio/detail/impl/reactive_socket_service_base.ipp @@ -2,7 +2,7 @@ // detail/reactive_socket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,7 +18,8 @@ #include "asio/detail/config.hpp" #if !defined(ASIO_HAS_IOCP) \ - && !defined(ASIO_WINDOWS_RUNTIME) + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #include "asio/detail/reactive_socket_service_base.hpp" @@ -28,9 +29,8 @@ namespace asio { namespace detail { reactive_socket_service_base::reactive_socket_service_base( - asio::io_context& io_context) - : io_context_(io_context), - reactor_(use_service<reactor>(io_context)) + execution_context& context) + : reactor_(use_service<reactor>(context)) { reactor_.init_task(); } @@ -44,11 +44,13 @@ void reactive_socket_service_base::construct( { impl.socket_ = invalid_socket; impl.state_ = 0; + impl.reactor_data_ = reactor::per_descriptor_data(); } void reactive_socket_service_base::base_move_construct( reactive_socket_service_base::base_implementation_type& impl, reactive_socket_service_base::base_implementation_type& other_impl) + noexcept { impl.socket_ = other_impl.socket_; other_impl.socket_ = invalid_socket; @@ -90,6 +92,8 @@ void reactive_socket_service_base::destroy( asio::error_code ignored_ec; socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); } } @@ -104,9 +108,15 @@ asio::error_code reactive_socket_service_base::close( reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, (impl.state_ & socket_ops::possible_dup) == 0); - } - socket_ops::close(impl.socket_, impl.state_, false, ec); + socket_ops::close(impl.socket_, impl.state_, false, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } // The descriptor is closed by the OS even if close() returns an error. // @@ -121,6 +131,27 @@ asio::error_code reactive_socket_service_base::close( return ec; } +socket_type reactive_socket_service_base::release( + reactive_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return invalid_socket; + } + + ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "release")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + socket_type sock = impl.socket_; + construct(impl); + ec = asio::error_code(); + return sock; +} + asio::error_code reactive_socket_service_base::cancel( reactive_socket_service_base::base_implementation_type& impl, asio::error_code& ec) @@ -202,10 +233,11 @@ asio::error_code reactive_socket_service_base::do_assign( return ec; } -void reactive_socket_service_base::start_op( - reactive_socket_service_base::base_implementation_type& impl, - int op_type, reactor_op* op, bool is_continuation, - bool is_non_blocking, bool noop) +void reactive_socket_service_base::do_start_op( + reactive_socket_service_base::base_implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if (!noop) { @@ -213,32 +245,38 @@ void reactive_socket_service_base::start_op( || socket_ops::set_internal_non_blocking( impl.socket_, impl.state_, true, op->ec_)) { - reactor_.start_op(op_type, impl.socket_, - impl.reactor_data_, op, is_continuation, is_non_blocking); + reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op, + is_continuation, is_non_blocking, on_immediate, immediate_arg); return; } } - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } -void reactive_socket_service_base::start_accept_op( +void reactive_socket_service_base::do_start_accept_op( reactive_socket_service_base::base_implementation_type& impl, - reactor_op* op, bool is_continuation, bool peer_is_open) + reactor_op* op, bool is_continuation, bool peer_is_open, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if (!peer_is_open) - start_op(impl, reactor::read_op, op, true, is_continuation, false); + { + do_start_op(impl, reactor::read_op, op, is_continuation, + true, false, on_immediate, immediate_arg); + } else { op->ec_ = asio::error::already_open; - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } } -void reactive_socket_service_base::start_connect_op( +void reactive_socket_service_base::do_start_connect_op( reactive_socket_service_base::base_implementation_type& impl, - reactor_op* op, bool is_continuation, - const socket_addr_type* addr, size_t addrlen) + reactor_op* op, bool is_continuation, const void* addr, size_t addrlen, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if ((impl.state_ & socket_ops::non_blocking) || socket_ops::set_internal_non_blocking( @@ -250,14 +288,14 @@ void reactive_socket_service_base::start_connect_op( || op->ec_ == asio::error::would_block) { op->ec_ = asio::error_code(); - reactor_.start_op(reactor::connect_op, impl.socket_, - impl.reactor_data_, op, is_continuation, false); + reactor_.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_, + op, is_continuation, false, on_immediate, immediate_arg); return; } } } - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } } // namespace detail @@ -267,5 +305,6 @@ void reactive_socket_service_base::start_connect_op( #endif // !defined(ASIO_HAS_IOCP) // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/resolver_service_base.ipp b/3rdparty/asio/include/asio/detail/impl/resolver_service_base.ipp index 5899db554fc..8d9e944ddde 100644 --- a/3rdparty/asio/include/asio/detail/impl/resolver_service_base.ipp +++ b/3rdparty/asio/include/asio/detail/impl/resolver_service_base.ipp @@ -2,7 +2,7 @@ // detail/impl/resolver_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,25 +23,30 @@ namespace asio { namespace detail { -class resolver_service_base::work_io_context_runner +class resolver_service_base::work_scheduler_runner { public: - work_io_context_runner(asio::io_context& io_context) - : io_context_(io_context) {} - void operator()() { io_context_.run(); } + work_scheduler_runner(scheduler_impl& work_scheduler) + : work_scheduler_(work_scheduler) + { + } + + void operator()() + { + asio::error_code ec; + work_scheduler_.run(ec); + } + private: - asio::io_context& io_context_; + scheduler_impl& work_scheduler_; }; -resolver_service_base::resolver_service_base( - asio::io_context& io_context) - : io_context_impl_(asio::use_service<io_context_impl>(io_context)), - work_io_context_(new asio::io_context(-1)), - work_io_context_impl_(asio::use_service< - io_context_impl>(*work_io_context_)), - work_(asio::make_work_guard(*work_io_context_)), +resolver_service_base::resolver_service_base(execution_context& context) + : scheduler_(asio::use_service<scheduler_impl>(context)), + work_scheduler_(new scheduler_impl(context, -1, false)), work_thread_(0) { + work_scheduler_->work_started(); } resolver_service_base::~resolver_service_base() @@ -51,35 +56,34 @@ resolver_service_base::~resolver_service_base() void resolver_service_base::base_shutdown() { - work_.reset(); - if (work_io_context_.get()) + if (work_scheduler_.get()) { - work_io_context_->stop(); + work_scheduler_->work_finished(); + work_scheduler_->stop(); if (work_thread_.get()) { work_thread_->join(); work_thread_.reset(); } - work_io_context_.reset(); + work_scheduler_.reset(); } } void resolver_service_base::base_notify_fork( - asio::io_context::fork_event fork_ev) + execution_context::fork_event fork_ev) { if (work_thread_.get()) { - if (fork_ev == asio::io_context::fork_prepare) + if (fork_ev == execution_context::fork_prepare) { - work_io_context_->stop(); + work_scheduler_->stop(); work_thread_->join(); + work_thread_.reset(); } - else - { - work_io_context_->restart(); - work_thread_.reset(new asio::detail::thread( - work_io_context_runner(*work_io_context_))); - } + } + else if (fork_ev != execution_context::fork_prepare) + { + work_scheduler_->restart(); } } @@ -92,7 +96,7 @@ void resolver_service_base::construct( void resolver_service_base::destroy( resolver_service_base::implementation_type& impl) { - ASIO_HANDLER_OPERATION((io_context_impl_.context(), + ASIO_HANDLER_OPERATION((scheduler_.context(), "resolver", &impl, 0, "cancel")); impl.reset(); @@ -101,20 +105,20 @@ void resolver_service_base::destroy( void resolver_service_base::move_construct(implementation_type& impl, implementation_type& other_impl) { - impl = ASIO_MOVE_CAST(implementation_type)(other_impl); + impl = static_cast<implementation_type&&>(other_impl); } void resolver_service_base::move_assign(implementation_type& impl, resolver_service_base&, implementation_type& other_impl) { destroy(impl); - impl = ASIO_MOVE_CAST(implementation_type)(other_impl); + impl = static_cast<implementation_type&&>(other_impl); } void resolver_service_base::cancel( resolver_service_base::implementation_type& impl) { - ASIO_HANDLER_OPERATION((io_context_impl_.context(), + ASIO_HANDLER_OPERATION((scheduler_.context(), "resolver", &impl, 0, "cancel")); impl.reset(static_cast<void*>(0), socket_ops::noop_deleter()); @@ -123,16 +127,16 @@ void resolver_service_base::cancel( void resolver_service_base::start_resolve_op(resolve_op* op) { if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, - io_context_impl_.concurrency_hint())) + scheduler_.concurrency_hint())) { start_work_thread(); - io_context_impl_.work_started(); - work_io_context_impl_.post_immediate_completion(op, false); + scheduler_.work_started(); + work_scheduler_->post_immediate_completion(op, false); } else { op->ec_ = asio::error::operation_not_supported; - io_context_impl_.post_immediate_completion(op, false); + scheduler_.post_immediate_completion(op, false); } } @@ -142,7 +146,7 @@ void resolver_service_base::start_work_thread() if (!work_thread_.get()) { work_thread_.reset(new asio::detail::thread( - work_io_context_runner(*work_io_context_))); + work_scheduler_runner(*work_scheduler_))); } } diff --git a/3rdparty/asio/include/asio/detail/impl/scheduler.ipp b/3rdparty/asio/include/asio/detail/impl/scheduler.ipp index 1b204653226..eccc80322d1 100644 --- a/3rdparty/asio/include/asio/detail/impl/scheduler.ipp +++ b/3rdparty/asio/include/asio/detail/impl/scheduler.ipp @@ -2,7 +2,7 @@ // detail/impl/scheduler.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,15 +20,39 @@ #include "asio/detail/concurrency_hint.hpp" #include "asio/detail/event.hpp" #include "asio/detail/limits.hpp" -#include "asio/detail/reactor.hpp" #include "asio/detail/scheduler.hpp" #include "asio/detail/scheduler_thread_info.hpp" +#include "asio/detail/signal_blocker.hpp" + +#if defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_service.hpp" +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/reactor.hpp" +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +class scheduler::thread_function +{ +public: + explicit thread_function(scheduler* s) + : this_(s) + { + } + + void operator()() + { + asio::error_code ec; + this_->run(ec); + } + +private: + scheduler* this_; +}; + struct scheduler::task_cleanup { ~task_cleanup() @@ -84,30 +108,64 @@ struct scheduler::work_cleanup thread_info* this_thread_; }; -scheduler::scheduler( - asio::execution_context& ctx, int concurrency_hint) +scheduler::scheduler(asio::execution_context& ctx, + int concurrency_hint, bool own_thread, get_task_func_type get_task) : asio::detail::execution_context_service_base<scheduler>(ctx), one_thread_(concurrency_hint == 1 || !ASIO_CONCURRENCY_HINT_IS_LOCKING( - SCHEDULER, concurrency_hint)), + SCHEDULER, concurrency_hint) + || !ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, concurrency_hint)), mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING( SCHEDULER, concurrency_hint)), task_(0), + get_task_(get_task), task_interrupted_(true), outstanding_work_(0), stopped_(false), shutdown_(false), - concurrency_hint_(concurrency_hint) + concurrency_hint_(concurrency_hint), + thread_(0) { ASIO_HANDLER_TRACKING_INIT; + + if (own_thread) + { + ++outstanding_work_; + asio::detail::signal_blocker sb; + thread_ = new asio::detail::thread(thread_function(this)); + } +} + +scheduler::~scheduler() +{ + if (thread_) + { + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_all_threads(lock); + lock.unlock(); + thread_->join(); + delete thread_; + } } void scheduler::shutdown() { mutex::scoped_lock lock(mutex_); shutdown_ = true; + if (thread_) + stop_all_threads(lock); lock.unlock(); + // Join thread to ensure task operation is returned to queue. + if (thread_) + { + thread_->join(); + delete thread_; + thread_ = 0; + } + // Destroy handler objects. while (!op_queue_.empty()) { @@ -126,7 +184,7 @@ void scheduler::init_task() mutex::scoped_lock lock(mutex_); if (!shutdown_ && !task_) { - task_ = &use_service<reactor>(this->context()); + task_ = get_task_(this->context()); op_queue_.push(&task_operation_); wake_one_thread_and_unlock(lock); } @@ -269,9 +327,21 @@ void scheduler::restart() void scheduler::compensating_work_started() { thread_info_base* this_thread = thread_call_stack::contains(this); + ASIO_ASSUME(this_thread != 0); // Only called from inside scheduler. ++static_cast<thread_info*>(this_thread)->private_outstanding_work; } +bool scheduler::can_dispatch() +{ + return thread_call_stack::contains(this) != 0; +} + +void scheduler::capture_current_exception() +{ + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + this_thread->capture_current_exception(); +} + void scheduler::post_immediate_completion( scheduler::operation* op, bool is_continuation) { @@ -295,6 +365,30 @@ void scheduler::post_immediate_completion( wake_one_thread_and_unlock(lock); } +void scheduler::post_immediate_completions(std::size_t n, + op_queue<scheduler::operation>& ops, bool is_continuation) +{ +#if defined(ASIO_HAS_THREADS) + if (one_thread_ || is_continuation) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast<thread_info*>(this_thread)->private_outstanding_work + += static_cast<long>(n); + static_cast<thread_info*>(this_thread)->private_op_queue.push(ops); + return; + } + } +#else // defined(ASIO_HAS_THREADS) + (void)is_continuation; +#endif // defined(ASIO_HAS_THREADS) + + increment(outstanding_work_, static_cast<long>(n)); + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); +} + void scheduler::post_deferred_completion(scheduler::operation* op) { #if defined(ASIO_HAS_THREADS) @@ -396,6 +490,7 @@ std::size_t scheduler::do_run_one(mutex::scoped_lock& lock, // Complete the operation. May throw an exception. Deletes the object. o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); return 1; } @@ -476,6 +571,7 @@ std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock, // Complete the operation. May throw an exception. Deletes the object. o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); return 1; } @@ -530,6 +626,7 @@ std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock, // Complete the operation. May throw an exception. Deletes the object. o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); return 1; } @@ -561,6 +658,15 @@ void scheduler::wake_one_thread_and_unlock( } } +scheduler_task* scheduler::get_default_task(asio::execution_context& ctx) +{ +#if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + return &use_service<io_uring_service>(ctx); +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + return &use_service<reactor>(ctx); +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) +} + } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/impl/select_reactor.hpp b/3rdparty/asio/include/asio/detail/impl/select_reactor.hpp index 04e17f880ca..933b02cddc5 100644 --- a/3rdparty/asio/include/asio/detail/impl/select_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/impl/select_reactor.hpp @@ -2,7 +2,7 @@ // detail/impl/select_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,11 +23,23 @@ && !defined(ASIO_HAS_KQUEUE) \ && !defined(ASIO_WINDOWS_RUNTIME)) +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +inline void select_reactor::post_immediate_completion( + operation* op, bool is_continuation) const +{ + scheduler_.post_immediate_completion(op, is_continuation); +} + template <typename Time_Traits> void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { @@ -74,6 +86,18 @@ std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue, } template <typename Time_Traits> +void select_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer_by_key(timer, ops, cancellation_key); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +template <typename Time_Traits> void select_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) diff --git a/3rdparty/asio/include/asio/detail/impl/select_reactor.ipp b/3rdparty/asio/include/asio/detail/impl/select_reactor.ipp index dc0737bfad8..5e5946bb84b 100644 --- a/3rdparty/asio/include/asio/detail/impl/select_reactor.ipp +++ b/3rdparty/asio/include/asio/detail/impl/select_reactor.ipp @@ -2,7 +2,7 @@ // detail/impl/select_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -28,6 +28,12 @@ #include "asio/detail/signal_blocker.hpp" #include "asio/detail/socket_ops.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + #include "asio/detail/push_options.hpp" namespace asio { @@ -60,6 +66,7 @@ select_reactor::select_reactor(asio::execution_context& ctx) #if defined(ASIO_HAS_IOCP) stop_thread_(false), thread_(0), + restart_reactor_(this), #endif // defined(ASIO_HAS_IOCP) shutdown_(false) { @@ -80,13 +87,14 @@ void select_reactor::shutdown() shutdown_ = true; #if defined(ASIO_HAS_IOCP) stop_thread_ = true; + if (thread_) + interrupter_.interrupt(); #endif // defined(ASIO_HAS_IOCP) lock.unlock(); #if defined(ASIO_HAS_IOCP) if (thread_) { - interrupter_.interrupt(); thread_->join(); delete thread_; thread_ = 0; @@ -106,8 +114,12 @@ void select_reactor::shutdown() void select_reactor::notify_fork( asio::execution_context::fork_event fork_ev) { +#if defined(ASIO_HAS_IOCP) + (void)fork_ev; +#else // defined(ASIO_HAS_IOCP) if (fork_ev == asio::execution_context::fork_child) interrupter_.recreate(); +#endif // defined(ASIO_HAS_IOCP) } void select_reactor::init_task() @@ -139,15 +151,23 @@ void select_reactor::move_descriptor(socket_type, { } +void select_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast<const select_reactor*>(self)->post_immediate_completion( + op, is_continuation); +} + void select_reactor::start_op(int op_type, socket_type descriptor, - select_reactor::per_descriptor_data&, reactor_op* op, - bool is_continuation, bool) + select_reactor::per_descriptor_data&, reactor_op* op, bool is_continuation, + bool, void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -164,6 +184,19 @@ void select_reactor::cancel_ops(socket_type descriptor, cancel_ops_unlocked(descriptor, asio::error::operation_aborted); } +void select_reactor::cancel_ops_by_key(socket_type descriptor, + select_reactor::per_descriptor_data&, + int op_type, void* cancellation_key) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + bool need_interrupt = op_queue_[op_type].cancel_operations_by_key( + descriptor, ops, cancellation_key, asio::error::operation_aborted); + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + void select_reactor::deregister_descriptor(socket_type descriptor, select_reactor::per_descriptor_data&, bool) { @@ -180,6 +213,11 @@ void select_reactor::deregister_internal_descriptor( op_queue_[i].cancel_operations(descriptor, ops); } +void select_reactor::cleanup_descriptor_data( + select_reactor::per_descriptor_data&) +{ +} + void select_reactor::run(long usec, op_queue<operation>& ops) { asio::detail::mutex::scoped_lock lock(mutex_); @@ -234,7 +272,16 @@ void select_reactor::run(long usec, op_queue<operation>& ops) // Reset the interrupter. if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor())) { - interrupter_.reset(); + if (!interrupter_.reset()) + { + lock.lock(); +#if defined(ASIO_HAS_IOCP) + stop_thread_ = true; + scheduler_.post_immediate_completion(&restart_reactor_, false); +#else // defined(ASIO_HAS_IOCP) + interrupter_.recreate(); +#endif // defined(ASIO_HAS_IOCP) + } --retval; } @@ -270,11 +317,36 @@ void select_reactor::run_thread() { lock.unlock(); op_queue<operation> ops; - run(true, ops); + run(-1, ops); scheduler_.post_deferred_completions(ops); lock.lock(); } } + +void select_reactor::restart_reactor::do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + select_reactor* reactor = static_cast<restart_reactor*>(base)->reactor_; + + if (reactor->thread_) + { + reactor->thread_->join(); + delete reactor->thread_; + reactor->thread_ = 0; + } + + asio::detail::mutex::scoped_lock lock(reactor->mutex_); + reactor->interrupter_.recreate(); + reactor->stop_thread_ = false; + lock.unlock(); + + asio::detail::signal_blocker sb; + reactor->thread_ = + new asio::detail::thread(thread_function(reactor)); + } +} #endif // defined(ASIO_HAS_IOCP) void select_reactor::do_add_timer_queue(timer_queue_base& queue) diff --git a/3rdparty/asio/include/asio/detail/impl/service_registry.hpp b/3rdparty/asio/include/asio/detail/impl/service_registry.hpp index 1b735e1596a..2490636c0ad 100644 --- a/3rdparty/asio/include/asio/detail/impl/service_registry.hpp +++ b/3rdparty/asio/include/asio/detail/impl/service_registry.hpp @@ -2,7 +2,7 @@ // detail/impl/service_registry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -64,8 +64,7 @@ inline void service_registry::init_key( #if !defined(ASIO_NO_TYPEID) template <typename Service> void service_registry::init_key(execution_context::service::key& key, - typename enable_if< - is_base_of<typename Service::key_type, Service>::value>::type*) + enable_if_t<is_base_of<typename Service::key_type, Service>::value>*) { key.type_info_ = &typeid(typeid_wrapper<Service>); key.id_ = 0; diff --git a/3rdparty/asio/include/asio/detail/impl/service_registry.ipp b/3rdparty/asio/include/asio/detail/impl/service_registry.ipp index ef1955f743c..b0133421d25 100644 --- a/3rdparty/asio/include/asio/detail/impl/service_registry.ipp +++ b/3rdparty/asio/include/asio/detail/impl/service_registry.ipp @@ -2,7 +2,7 @@ // detail/impl/service_registry.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/signal_set_service.ipp b/3rdparty/asio/include/asio/detail/impl/signal_set_service.ipp index 114a0b1417f..7f6be8b71a9 100644 --- a/3rdparty/asio/include/asio/detail/impl/signal_set_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/signal_set_service.ipp @@ -2,7 +2,7 @@ // detail/impl/signal_set_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,12 +19,17 @@ #include <cstring> #include <stdexcept> -#include "asio/detail/reactor.hpp" #include "asio/detail/signal_blocker.hpp" #include "asio/detail/signal_set_service.hpp" #include "asio/detail/static_mutex.hpp" #include "asio/detail/throw_exception.hpp" +#if defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_service.hpp" +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/reactor.hpp" +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + #include "asio/detail/push_options.hpp" namespace asio { @@ -49,12 +54,16 @@ struct signal_state // A count of the number of objects that are registered for each signal. std::size_t registration_count_[max_signal_number]; + + // The flags used for each registered signal. + signal_set_base::flags_t flags_[max_signal_number]; }; signal_state* get_signal_state() { static signal_state state = { - ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } }; + ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, + { 0 }, { signal_set_base::flags_t() } }; return &state; } @@ -85,11 +94,45 @@ void asio_signal_handler(int signal_number) #if !defined(ASIO_WINDOWS) \ && !defined(ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) -class signal_set_service::pipe_read_op : public reactor_op +class signal_set_service::pipe_read_op : +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + public io_uring_operation +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + public reactor_op +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) { public: +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + pipe_read_op() + : io_uring_operation(asio::error_code(), &pipe_read_op::do_prepare, + &pipe_read_op::do_perform, pipe_read_op::do_complete) + { + } + + static void do_prepare(io_uring_operation*, ::io_uring_sqe* sqe) + { + signal_state* state = get_signal_state(); + + int fd = state->read_descriptor_; + ::io_uring_prep_poll_add(sqe, fd, POLLIN); + } + + static bool do_perform(io_uring_operation*, bool) + { + signal_state* state = get_signal_state(); + + int fd = state->read_descriptor_; + int signal_number = 0; + while (::read(fd, &signal_number, sizeof(int)) == sizeof(int)) + if (signal_number >= 0 && signal_number < max_signal_number) + signal_set_service::deliver_signal(signal_number); + + return false; + } +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) pipe_read_op() - : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete) + : reactor_op(asio::error_code(), + &pipe_read_op::do_perform, pipe_read_op::do_complete) { } @@ -105,6 +148,7 @@ public: return not_done; } +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) static void do_complete(void* /*owner*/, operation* base, const asio::error_code& /*ec*/, @@ -118,14 +162,17 @@ public: // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) -signal_set_service::signal_set_service( - asio::io_context& io_context) - : service_base<signal_set_service>(io_context), - io_context_(asio::use_service<io_context_impl>(io_context)), +signal_set_service::signal_set_service(execution_context& context) + : execution_context_service_base<signal_set_service>(context), + scheduler_(asio::use_service<scheduler_impl>(context)), #if !defined(ASIO_WINDOWS) \ && !defined(ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) - reactor_(asio::use_service<reactor>(io_context)), +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + io_uring_service_(asio::use_service<io_uring_service>(context)), +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + reactor_(asio::use_service<reactor>(context)), +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // !defined(ASIO_WINDOWS) // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) @@ -137,7 +184,11 @@ signal_set_service::signal_set_service( #if !defined(ASIO_WINDOWS) \ && !defined(ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + io_uring_service_.init_task(); +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) reactor_.init_task(); +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // !defined(ASIO_WINDOWS) // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) @@ -169,11 +220,10 @@ void signal_set_service::shutdown() } } - io_context_.abandon_operations(ops); + scheduler_.abandon_operations(ops); } -void signal_set_service::notify_fork( - asio::io_context::fork_event fork_ev) +void signal_set_service::notify_fork(execution_context::fork_event fork_ev) { #if !defined(ASIO_WINDOWS) \ && !defined(ASIO_WINDOWS_RUNTIME) \ @@ -183,25 +233,38 @@ void signal_set_service::notify_fork( switch (fork_ev) { - case asio::io_context::fork_prepare: + case execution_context::fork_prepare: { int read_descriptor = state->read_descriptor_; state->fork_prepared_ = true; lock.unlock(); +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + (void)read_descriptor; + io_uring_service_.deregister_io_object(io_object_data_); + io_uring_service_.cleanup_io_object(io_object_data_); +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_); + reactor_.cleanup_descriptor_data(reactor_data_); +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) } break; - case asio::io_context::fork_parent: + case execution_context::fork_parent: if (state->fork_prepared_) { int read_descriptor = state->read_descriptor_; state->fork_prepared_ = false; lock.unlock(); +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + (void)read_descriptor; + io_uring_service_.register_internal_io_object(io_object_data_, + io_uring_service::read_op, new pipe_read_op); +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) reactor_.register_internal_descriptor(reactor::read_op, read_descriptor, reactor_data_, new pipe_read_op); +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) } break; - case asio::io_context::fork_child: + case execution_context::fork_child: if (state->fork_prepared_) { asio::detail::signal_blocker blocker; @@ -210,8 +273,14 @@ void signal_set_service::notify_fork( int read_descriptor = state->read_descriptor_; state->fork_prepared_ = false; lock.unlock(); +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + (void)read_descriptor; + io_uring_service_.register_internal_io_object(io_object_data_, + io_uring_service::read_op, new pipe_read_op); +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) reactor_.register_internal_descriptor(reactor::read_op, read_descriptor, reactor_data_, new pipe_read_op); +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) } break; default: @@ -241,8 +310,8 @@ void signal_set_service::destroy( } asio::error_code signal_set_service::add( - signal_set_service::implementation_type& impl, - int signal_number, asio::error_code& ec) + signal_set_service::implementation_type& impl, int signal_number, + signal_set_base::flags_t f, asio::error_code& ec) { // Check that the signal number is valid. if (signal_number < 0 || signal_number >= max_signal_number) @@ -251,6 +320,15 @@ asio::error_code signal_set_service::add( return ec; } + // Check that the specified flags are supported. +#if !defined(ASIO_HAS_SIGACTION) + if (f != signal_set_base::flags::dont_care) + { + ec = asio::error::operation_not_supported; + return ec; + } +#endif // !defined(ASIO_HAS_SIGACTION) + signal_state* state = get_signal_state(); static_mutex::scoped_lock lock(state->mutex_); @@ -278,6 +356,8 @@ asio::error_code signal_set_service::add( memset(&sa, 0, sizeof(sa)); sa.sa_handler = asio_signal_handler; sigfillset(&sa.sa_mask); + if (f != signal_set_base::flags::dont_care) + sa.sa_flags = static_cast<int>(f); if (::sigaction(signal_number, &sa, 0) == -1) # else // defined(ASIO_HAS_SIGACTION) if (::signal(signal_number, asio_signal_handler) == SIG_ERR) @@ -292,7 +372,39 @@ asio::error_code signal_set_service::add( delete new_registration; return ec; } +# if defined(ASIO_HAS_SIGACTION) + state->flags_[signal_number] = f; +# endif // defined(ASIO_HAS_SIGACTION) } +# if defined(ASIO_HAS_SIGACTION) + // Otherwise check to see if the flags have changed. + else if (f != signal_set_base::flags::dont_care) + { + if (f != state->flags_[signal_number]) + { + using namespace std; // For memset. + if (state->flags_[signal_number] != signal_set_base::flags::dont_care) + { + ec = asio::error::invalid_argument; + delete new_registration; + return ec; + } + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = asio_signal_handler; + sigfillset(&sa.sa_mask); + sa.sa_flags = static_cast<int>(f); + if (::sigaction(signal_number, &sa, 0) == -1) + { + ec = asio::error_code(errno, + asio::error::get_system_category()); + delete new_registration; + return ec; + } + state->flags_[signal_number] = f; + } + } +# endif // defined(ASIO_HAS_SIGACTION) #endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) // Record the new registration in the set. @@ -361,6 +473,9 @@ asio::error_code signal_set_service::remove( # endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) return ec; } +# if defined(ASIO_HAS_SIGACTION) + state->flags_[signal_number] = signal_set_base::flags_t(); +# endif // defined(ASIO_HAS_SIGACTION) } #endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) @@ -415,6 +530,9 @@ asio::error_code signal_set_service::clear( # endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) return ec; } +# if defined(ASIO_HAS_SIGACTION) + state->flags_[reg->signal_number_] = signal_set_base::flags_t(); +# endif // defined(ASIO_HAS_SIGACTION) } #endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION) @@ -440,7 +558,7 @@ asio::error_code signal_set_service::cancel( signal_set_service::implementation_type& impl, asio::error_code& ec) { - ASIO_HANDLER_OPERATION((io_context_.context(), + ASIO_HANDLER_OPERATION((scheduler_.context(), "signal_set", &impl, 0, "cancel")); op_queue<operation> ops; @@ -456,12 +574,39 @@ asio::error_code signal_set_service::cancel( } } - io_context_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); ec = asio::error_code(); return ec; } +void signal_set_service::cancel_ops_by_key( + signal_set_service::implementation_type& impl, void* cancellation_key) +{ + op_queue<operation> ops; + { + op_queue<signal_op> other_ops; + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + while (signal_op* op = impl.queue_.front()) + { + impl.queue_.pop(); + if (op->cancellation_key_ == cancellation_key) + { + op->ec_ = asio::error::operation_aborted; + ops.push(op); + } + else + other_ops.push(op); + } + + impl.queue_.push(other_ops); + } + + scheduler_.post_deferred_completions(ops); +} + void signal_set_service::deliver_signal(int signal_number) { signal_state* state = get_signal_state(); @@ -492,7 +637,7 @@ void signal_set_service::deliver_signal(int signal_number) reg = reg->next_in_table_; } - service->io_context_.post_deferred_completions(ops); + service->scheduler_.post_deferred_completions(ops); service = service->next_; } @@ -509,17 +654,17 @@ void signal_set_service::add_service(signal_set_service* service) open_descriptors(); #endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) - // If an io_context object is thread-unsafe then it must be the only - // io_context used to create signal_set objects. + // If a scheduler_ object is thread-unsafe then it must be the only + // scheduler used to create signal_set objects. if (state->service_list_ != 0) { if (!ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, - service->io_context_.concurrency_hint()) + service->scheduler_.concurrency_hint()) || !ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, - state->service_list_->io_context_.concurrency_hint())) + state->service_list_->scheduler_.concurrency_hint())) { std::logic_error ex( - "Thread-unsafe io_context objects require " + "Thread-unsafe execution context objects require " "exclusive access to signal handling."); asio::detail::throw_exception(ex); } @@ -538,8 +683,14 @@ void signal_set_service::add_service(signal_set_service* service) // Register for pipe readiness notifications. int read_descriptor = state->read_descriptor_; lock.unlock(); +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + (void)read_descriptor; + service->io_uring_service_.register_internal_io_object( + service->io_object_data_, io_uring_service::read_op, new pipe_read_op); +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) service->reactor_.register_internal_descriptor(reactor::read_op, read_descriptor, service->reactor_data_, new pipe_read_op); +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // !defined(ASIO_WINDOWS) // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) @@ -558,9 +709,17 @@ void signal_set_service::remove_service(signal_set_service* service) // Disable the pipe readiness notifications. int read_descriptor = state->read_descriptor_; lock.unlock(); - service->reactor_.deregister_descriptor( - read_descriptor, service->reactor_data_, false); +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + (void)read_descriptor; + service->io_uring_service_.deregister_io_object(service->io_object_data_); + service->io_uring_service_.cleanup_io_object(service->io_object_data_); + lock.lock(); +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + service->reactor_.deregister_internal_descriptor( + read_descriptor, service->reactor_data_); + service->reactor_.cleanup_descriptor_data(service->reactor_data_); lock.lock(); +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // !defined(ASIO_WINDOWS) // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) @@ -637,7 +796,7 @@ void signal_set_service::close_descriptors() void signal_set_service::start_wait_op( signal_set_service::implementation_type& impl, signal_op* op) { - io_context_.work_started(); + scheduler_.work_started(); signal_state* state = get_signal_state(); static_mutex::scoped_lock lock(state->mutex_); @@ -649,7 +808,7 @@ void signal_set_service::start_wait_op( { --reg->undelivered_; op->signal_number_ = reg->signal_number_; - io_context_.post_deferred_completion(op); + scheduler_.post_deferred_completion(op); return; } diff --git a/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp b/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp index d9cc1c95722..7feb7ca02df 100644 --- a/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp +++ b/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp @@ -2,7 +2,7 @@ // detail/impl/socket_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -73,32 +73,39 @@ inline void clear_last_error() #if !defined(ASIO_WINDOWS_RUNTIME) -template <typename ReturnType> -inline ReturnType error_wrapper(ReturnType return_value, - asio::error_code& ec) +inline void get_last_error( + asio::error_code& ec, bool is_error_condition) { + if (!is_error_condition) + { + asio::error::clear(ec); + } + else + { #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - ec = asio::error_code(WSAGetLastError(), - asio::error::get_system_category()); + ec = asio::error_code(WSAGetLastError(), + asio::error::get_system_category()); #else - ec = asio::error_code(errno, - asio::error::get_system_category()); + ec = asio::error_code(errno, + asio::error::get_system_category()); #endif - return return_value; + } } template <typename SockLenType> inline socket_type call_accept(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) + socket_type s, void* addr, std::size_t* addrlen) { SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; - socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + socket_type result = ::accept(s, + static_cast<socket_addr_type*>(addr), + addrlen ? &tmp_addrlen : 0); if (addrlen) *addrlen = (std::size_t)tmp_addrlen; return result; } -socket_type accept(socket_type s, socket_addr_type* addr, +socket_type accept(socket_type s, void* addr, std::size_t* addrlen, asio::error_code& ec) { if (s == invalid_socket) @@ -107,17 +114,16 @@ socket_type accept(socket_type s, socket_addr_type* addr, return invalid_socket; } - clear_last_error(); - - socket_type new_s = error_wrapper(call_accept( - &msghdr::msg_namelen, s, addr, addrlen), ec); + socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, new_s == invalid_socket); if (new_s == invalid_socket) return new_s; #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) int optval = 1; - int result = error_wrapper(::setsockopt(new_s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + int result = ::setsockopt(new_s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); if (result != 0) { ::close(new_s); @@ -125,12 +131,12 @@ socket_type accept(socket_type s, socket_addr_type* addr, } #endif - ec = asio::error_code(); + asio::error::clear(ec); return new_s; } socket_type sync_accept(socket_type s, state_type state, - socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) + void* addr, std::size_t* addrlen, asio::error_code& ec) { // Accept a socket. for (;;) @@ -175,9 +181,8 @@ socket_type sync_accept(socket_type s, state_type state, #if defined(ASIO_HAS_IOCP) -void complete_iocp_accept(socket_type s, - void* output_buffer, DWORD address_length, - socket_addr_type* addr, std::size_t* addrlen, +void complete_iocp_accept(socket_type s, void* output_buffer, + DWORD address_length, void* addr, std::size_t* addrlen, socket_type new_socket, asio::error_code& ec) { // Map non-portable errors to their portable counterparts. @@ -221,7 +226,7 @@ void complete_iocp_accept(socket_type s, #else // defined(ASIO_HAS_IOCP) bool non_blocking_accept(socket_type s, - state_type state, socket_addr_type* addr, std::size_t* addrlen, + state_type state, void* addr, std::size_t* addrlen, asio::error_code& ec, socket_type& new_socket) { for (;;) @@ -241,8 +246,6 @@ bool non_blocking_accept(socket_type s, if (ec == asio::error::would_block || ec == asio::error::try_again) { - if (state & user_set_non_blocking) - return true; // Fall through to retry operation. } else if (ec == asio::error::connection_aborted) @@ -270,12 +273,13 @@ bool non_blocking_accept(socket_type s, template <typename SockLenType> inline int call_bind(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) + socket_type s, const void* addr, std::size_t addrlen) { - return ::bind(s, addr, (SockLenType)addrlen); + return ::bind(s, static_cast<const socket_addr_type*>(addr), + (SockLenType)addrlen); } -int bind(socket_type s, const socket_addr_type* addr, +int bind(socket_type s, const void* addr, std::size_t addrlen, asio::error_code& ec) { if (s == invalid_socket) @@ -284,11 +288,8 @@ int bind(socket_type s, const socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_bind( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -311,12 +312,12 @@ int close(socket_type s, state_type& state, SO_LINGER, &opt, sizeof(opt), ignored_ec); } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::closesocket(s), ec); + result = ::closesocket(s); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::close(s), ec); + result = ::close(s); #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); if (result != 0 && (ec == asio::error::would_block @@ -332,28 +333,44 @@ int close(socket_type s, state_type& state, ioctl_arg_type arg = 0; ::ioctlsocket(s, FIONBIO, &arg); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) -# if defined(__SYMBIAN32__) +# if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int flags = ::fcntl(s, F_GETFL, 0); if (flags >= 0) ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); -# else // defined(__SYMBIAN32__) +# else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = 0; +# if defined(ENOTTY) || defined(ENOTCAPABLE) + result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + int flags = ::fcntl(s, F_GETFL, 0); + if (flags >= 0) + ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); + } +# else // defined(ENOTTY) || defined(ENOTCAPABLE) ::ioctl(s, FIONBIO, &arg); -# endif // defined(__SYMBIAN32__) +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +# endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) state &= ~non_blocking; - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::closesocket(s), ec); + result = ::closesocket(s); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::close(s), ec); + result = ::close(s); #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); } } - if (result == 0) - ec = asio::error_code(); return result; } @@ -366,26 +383,47 @@ bool set_user_non_blocking(socket_type s, return false; } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); -#elif defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - clear_last_error(); int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); } -#else +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); -#endif + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +# if defined(ENOTTY) || defined(ENOTCAPABLE) + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); + } + } +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = asio::error_code(); if (value) state |= user_set_non_blocking; else @@ -419,26 +457,47 @@ bool set_internal_non_blocking(socket_type s, return false; } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); -#elif defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - clear_last_error(); int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); } -#else +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); -#endif + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +# if defined(ENOTTY) || defined(ENOTCAPABLE) + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); + } + } +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = asio::error_code(); if (value) state |= internal_non_blocking; else @@ -457,21 +516,20 @@ int shutdown(socket_type s, int what, asio::error_code& ec) return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(::shutdown(s, what), ec); - if (result == 0) - ec = asio::error_code(); + int result = ::shutdown(s, what); + get_last_error(ec, result != 0); return result; } template <typename SockLenType> inline int call_connect(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) + socket_type s, const void* addr, std::size_t addrlen) { - return ::connect(s, addr, (SockLenType)addrlen); + return ::connect(s, static_cast<const socket_addr_type*>(addr), + (SockLenType)addrlen); } -int connect(socket_type s, const socket_addr_type* addr, +int connect(socket_type s, const void* addr, std::size_t addrlen, asio::error_code& ec) { if (s == invalid_socket) @@ -480,19 +538,21 @@ int connect(socket_type s, const socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_connect( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); #if defined(__linux__) - else if (ec == asio::error::try_again) - ec = asio::error::no_buffer_space; + if (result != 0 && ec == asio::error::try_again) + { + if (static_cast<const socket_addr_type*>(addr)->sa_family == AF_UNIX) + ec = asio::error::in_progress; + else + ec = asio::error::no_buffer_space; + } #endif // defined(__linux__) return result; } -void sync_connect(socket_type s, const socket_addr_type* addr, +void sync_connect(socket_type s, const void* addr, std::size_t addrlen, asio::error_code& ec) { // Perform the connect operation. @@ -602,7 +662,7 @@ bool non_blocking_connect(socket_type s, asio::error_code& ec) asio::error::get_system_category()); } else - ec = asio::error_code(); + asio::error::clear(ec); } return true; @@ -619,10 +679,8 @@ int socketpair(int af, int type, int protocol, ec = asio::error::operation_not_supported; return socket_error_retval; #else - clear_last_error(); - int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); - if (result == 0) - ec = asio::error_code(); + int result = ::socketpair(af, type, protocol, sv); + get_last_error(ec, result != 0); return result; #endif } @@ -638,20 +696,18 @@ bool sockatmark(socket_type s, asio::error_code& ec) #if defined(SIOCATMARK) ioctl_arg_type value = 0; # if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); + int result = ::ioctlsocket(s, SIOCATMARK, &value); # else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); + int result = ::ioctl(s, SIOCATMARK, &value); # endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - ec = asio::error_code(); + get_last_error(ec, result < 0); # if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket; # endif // defined(ENOTTY) #else // defined(SIOCATMARK) - int value = error_wrapper(::sockatmark(s), ec); - if (value != -1) - ec = asio::error_code(); + int value = ::sockatmark(s); + get_last_error(ec, value < 0); #endif // defined(SIOCATMARK) return ec ? false : value != 0; @@ -667,12 +723,11 @@ size_t available(socket_type s, asio::error_code& ec) ioctl_arg_type value = 0; #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); + int result = ::ioctlsocket(s, FIONREAD, &value); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); + int result = ::ioctl(s, FIONREAD, &value); #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - ec = asio::error_code(); + get_last_error(ec, result < 0); #if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket; @@ -689,10 +744,8 @@ int listen(socket_type s, int backlog, asio::error_code& ec) return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(::listen(s, backlog), ec); - if (result == 0) - ec = asio::error_code(); + int result = ::listen(s, backlog); + get_last_error(ec, result != 0); return result; } @@ -735,9 +788,9 @@ void init_buf(buf& b, const void* data, size_t size) #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } -inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +inline void init_msghdr_msg_name(void*& name, void* addr) { - name = addr; + name = static_cast<socket_addr_type*>(addr); } inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) @@ -746,43 +799,74 @@ inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) } template <typename T> -inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +inline void init_msghdr_msg_name(T& name, void* addr) { - name = reinterpret_cast<T>(addr); + name = static_cast<T>(addr); } template <typename T> -inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +inline void init_msghdr_msg_name(T& name, const void* addr) { - name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr)); + name = static_cast<T>(const_cast<void*>(addr)); } signed_size_type recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int result = error_wrapper(::WSARecv(s, bufs, - recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + int result = ::WSARecv(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + asio::error::clear(ec); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); - if (result >= 0) - ec = asio::error_code(); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +signed_size_type recv1(socket_type s, void* data, size_t size, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = const_cast<char*>(static_cast<const char*>(data)); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(s, &buf, 1, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + asio::error::clear(ec); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = ::recv(s, static_cast<char*>(data), size, flags); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -799,7 +883,7 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, // A request to read 0 bytes on a stream is a no-op. if (all_empty && (state & stream_oriented)) { - ec = asio::error_code(); + asio::error::clear(ec); return 0; } @@ -809,10 +893,51 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, // Try to complete the operation without blocking. signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = asio::error::eof; + return 0; + } + // Check if operation succeeded. - if (bytes > 0) + if (bytes >= 0) return bytes; + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +size_t sync_recv1(socket_type s, state_type state, void* data, + size_t size, int flags, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + // Check for EOF. if ((state & stream_oriented) && bytes == 0) { @@ -820,6 +945,10 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, return 0; } + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block @@ -850,6 +979,10 @@ void complete_iocp_recv(state_type state, { ec = asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + asio::error::clear(ec); + } // Check for connection closed. else if (!ec && bytes_transferred == 0 @@ -878,6 +1011,13 @@ bool non_blocking_recv(socket_type s, return true; } + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -887,15 +1027,46 @@ bool non_blocking_recv(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_recv1(socket_type s, + void* data, size_t size, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -903,26 +1074,27 @@ bool non_blocking_recv(socket_type s, #endif // defined(ASIO_HAS_IOCP) signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, - int flags, socket_addr_type* addr, std::size_t* addrlen, - asio::error_code& ec) + int flags, void* addr, std::size_t* addrlen, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int tmp_addrlen = (int)*addrlen; - int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + int result = ::WSARecvFrom(s, bufs, recv_buf_count, &bytes_transferred, + &recv_flags, static_cast<socket_addr_type*>(addr), &tmp_addrlen, 0, 0); + get_last_error(ec, true); *addrlen = (std::size_t)tmp_addrlen; if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + asio::error::clear(ec); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -930,17 +1102,60 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, msg.msg_namelen = static_cast<int>(*addrlen); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); *addrlen = msg.msg_namelen; - if (result >= 0) - ec = asio::error_code(); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } -size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, - size_t count, int flags, socket_addr_type* addr, - std::size_t* addrlen, asio::error_code& ec) +template <typename SockLenType> +inline signed_size_type call_recvfrom(SockLenType msghdr::*, socket_type s, + void* data, size_t size, int flags, void* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + signed_size_type result = ::recvfrom(s, static_cast<char*>(data), size, + flags, static_cast<socket_addr_type*>(addr), addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +signed_size_type recvfrom1(socket_type s, void* data, size_t size, + int flags, void* addr, std::size_t* addrlen, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = static_cast<char*>(data); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred, &recv_flags, + static_cast<socket_addr_type*>(addr), &tmp_addrlen, 0, 0); + get_last_error(ec, true); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + asio::error::clear(ec); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = call_recvfrom(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, size_t count, + int flags, void* addr, std::size_t* addrlen, asio::error_code& ec) { if (s == invalid_socket) { @@ -971,6 +1186,38 @@ size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, } } +size_t sync_recvfrom1(socket_type s, state_type state, void* data, size_t size, + int flags, void* addr, std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + #if defined(ASIO_HAS_IOCP) void complete_iocp_recvfrom( @@ -989,13 +1236,16 @@ void complete_iocp_recvfrom( { ec = asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + asio::error::clear(ec); + } } #else // defined(ASIO_HAS_IOCP) -bool non_blocking_recvfrom(socket_type s, - buf* bufs, size_t count, int flags, - socket_addr_type* addr, std::size_t* addrlen, +bool non_blocking_recvfrom(socket_type s, buf* bufs, + size_t count, int flags, void* addr, std::size_t* addrlen, asio::error_code& ec, size_t& bytes_transferred) { for (;;) @@ -1004,6 +1254,13 @@ bool non_blocking_recvfrom(socket_type s, signed_size_type bytes = socket_ops::recvfrom( s, bufs, count, flags, addr, addrlen, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1013,15 +1270,40 @@ bool non_blocking_recvfrom(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_recvfrom1(socket_type s, void* data, + size_t size, int flags, void* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1031,7 +1313,6 @@ bool non_blocking_recvfrom(socket_type s, signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, int in_flags, int& out_flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) out_flags = 0; return socket_ops::recv(s, bufs, count, in_flags, ec); @@ -1039,12 +1320,10 @@ signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, in_flags), ec); + signed_size_type result = ::recvmsg(s, &msg, in_flags); + get_last_error(ec, result < 0); if (result >= 0) - { - ec = asio::error_code(); out_flags = msg.msg_flags; - } else out_flags = 0; return result; @@ -1102,6 +1381,10 @@ void complete_iocp_recvmsg( { ec = asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + asio::error::clear(ec); + } } #else // defined(ASIO_HAS_IOCP) @@ -1116,6 +1399,13 @@ bool non_blocking_recvmsg(socket_type s, signed_size_type bytes = socket_ops::recvmsg( s, bufs, count, in_flags, out_flags, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1125,15 +1415,8 @@ bool non_blocking_recvmsg(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = asio::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1143,32 +1426,63 @@ bool non_blocking_recvmsg(socket_type s, signed_size_type send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD send_flags = flags; - int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs), - send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + int result = ::WSASend(s, const_cast<buf*>(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + asio::error::clear(ec); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = const_cast<buf*>(bufs); msg.msg_iovlen = static_cast<int>(count); -#if defined(__linux__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - ec = asio::error_code(); +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +signed_size_type send1(socket_type s, const void* data, size_t size, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast<char*>(static_cast<const char*>(data)); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = ::WSASend(s, &buf, 1, + &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + asio::error::clear(ec); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::send(s, + static_cast<const char*>(data), size, flags); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1185,7 +1499,7 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs, // A request to write 0 bytes to a stream is a no-op. if (all_empty && (state & stream_oriented)) { - ec = asio::error_code(); + asio::error::clear(ec); return 0; } @@ -1211,6 +1525,44 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs, } } +size_t sync_send1(socket_type s, state_type state, const void* data, + size_t size, int flags, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + #if defined(ASIO_HAS_IOCP) void complete_iocp_send( @@ -1242,6 +1594,13 @@ bool non_blocking_send(socket_type s, // Write some data. signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1251,40 +1610,65 @@ bool non_blocking_send(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_send1(socket_type s, + const void* data, size_t size, int flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } #endif // defined(ASIO_HAS_IOCP) -signed_size_type sendto(socket_type s, const buf* bufs, size_t count, - int flags, const socket_addr_type* addr, std::size_t addrlen, - asio::error_code& ec) +signed_size_type sendto(socket_type s, const buf* bufs, + size_t count, int flags, const void* addr, + std::size_t addrlen, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; - int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs), - send_buf_count, &bytes_transferred, flags, addr, - static_cast<int>(addrlen), 0, 0), ec); + int result = ::WSASendTo(s, const_cast<buf*>(bufs), + send_buf_count, &bytes_transferred, flags, + static_cast<const socket_addr_type*>(addr), + static_cast<int>(addrlen), 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + asio::error::clear(ec); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -1292,18 +1676,59 @@ signed_size_type sendto(socket_type s, const buf* bufs, size_t count, msg.msg_namelen = static_cast<int>(addrlen); msg.msg_iov = const_cast<buf*>(bufs); msg.msg_iovlen = static_cast<int>(count); -#if defined(__linux__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - ec = asio::error_code(); +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template <typename SockLenType> +inline signed_size_type call_sendto(SockLenType msghdr::*, + socket_type s, const void* data, size_t size, int flags, + const void* addr, std::size_t addrlen) +{ + return ::sendto(s, static_cast<char*>(const_cast<void*>(data)), size, flags, + static_cast<const socket_addr_type*>(addr), (SockLenType)addrlen); +} + +signed_size_type sendto1(socket_type s, const void* data, + size_t size, int flags, const void* addr, + std::size_t addrlen, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast<char*>(static_cast<const char*>(data)); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + int result = ::WSASendTo(s, &buf, 1, &bytes_transferred, flags, + static_cast<const socket_addr_type*>(addr), + static_cast<int>(addrlen), 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + asio::error::clear(ec); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = call_sendto(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } -size_t sync_sendto(socket_type s, state_type state, const buf* bufs, - size_t count, int flags, const socket_addr_type* addr, +size_t sync_sendto(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, const void* addr, std::size_t addrlen, asio::error_code& ec) { if (s == invalid_socket) @@ -1335,11 +1760,44 @@ size_t sync_sendto(socket_type s, state_type state, const buf* bufs, } } +size_t sync_sendto1(socket_type s, state_type state, + const void* data, size_t size, int flags, const void* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + #if !defined(ASIO_HAS_IOCP) bool non_blocking_sendto(socket_type s, const buf* bufs, size_t count, int flags, - const socket_addr_type* addr, std::size_t addrlen, + const void* addr, std::size_t addrlen, asio::error_code& ec, size_t& bytes_transferred) { for (;;) @@ -1348,6 +1806,13 @@ bool non_blocking_sendto(socket_type s, signed_size_type bytes = socket_ops::sendto( s, bufs, count, flags, addr, addrlen, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1357,15 +1822,41 @@ bool non_blocking_sendto(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_sendto1(socket_type s, + const void* data, size_t size, int flags, + const void* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1375,10 +1866,9 @@ bool non_blocking_sendto(socket_type s, socket_type socket(int af, int type, int protocol, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - socket_type s = error_wrapper(::WSASocketW(af, type, protocol, 0, 0, - WSA_FLAG_OVERLAPPED), ec); + socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED); + get_last_error(ec, s == invalid_socket); if (s == invalid_socket) return s; @@ -1392,17 +1882,17 @@ socket_type socket(int af, int type, int protocol, reinterpret_cast<const char*>(&optval), sizeof(optval)); } - ec = asio::error_code(); - return s; #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type s = error_wrapper(::socket(af, type, protocol), ec); + socket_type s = ::socket(af, type, protocol); + get_last_error(ec, s == invalid_socket); if (s == invalid_socket) return s; int optval = 1; - int result = error_wrapper(::setsockopt(s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + int result = ::setsockopt(s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); if (result != 0) { ::close(s); @@ -1411,9 +1901,8 @@ socket_type socket(int af, int type, int protocol, return s; #else - int s = error_wrapper(::socket(af, type, protocol), ec); - if (s >= 0) - ec = asio::error_code(); + int s = ::socket(af, type, protocol); + get_last_error(ec, s < 0); return s; #endif } @@ -1455,7 +1944,7 @@ int setsockopt(socket_type s, state_type& state, int level, int optname, state |= enable_connection_aborted; else state &= ~enable_connection_aborted; - ec = asio::error_code(); + asio::error::clear(ec); return 0; } @@ -1471,24 +1960,24 @@ int setsockopt(socket_type s, state_type& state, int level, int optname, typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) { - clear_last_error(); - return error_wrapper(sso(s, level, optname, + int result = sso(s, level, optname, reinterpret_cast<const char*>(optval), - static_cast<int>(optlen)), ec); + static_cast<int>(optlen)); + get_last_error(ec, result != 0); + return result; } } ec = asio::error::fault; return socket_error_retval; #else // defined(__BORLANDC__) - clear_last_error(); - int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); if (result == 0) { - ec = asio::error_code(); - #if defined(__MACH__) && defined(__APPLE__) \ - || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + || defined(__NetBSD__) || defined(__FreeBSD__) \ + || defined(__OpenBSD__) || defined(__QNX__) // To implement portable behaviour for SO_REUSEADDR with UDP sockets we // need to also set SO_REUSEPORT on BSD-based platforms. if ((state & datagram_oriented) @@ -1540,7 +2029,7 @@ int getsockopt(socket_type s, state_type state, int level, int optname, } *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0; - ec = asio::error_code(); + asio::error::clear(ec); return 0; } @@ -1553,10 +2042,10 @@ int getsockopt(socket_type s, state_type state, int level, int optname, typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) { - clear_last_error(); int tmp_optlen = static_cast<int>(*optlen); - int result = error_wrapper(gso(s, level, optname, - reinterpret_cast<char*>(optval), &tmp_optlen), ec); + int result = gso(s, level, optname, + reinterpret_cast<char*>(optval), &tmp_optlen); + get_last_error(ec, result != 0); *optlen = static_cast<size_t>(tmp_optlen); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) @@ -1567,7 +2056,7 @@ int getsockopt(socket_type s, state_type state, int level, int optname, // value is non-zero (i.e. true). This corresponds to the behavior of // IPv6 sockets on Windows platforms pre-Vista. *static_cast<DWORD*>(optval) = 1; - ec = asio::error_code(); + asio::error::clear(ec); } return result; } @@ -1575,9 +2064,9 @@ int getsockopt(socket_type s, state_type state, int level, int optname, ec = asio::error::fault; return socket_error_retval; #elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) { @@ -1587,15 +2076,13 @@ int getsockopt(socket_type s, state_type state, int level, int optname, // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets // on Windows platforms pre-Vista. *static_cast<DWORD*>(optval) = 1; - ec = asio::error_code(); + asio::error::clear(ec); } - if (result == 0) - ec = asio::error_code(); return result; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); #if defined(__linux__) if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) && (optname == SO_SNDBUF || optname == SO_RCVBUF)) @@ -1608,24 +2095,23 @@ int getsockopt(socket_type s, state_type state, int level, int optname, *static_cast<int*>(optval) /= 2; } #endif // defined(__linux__) - if (result == 0) - ec = asio::error_code(); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } template <typename SockLenType> inline int call_getpeername(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) + socket_type s, void* addr, std::size_t* addrlen) { SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getpeername(s, addr, &tmp_addrlen); + int result = ::getpeername(s, + static_cast<socket_addr_type*>(addr), &tmp_addrlen); *addrlen = (std::size_t)tmp_addrlen; return result; } -int getpeername(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, bool cached, asio::error_code& ec) +int getpeername(socket_type s, void* addr, std::size_t* addrlen, + bool cached, asio::error_code& ec) { if (s == invalid_socket) { @@ -1652,7 +2138,7 @@ int getpeername(socket_type s, socket_addr_type* addr, } // The cached value is still valid. - ec = asio::error_code(); + asio::error::clear(ec); return 0; } #else // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) @@ -1661,25 +2147,23 @@ int getpeername(socket_type s, socket_addr_type* addr, #endif // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) // || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getpeername( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } template <typename SockLenType> inline int call_getsockname(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) + socket_type s, void* addr, std::size_t* addrlen) { SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getsockname(s, addr, &tmp_addrlen); + int result = ::getsockname(s, + static_cast<socket_addr_type*>(addr), &tmp_addrlen); *addrlen = (std::size_t)tmp_addrlen; return result; } -int getsockname(socket_type s, socket_addr_type* addr, +int getsockname(socket_type s, void* addr, std::size_t* addrlen, asio::error_code& ec) { if (s == invalid_socket) @@ -1688,11 +2172,8 @@ int getsockname(socket_type s, socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_getsockname( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -1705,20 +2186,17 @@ int ioctl(socket_type s, state_type& state, int cmd, return socket_error_retval; } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); + int result = ::ioctlsocket(s, cmd, arg); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - int result = error_wrapper(::ioctl(s, - static_cast<unsigned int>(cmd), arg), ec); + int result = ::ioctl(s, static_cast<unsigned int>(cmd), arg); #else - int result = error_wrapper(::ioctl(s, cmd, arg), ec); + int result = ::ioctl(s, cmd, arg); #endif + get_last_error(ec, result < 0); if (result >= 0) { - ec = asio::error_code(); - // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the socket is already in // the correct state. This ensures that the underlying socket is put into @@ -1746,7 +2224,9 @@ int ioctl(socket_type s, state_type& state, int cmd, int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout, asio::error_code& ec) { - clear_last_error(); +#if defined(__EMSCRIPTEN__) + exceptfds = 0; +#endif // defined(__EMSCRIPTEN__) #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) if (!readfds && !writefds && !exceptfds && timeout) { @@ -1754,7 +2234,7 @@ int select(int nfds, fd_set* readfds, fd_set* writefds, if (milliseconds == 0) milliseconds = 1; // Force context switch. ::Sleep(milliseconds); - ec = asio::error_code(); + asio::error::clear(ec); return 0; } @@ -1773,15 +2253,13 @@ int select(int nfds, fd_set* readfds, fd_set* writefds, timespec ts; ts.tv_sec = timeout ? timeout->tv_sec : 0; ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; - return error_wrapper(::pselect(nfds, readfds, - writefds, exceptfds, timeout ? &ts : 0, 0), ec); + int result = ::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0); #else - int result = error_wrapper(::select(nfds, readfds, - writefds, exceptfds, timeout), ec); - if (result >= 0) - ec = asio::error_code(); - return result; + int result = ::select(nfds, readfds, writefds, exceptfds, timeout); #endif + get_last_error(ec, result < 0); + return result; } int poll_read(socket_type s, state_type state, @@ -1815,8 +2293,8 @@ int poll_read(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec); + int result = ::select(s + 1, &fds, 0, 0, timeout); + get_last_error(ec, result < 0); #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -1825,16 +2303,14 @@ int poll_read(socket_type s, state_type state, fds.events = POLLIN; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -1869,8 +2345,8 @@ int poll_write(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec); + int result = ::select(s + 1, 0, &fds, 0, timeout); + get_last_error(ec, result < 0); #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -1879,16 +2355,14 @@ int poll_write(socket_type s, state_type state, fds.events = POLLOUT; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -1923,8 +2397,8 @@ int poll_error(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec); + int result = ::select(s + 1, 0, 0, &fds, timeout); + get_last_error(ec, result < 0); #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -1933,16 +2407,14 @@ int poll_error(socket_type s, state_type state, fds.events = POLLPRI | POLLERR | POLLHUP; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -1973,11 +2445,8 @@ int poll_connect(socket_type s, int msec, asio::error_code& ec) } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select( - s + 1, 0, &write_fds, &except_fds, timeout), ec); - if (result >= 0) - ec = asio::error_code(); + int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout); + get_last_error(ec, result < 0); return result; #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) @@ -1986,10 +2455,8 @@ int poll_connect(socket_type s, int msec, asio::error_code& ec) fds.fd = s; fds.events = POLLOUT; fds.revents = 0; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, msec), ec); - if (result >= 0) - ec = asio::error_code(); + int result = ::poll(&fds, 1, msec); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) @@ -2074,18 +2541,20 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, DWORD string_length = static_cast<DWORD>(length); #if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); - int result = error_wrapper(::WSAAddressToStringW(&address.base, - address_length, 0, string_buffer, &string_length), ec); + int result = ::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length); + get_last_error(ec, true); ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, static_cast<int>(length), 0, 0); #else - int result = error_wrapper(::WSAAddressToStringA( - &address.base, address_length, 0, dest, &string_length), ec); + int result = ::WSAAddressToStringA(&address.base, + address_length, 0, dest, &string_length); + get_last_error(ec, true); #endif // Windows may set error code on success. if (result != socket_error_retval) - ec = asio::error_code(); + asio::error::clear(ec); // Windows may not set an error code on failure. else if (result == socket_error_retval && !ec) @@ -2093,14 +2562,14 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, return result == socket_error_retval ? 0 : dest; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - const char* result = error_wrapper(::inet_ntop( - af, src, dest, static_cast<int>(length)), ec); + const char* result = ::inet_ntop(af, src, dest, static_cast<int>(length)); + get_last_error(ec, true); if (result == 0 && !ec) ec = asio::error::invalid_argument; if (result != 0 && af == ASIO_OS_DEF(AF_INET6) && scope_id != 0) { using namespace std; // For strcat and sprintf. - char if_name[IF_NAMESIZE + 1] = "%"; + char if_name[(IF_NAMESIZE > 21 ? IF_NAMESIZE : 21) + 1] = "%"; const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src); bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); @@ -2108,7 +2577,11 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02)); if ((!is_link_local && !is_multicast_link_local) || if_indextoname(static_cast<unsigned>(scope_id), if_name + 1) == 0) +#if defined(ASIO_HAS_SNPRINTF) + snprintf(if_name + 1, sizeof(if_name) - 1, "%lu", scope_id); +#else // defined(ASIO_HAS_SNPRINTF) sprintf(if_name + 1, "%lu", scope_id); +#endif // defined(ASIO_HAS_SNPRINTF) strcat(dest, if_name); } return result; @@ -2139,7 +2612,7 @@ int inet_pton(int af, const char* src, void* dest, bytes[1] = static_cast<unsigned char>(b1); bytes[2] = static_cast<unsigned char>(b2); bytes[3] = static_cast<unsigned char>(b3); - ec = asio::error_code(); + asio::error::clear(ec); return 1; } else if (af == ASIO_OS_DEF(AF_INET6)) @@ -2255,7 +2728,7 @@ int inet_pton(int af, const char* src, void* dest, for (int i = 0; i < num_back_bytes; ++i) bytes[16 - num_back_bytes + i] = back_bytes[i]; - ec = asio::error_code(); + asio::error::clear(ec); return 1; } else @@ -2284,11 +2757,13 @@ int inet_pton(int af, const char* src, void* dest, int num_wide_chars = static_cast<int>(strlen(src)) + 1; LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); - int result = error_wrapper(::WSAStringToAddressW( - wide_buffer, af, 0, &address.base, &address_length), ec); + int result = ::WSAStringToAddressW(wide_buffer, + af, 0, &address.base, &address_length); + get_last_error(ec, true); #else - int result = error_wrapper(::WSAStringToAddressA( - const_cast<char*>(src), af, 0, &address.base, &address_length), ec); + int result = ::WSAStringToAddressA(const_cast<char*>(src), + af, 0, &address.base, &address_length); + get_last_error(ec, true); #endif if (af == ASIO_OS_DEF(AF_INET)) @@ -2296,12 +2771,12 @@ int inet_pton(int af, const char* src, void* dest, if (result != socket_error_retval) { memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); - ec = asio::error_code(); + asio::error::clear(ec); } else if (strcmp(src, "255.255.255.255") == 0) { static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; - ec = asio::error_code(); + asio::error::clear(ec); } } else // AF_INET6 @@ -2311,7 +2786,7 @@ int inet_pton(int af, const char* src, void* dest, memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); if (scope_id) *scope_id = address.v6.sin6_scope_id; - ec = asio::error_code(); + asio::error::clear(ec); } } @@ -2320,7 +2795,7 @@ int inet_pton(int af, const char* src, void* dest, ec = asio::error::invalid_argument; if (result != socket_error_retval) - ec = asio::error_code(); + asio::error::clear(ec); return result == socket_error_retval ? -1 : 1; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) @@ -2344,7 +2819,8 @@ int inet_pton(int af, const char* src, void* dest, src_ptr = src_buf; } - int result = error_wrapper(::inet_pton(af, src_ptr, dest), ec); + int result = ::inet_pton(af, src_ptr, dest); + get_last_error(ec, true); if (result <= 0 && !ec) ec = asio::error::invalid_argument; if (result > 0 && is_v6 && scope_id) @@ -2370,7 +2846,6 @@ int inet_pton(int af, const char* src, void* dest, int gethostname(char* name, int namelen, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS_RUNTIME) try { @@ -2401,11 +2876,8 @@ int gethostname(char* name, int namelen, asio::error_code& ec) return -1; } #else // defined(ASIO_WINDOWS_RUNTIME) - int result = error_wrapper(::gethostname(name, namelen), ec); -# if defined(ASIO_WINDOWS) - if (result == 0) - ec = asio::error_code(); -# endif // defined(ASIO_WINDOWS) + int result = ::gethostname(name, namelen); + get_last_error(ec, result != 0); return result; #endif // defined(ASIO_WINDOWS_RUNTIME) } @@ -2440,20 +2912,20 @@ inline asio::error_code translate_netdb_error(int error) inline hostent* gethostbyaddr(const char* addr, int length, int af, hostent* result, char* buffer, int buflength, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); - hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + hostent* retval = ::gethostbyaddr(addr, length, af); + get_last_error(ec, !retval); if (!retval) return 0; - ec = asio::error_code(); *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) int error = 0; - hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, - buffer, buflength, &error), ec); + hostent* retval = ::gethostbyaddr_r(addr, length, + af, result, buffer, buflength, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; @@ -2461,8 +2933,8 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, (void)(buffer); (void)(buflength); int error = 0; - hostent* retval = error_wrapper(::getipnodebyaddr( - addr, length, af, &error), ec); + hostent* retval = ::getipnodebyaddr(addr, length, af, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); if (!retval) @@ -2472,8 +2944,10 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, #else hostent* retval = 0; int error = 0; - error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, - buflength, &retval, &error), ec); + clear_last_error(); + ::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &retval, &error); + get_last_error(ec, true); if (error) ec = translate_netdb_error(error); return retval; @@ -2483,7 +2957,6 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, inline hostent* gethostbyname(const char* name, int af, struct hostent* result, char* buffer, int buflength, int ai_flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); @@ -2493,10 +2966,10 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, ec = asio::error::address_family_not_supported; return 0; } - hostent* retval = error_wrapper(::gethostbyname(name), ec); + hostent* retval = ::gethostbyname(name); + get_last_error(ec, !retval); if (!retval) return 0; - ec = asio::error_code(); *result = *retval; return result; #elif defined(__sun) || defined(__QNX__) @@ -2507,8 +2980,8 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, return 0; } int error = 0; - hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, - buflength, &error), ec); + hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; @@ -2516,8 +2989,8 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, (void)(buffer); (void)(buflength); int error = 0; - hostent* retval = error_wrapper(::getipnodebyname( - name, af, ai_flags, &error), ec); + hostent* retval = ::getipnodebyname(name, af, ai_flags, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); if (!retval) @@ -2533,8 +3006,9 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, } hostent* retval = 0; int error = 0; - error_wrapper(::gethostbyname_r(name, result, - buffer, buflength, &retval, &error), ec); + clear_last_error(); + ::gethostbyname_r(name, result, buffer, buflength, &retval, &error); + get_last_error(ec, true); if (error) ec = translate_netdb_error(error); return retval; @@ -3215,7 +3689,9 @@ inline asio::error_code getnameinfo_emulation( { return ec = asio::error::no_buffer_space; } -#if defined(ASIO_HAS_SECURE_RTL) +#if defined(ASIO_HAS_SNPRINTF) + snprintf(serv, servlen, "%u", ntohs(port)); +#elif defined(ASIO_HAS_SECURE_RTL) sprintf_s(serv, servlen, "%u", ntohs(port)); #else // defined(ASIO_HAS_SECURE_RTL) sprintf(serv, "%u", ntohs(port)); @@ -3238,7 +3714,9 @@ inline asio::error_code getnameinfo_emulation( { return ec = asio::error::no_buffer_space; } -#if defined(ASIO_HAS_SECURE_RTL) +#if defined(ASIO_HAS_SNPRINTF) + snprintf(serv, servlen, "%u", ntohs(port)); +#elif defined(ASIO_HAS_SECURE_RTL) sprintf_s(serv, servlen, "%u", ntohs(port)); #else // defined(ASIO_HAS_SECURE_RTL) sprintf(serv, "%u", ntohs(port)); @@ -3250,7 +3728,7 @@ inline asio::error_code getnameinfo_emulation( } } - ec = asio::error_code(); + asio::error::clear(ec); return ec; } @@ -3327,6 +3805,37 @@ asio::error_code getaddrinfo(const char* host, return ec = translate_addrinfo_error(error); #else int error = ::getaddrinfo(host, service, &hints, result); +#if defined(__MACH__) && defined(__APPLE__) + using namespace std; // For isdigit and atoi. + if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0]))) + { + u_short_type port = host_to_network_short(atoi(service)); + for (addrinfo_type* ai = *result; ai; ai = ai->ai_next) + { + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr); + if (sinptr->sin_port == 0) + sinptr->sin_port = port; + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr); + if (sin6ptr->sin6_port == 0) + sin6ptr->sin6_port = port; + break; + } + default: + break; + } + } + } +#endif return ec = translate_addrinfo_error(error); #endif } @@ -3369,7 +3878,7 @@ void freeaddrinfo(addrinfo_type* ai) #endif } -asio::error_code getnameinfo(const socket_addr_type* addr, +asio::error_code getnameinfo(const void* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { @@ -3377,8 +3886,8 @@ asio::error_code getnameinfo(const socket_addr_type* addr, # if defined(ASIO_HAS_GETADDRINFO) // Building for Windows XP, Windows Server 2003, or later. clear_last_error(); - int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen), - host, static_cast<DWORD>(hostlen), + int error = ::getnameinfo(static_cast<const socket_addr_type*>(addr), + static_cast<socklen_t>(addrlen), host, static_cast<DWORD>(hostlen), serv, static_cast<DWORD>(servlen), flags); return ec = translate_addrinfo_error(error); # else @@ -3390,35 +3899,34 @@ asio::error_code getnameinfo(const socket_addr_type* addr, if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) { clear_last_error(); - int error = gni(addr, static_cast<int>(addrlen), - host, static_cast<DWORD>(hostlen), + int error = gni(static_cast<const socket_addr_type*>(addr), + static_cast<int>(addrlen), host, static_cast<DWORD>(hostlen), serv, static_cast<DWORD>(servlen), flags); return ec = translate_addrinfo_error(error); } } clear_last_error(); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); + return getnameinfo_emulation(static_cast<const socket_addr_type*>(addr), + addrlen, host, hostlen, serv, servlen, flags, ec); # endif #elif !defined(ASIO_HAS_GETADDRINFO) using namespace std; // For memcpy. sockaddr_storage_type tmp_addr; memcpy(&tmp_addr, addr, addrlen); - tmp_addr.ss_len = addrlen; - addr = reinterpret_cast<socket_addr_type*>(&tmp_addr); + addr = &tmp_addr; clear_last_error(); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); + return getnameinfo_emulation(static_cast<const socket_addr_type*>(addr), + addrlen, host, hostlen, serv, servlen, flags, ec); #else clear_last_error(); - int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + int error = ::getnameinfo(static_cast<const socket_addr_type*>(addr), + addrlen, host, hostlen, serv, servlen, flags); return ec = translate_addrinfo_error(error); #endif } -asio::error_code sync_getnameinfo( - const socket_addr_type* addr, std::size_t addrlen, - char* host, std::size_t hostlen, char* serv, +asio::error_code sync_getnameinfo(const void* addr, + std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec) { // First try resolving with the service name. If that fails try resolving @@ -3437,7 +3945,7 @@ asio::error_code sync_getnameinfo( asio::error_code background_getnameinfo( const weak_cancel_token_type& cancel_token, - const socket_addr_type* addr, std::size_t addrlen, + const void* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec) { diff --git a/3rdparty/asio/include/asio/detail/impl/socket_select_interrupter.ipp b/3rdparty/asio/include/asio/detail/impl/socket_select_interrupter.ipp index 2f4d37771d5..a5b29581eb0 100644 --- a/3rdparty/asio/include/asio/detail/impl/socket_select_interrupter.ipp +++ b/3rdparty/asio/include/asio/detail/impl/socket_select_interrupter.ipp @@ -2,7 +2,7 @@ // detail/impl/socket_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -60,11 +60,11 @@ void socket_select_interrupter::open_descriptors() addr.sin_family = AF_INET; addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK); addr.sin_port = 0; - if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + if (socket_ops::bind(acceptor.get(), &addr, addr_len, ec) == socket_error_retval) asio::detail::throw_error(ec, "socket_select_interrupter"); - if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + if (socket_ops::getsockname(acceptor.get(), &addr, &addr_len, ec) == socket_error_retval) asio::detail::throw_error(ec, "socket_select_interrupter"); @@ -83,7 +83,7 @@ void socket_select_interrupter::open_descriptors() if (client.get() == invalid_socket) asio::detail::throw_error(ec, "socket_select_interrupter"); - if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + if (socket_ops::connect(client.get(), &addr, addr_len, ec) == socket_error_retval) asio::detail::throw_error(ec, "socket_select_interrupter"); @@ -155,11 +155,20 @@ bool socket_select_interrupter::reset() socket_ops::buf b; socket_ops::init_buf(b, data, sizeof(data)); asio::error_code ec; - int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - return was_interrupted; + for (;;) + { + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + if (bytes_read == sizeof(data)) + continue; + if (bytes_read > 0) + return true; + if (bytes_read == 0) + return false; + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return true; + return false; + } } } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp b/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp index fedea1cf3b4..3ffb398dcf6 100644 --- a/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp +++ b/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp @@ -2,7 +2,7 @@ // detail/impl/strand_executor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,19 +15,130 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/call_stack.hpp" #include "asio/detail/fenced_block.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/recycling_allocator.hpp" #include "asio/executor_work_guard.hpp" +#include "asio/defer.hpp" +#include "asio/dispatch.hpp" +#include "asio/post.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +template <typename F, typename Allocator> +class strand_executor_service::allocator_binder +{ +public: + typedef Allocator allocator_type; + + allocator_binder(F&& f, const Allocator& a) + : f_(static_cast<F&&>(f)), + allocator_(a) + { + } + + allocator_binder(const allocator_binder& other) + : f_(other.f_), + allocator_(other.allocator_) + { + } + + allocator_binder(allocator_binder&& other) + : f_(static_cast<F&&>(other.f_)), + allocator_(static_cast<allocator_type&&>(other.allocator_)) + { + } + + allocator_type get_allocator() const noexcept + { + return allocator_; + } + + void operator()() + { + f_(); + } + +private: + F f_; + allocator_type allocator_; +}; + template <typename Executor> -class strand_executor_service::invoker +class strand_executor_service::invoker<Executor, + enable_if_t< + execution::is_executor<Executor>::value + >> +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + executor_(other.executor_) + { + } + + invoker(invoker&& other) + : impl_(static_cast<implementation_type&&>(other.impl_)), + executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + if (push_waiting_to_ready(this_->impl_)) + { + recycling_allocator<void> allocator; + executor_type ex = this_->executor_; + asio::prefer( + asio::require( + static_cast<executor_type&&>(ex), + execution::blocking.never), + execution::allocator(allocator) + ).execute(static_cast<invoker&&>(*this_)); + } + } + }; + + void operator()() + { + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + run_ready_handlers(impl_); + } + +private: + typedef decay_t< + prefer_result_t< + Executor, + execution::outstanding_work_t::tracked_t + > + > executor_type; + + implementation_type impl_; + executor_type executor_; +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor> +class strand_executor_service::invoker<Executor, + enable_if_t< + !execution::is_executor<Executor>::value + >> { public: invoker(const implementation_type& impl, Executor& ex) @@ -42,13 +153,11 @@ public: { } -#if defined(ASIO_HAS_MOVE) invoker(invoker&& other) - : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)), - work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_)) + : impl_(static_cast<implementation_type&&>(other.impl_)), + work_(static_cast<executor_work_guard<Executor>&&>(other.work_)) { } -#endif // defined(ASIO_HAS_MOVE) struct on_invoker_exit { @@ -56,38 +165,22 @@ public: ~on_invoker_exit() { - this_->impl_->mutex_->lock(); - this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_); - bool more_handlers = this_->impl_->locked_ = - !this_->impl_->ready_queue_.empty(); - this_->impl_->mutex_->unlock(); - - if (more_handlers) + if (push_waiting_to_ready(this_->impl_)) { Executor ex(this_->work_.get_executor()); recycling_allocator<void> allocator; - ex.post(ASIO_MOVE_CAST(invoker)(*this_), allocator); + ex.post(static_cast<invoker&&>(*this_), allocator); } } }; void operator()() { - // Indicate that this strand is executing on the current thread. - call_stack<strand_impl>::context ctx(impl_.get()); - // Ensure the next handler, if any, is scheduled on block exit. on_invoker_exit on_exit = { this }; (void)on_exit; - // Run all ready handlers. No lock is required since the ready queue is - // accessed only within the strand. - asio::error_code ec; - while (scheduler_operation* o = impl_->ready_queue_.front()) - { - impl_->ready_queue_.pop(); - o->complete(impl_.get(), ec, 0); - } + run_ready_handlers(impl_); } private: @@ -95,31 +188,89 @@ private: executor_work_guard<Executor> work_; }; +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor, typename Function> +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, Function&& function, + enable_if_t< + can_query<Executor, execution::allocator_t<void>>::value + >*) +{ + return strand_executor_service::do_execute(impl, ex, + static_cast<Function&&>(function), + asio::query(ex, execution::allocator)); +} + +template <typename Executor, typename Function> +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, Function&& function, + enable_if_t< + !can_query<Executor, execution::allocator_t<void>>::value + >*) +{ + return strand_executor_service::do_execute(impl, ex, + static_cast<Function&&>(function), + std::allocator<void>()); +} + +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::do_execute(const implementation_type& impl, + Executor& ex, Function&& function, const Allocator& a) +{ + typedef decay_t<Function> function_type; + + // If the executor is not never-blocking, and we are already in the strand, + // then the function can run immediately. + if (asio::query(ex, execution::blocking) != execution::blocking.never + && running_in_this_thread(impl)) + { + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(function)); + + fenced_block b(fenced_block::full); + static_cast<function_type&&>(tmp)(); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "execute")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + { + ex.execute(invoker<Executor>(impl, ex)); + } +} + template <typename Executor, typename Function, typename Allocator> void strand_executor_service::dispatch(const implementation_type& impl, - Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) + Executor& ex, Function&& function, const Allocator& a) { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(function)); + typedef decay_t<Function> function_type; // If we are already in the strand then the function can run immediately. - if (call_stack<strand_impl>::contains(impl.get())) + if (running_in_this_thread(impl)) { + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(function)); + fenced_block b(fenced_block::full); - asio_handler_invoke_helpers::invoke(tmp, tmp); + static_cast<function_type&&>(tmp)(); return; } - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); - // Allocate and construct an operation to wrap the function. - typedef executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, "strand_executor", impl.get(), 0, "dispatch")); @@ -128,27 +279,24 @@ void strand_executor_service::dispatch(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.dispatch(invoker<Executor>(impl, ex), allocator); + { + asio::dispatch(ex, + allocator_binder<invoker<Executor>, Allocator>( + invoker<Executor>(impl, ex), a)); + } } // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> void strand_executor_service::post(const implementation_type& impl, - Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) + Executor& ex, Function&& function, const Allocator& a) { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(function)); - - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); + typedef decay_t<Function> function_type; // Allocate and construct an operation to wrap the function. - typedef executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, "strand_executor", impl.get(), 0, "post")); @@ -157,27 +305,24 @@ void strand_executor_service::post(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.post(invoker<Executor>(impl, ex), allocator); + { + asio::post(ex, + allocator_binder<invoker<Executor>, Allocator>( + invoker<Executor>(impl, ex), a)); + } } // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> void strand_executor_service::defer(const implementation_type& impl, - Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) + Executor& ex, Function&& function, const Allocator& a) { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(function)); - - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); + typedef decay_t<Function> function_type; // Allocate and construct an operation to wrap the function. - typedef executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, "strand_executor", impl.get(), 0, "defer")); @@ -186,7 +331,11 @@ void strand_executor_service::defer(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.defer(invoker<Executor>(impl, ex), allocator); + { + asio::defer(ex, + allocator_binder<invoker<Executor>, Allocator>( + invoker<Executor>(impl, ex), a)); + } } } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/impl/strand_executor_service.ipp b/3rdparty/asio/include/asio/detail/impl/strand_executor_service.ipp index 3baadcb07be..a2dff894cca 100644 --- a/3rdparty/asio/include/asio/detail/impl/strand_executor_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/strand_executor_service.ipp @@ -2,7 +2,7 @@ // detail/impl/strand_executor_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -40,8 +40,11 @@ void strand_executor_service::shutdown() strand_impl* impl = impl_list_; while (impl) { + impl->mutex_->lock(); + impl->shutdown_ = true; ops.push(impl->waiting_queue_); ops.push(impl->ready_queue_); + impl->mutex_->unlock(); impl = impl->next_; } } @@ -51,6 +54,7 @@ strand_executor_service::create_implementation() { implementation_type new_impl(new strand_impl); new_impl->locked_ = false; + new_impl->shutdown_ = false; asio::detail::mutex::scoped_lock lock(mutex_); @@ -92,7 +96,13 @@ bool strand_executor_service::enqueue(const implementation_type& impl, scheduler_operation* op) { impl->mutex_->lock(); - if (impl->locked_) + if (impl->shutdown_) + { + impl->mutex_->unlock(); + op->destroy(); + return false; + } + else if (impl->locked_) { // Some other function already holds the strand lock. Enqueue for later. impl->waiting_queue_.push(op); @@ -116,6 +126,30 @@ bool strand_executor_service::running_in_this_thread( return !!call_stack<strand_impl>::contains(impl.get()); } +bool strand_executor_service::push_waiting_to_ready(implementation_type& impl) +{ + impl->mutex_->lock(); + impl->ready_queue_.push(impl->waiting_queue_); + bool more_handlers = impl->locked_ = !impl->ready_queue_.empty(); + impl->mutex_->unlock(); + return more_handlers; +} + +void strand_executor_service::run_ready_handlers(implementation_type& impl) +{ + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl.get()); + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + asio::error_code ec; + while (scheduler_operation* o = impl->ready_queue_.front()) + { + impl->ready_queue_.pop(); + o->complete(impl.get(), ec, 0); + } +} + } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/impl/strand_service.hpp b/3rdparty/asio/include/asio/detail/impl/strand_service.hpp index 00b88a42bb1..8249c9eb8d5 100644 --- a/3rdparty/asio/include/asio/detail/impl/strand_service.hpp +++ b/3rdparty/asio/include/asio/detail/impl/strand_service.hpp @@ -2,7 +2,7 @@ // detail/impl/strand_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,11 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/call_stack.hpp" #include "asio/detail/completion_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/push_options.hpp" @@ -33,60 +31,30 @@ inline strand_service::strand_impl::strand_impl() { } -struct strand_service::on_dispatch_exit -{ - io_context_impl* io_context_; - strand_impl* impl_; - - ~on_dispatch_exit() - { - impl_->mutex_.lock(); - impl_->ready_queue_.push(impl_->waiting_queue_); - bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); - impl_->mutex_.unlock(); - - if (more_handlers) - io_context_->post_immediate_completion(impl_, false); - } -}; - template <typename Handler> void strand_service::dispatch(strand_service::implementation_type& impl, Handler& handler) { // If we are already in the strand then the handler can run immediately. - if (call_stack<strand_impl>::contains(impl)) + if (running_in_this_thread(impl)) { fenced_block b(fenced_block::full); - asio_handler_invoke_helpers::invoke(handler, handler); + static_cast<Handler&&>(handler)(); return; } // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> op; + typedef completion_handler<Handler, io_context::executor_type> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_context_.get_executor()); ASIO_HANDLER_CREATION((this->context(), *p.p, "strand", impl, 0, "dispatch")); - bool dispatch_immediately = do_dispatch(impl, p.p); operation* o = p.p; p.v = p.p = 0; - - if (dispatch_immediately) - { - // Indicate that this strand is executing on the current thread. - call_stack<strand_impl>::context ctx(impl); - - // Ensure the next handler, if any, is scheduled on block exit. - on_dispatch_exit on_exit = { &io_context_, impl }; - (void)on_exit; - - completion_handler<Handler>::do_complete( - &io_context_, o, asio::error_code(), 0); - } + do_dispatch(impl, o); } // Request the io_context to invoke the given handler and return immediately. @@ -98,10 +66,10 @@ void strand_service::post(strand_service::implementation_type& impl, asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> op; + typedef completion_handler<Handler, io_context::executor_type> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_context_.get_executor()); ASIO_HANDLER_CREATION((this->context(), *p.p, "strand", impl, 0, "post")); diff --git a/3rdparty/asio/include/asio/detail/impl/strand_service.ipp b/3rdparty/asio/include/asio/detail/impl/strand_service.ipp index 16946dcab67..af8929a00c6 100644 --- a/3rdparty/asio/include/asio/detail/impl/strand_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/strand_service.ipp @@ -2,7 +2,7 @@ // detail/impl/strand_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -43,7 +43,8 @@ struct strand_service::on_do_complete_exit strand_service::strand_service(asio::io_context& io_context) : asio::detail::service_base<strand_service>(io_context), - io_context_(asio::use_service<io_context_impl>(io_context)), + io_context_(io_context), + io_context_impl_(asio::use_service<io_context_impl>(io_context)), mutex_(), salt_(0) { @@ -90,18 +91,44 @@ bool strand_service::running_in_this_thread( return call_stack<strand_impl>::contains(impl) != 0; } -bool strand_service::do_dispatch(implementation_type& impl, operation* op) +struct strand_service::on_dispatch_exit +{ + io_context_impl* io_context_impl_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + impl_->ready_queue_.push(impl_->waiting_queue_); + bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); + impl_->mutex_.unlock(); + + if (more_handlers) + io_context_impl_->post_immediate_completion(impl_, false); + } +}; + +void strand_service::do_dispatch(implementation_type& impl, operation* op) { // If we are running inside the io_context, and no other handler already // holds the strand lock, then the handler can run immediately. - bool can_dispatch = io_context_.can_dispatch(); + bool can_dispatch = io_context_impl_.can_dispatch(); impl->mutex_.lock(); if (can_dispatch && !impl->locked_) { // Immediate invocation is allowed. impl->locked_ = true; impl->mutex_.unlock(); - return true; + + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_context_impl_, impl }; + (void)on_exit; + + op->complete(&io_context_impl_, asio::error_code(), 0); + return; } if (impl->locked_) @@ -117,10 +144,8 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op) impl->locked_ = true; impl->mutex_.unlock(); impl->ready_queue_.push(op); - io_context_.post_immediate_completion(impl, false); + io_context_impl_.post_immediate_completion(impl, false); } - - return false; } void strand_service::do_post(implementation_type& impl, @@ -140,7 +165,7 @@ void strand_service::do_post(implementation_type& impl, impl->locked_ = true; impl->mutex_.unlock(); impl->ready_queue_.push(op); - io_context_.post_immediate_completion(impl, is_continuation); + io_context_impl_.post_immediate_completion(impl, is_continuation); } } diff --git a/3rdparty/asio/include/asio/detail/impl/thread_context.ipp b/3rdparty/asio/include/asio/detail/impl/thread_context.ipp new file mode 100644 index 00000000000..8e729776362 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/impl/thread_context.ipp @@ -0,0 +1,35 @@ +// +// detail/impl/thread_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_THREAD_CONTEXT_IPP +#define ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +thread_info_base* thread_context::top_of_thread_call_stack() +{ + return thread_call_stack::top(); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/throw_error.ipp b/3rdparty/asio/include/asio/detail/impl/throw_error.ipp index d59eca2d8e2..7baf3e729e5 100644 --- a/3rdparty/asio/include/asio/detail/impl/throw_error.ipp +++ b/3rdparty/asio/include/asio/detail/impl/throw_error.ipp @@ -2,7 +2,7 @@ // detail/impl/throw_error.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,7 +17,6 @@ #include "asio/detail/config.hpp" #include "asio/detail/throw_error.hpp" -#include "asio/detail/throw_exception.hpp" #include "asio/system_error.hpp" #include "asio/detail/push_options.hpp" @@ -25,31 +24,21 @@ namespace asio { namespace detail { -void do_throw_error(const asio::error_code& err) +void do_throw_error( + const asio::error_code& err + ASIO_SOURCE_LOCATION_PARAM) { asio::system_error e(err); - asio::detail::throw_exception(e); + asio::detail::throw_exception(e ASIO_SOURCE_LOCATION_ARG); } -void do_throw_error(const asio::error_code& err, const char* location) +void do_throw_error( + const asio::error_code& err, + const char* location + ASIO_SOURCE_LOCATION_PARAM) { - // boostify: non-boost code starts here -#if defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) - // Microsoft's implementation of std::system_error is non-conformant in that - // it ignores the error code's message when a "what" string is supplied. We'll - // work around this by explicitly formatting the "what" string. - std::string what_msg = location; - what_msg += ": "; - what_msg += err.message(); - asio::system_error e(err, what_msg); - asio::detail::throw_exception(e); -#else // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) - // boostify: non-boost code ends here asio::system_error e(err, location); - asio::detail::throw_exception(e); - // boostify: non-boost code starts here -#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR) - // boostify: non-boost code ends here + asio::detail::throw_exception(e ASIO_SOURCE_LOCATION_ARG); } } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/impl/timer_queue_ptime.ipp b/3rdparty/asio/include/asio/detail/impl/timer_queue_ptime.ipp index 10c42956843..bdf994e3a41 100644 --- a/3rdparty/asio/include/asio/detail/impl/timer_queue_ptime.ipp +++ b/3rdparty/asio/include/asio/detail/impl/timer_queue_ptime.ipp @@ -2,7 +2,7 @@ // detail/impl/timer_queue_ptime.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -26,56 +26,62 @@ namespace asio { namespace detail { -timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue() +timer_queue<time_traits<boost::posix_time::ptime>>::timer_queue() { } -timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue() +timer_queue<time_traits<boost::posix_time::ptime>>::~timer_queue() { } -bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer( +bool timer_queue<time_traits<boost::posix_time::ptime>>::enqueue_timer( const time_type& time, per_timer_data& timer, wait_op* op) { return impl_.enqueue_timer(time, timer, op); } -bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const +bool timer_queue<time_traits<boost::posix_time::ptime>>::empty() const { return impl_.empty(); } -long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec( +long timer_queue<time_traits<boost::posix_time::ptime>>::wait_duration_msec( long max_duration) const { return impl_.wait_duration_msec(max_duration); } -long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec( +long timer_queue<time_traits<boost::posix_time::ptime>>::wait_duration_usec( long max_duration) const { return impl_.wait_duration_usec(max_duration); } -void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers( +void timer_queue<time_traits<boost::posix_time::ptime>>::get_ready_timers( op_queue<operation>& ops) { impl_.get_ready_timers(ops); } -void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers( +void timer_queue<time_traits<boost::posix_time::ptime>>::get_all_timers( op_queue<operation>& ops) { impl_.get_all_timers(ops); } -std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer( +std::size_t timer_queue<time_traits<boost::posix_time::ptime>>::cancel_timer( per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled) { return impl_.cancel_timer(timer, ops, max_cancelled); } -void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer( +void timer_queue<time_traits<boost::posix_time::ptime>>::cancel_timer_by_key( + per_timer_data* timer, op_queue<operation>& ops, void* cancellation_key) +{ + impl_.cancel_timer_by_key(timer, ops, cancellation_key); +} + +void timer_queue<time_traits<boost::posix_time::ptime>>::move_timer( per_timer_data& target, per_timer_data& source) { impl_.move_timer(target, source); diff --git a/3rdparty/asio/include/asio/detail/impl/timer_queue_set.ipp b/3rdparty/asio/include/asio/detail/impl/timer_queue_set.ipp index a6831820fdc..66420e98a7c 100644 --- a/3rdparty/asio/include/asio/detail/impl/timer_queue_set.ipp +++ b/3rdparty/asio/include/asio/detail/impl/timer_queue_set.ipp @@ -2,7 +2,7 @@ // detail/impl/timer_queue_set.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/win_event.ipp b/3rdparty/asio/include/asio/detail/impl/win_event.ipp index e3d77e68d8c..9827e339769 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_event.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_event.ipp @@ -2,7 +2,7 @@ // detail/win_event.ipp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -32,7 +32,8 @@ win_event::win_event() : state_(0) { #if defined(ASIO_WINDOWS_APP) - events_[0] = ::CreateEventExW(0, 0, CREATE_EVENT_MANUAL_RESET, 0); + events_[0] = ::CreateEventExW(0, 0, + CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); #else // defined(ASIO_WINDOWS_APP) events_[0] = ::CreateEventW(0, true, false, 0); #endif // defined(ASIO_WINDOWS_APP) @@ -45,7 +46,7 @@ win_event::win_event() } #if defined(ASIO_WINDOWS_APP) - events_[1] = ::CreateEventExW(0, 0, 0, 0); + events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS); #else // defined(ASIO_WINDOWS_APP) events_[1] = ::CreateEventW(0, false, false, 0); #endif // defined(ASIO_WINDOWS_APP) diff --git a/3rdparty/asio/include/asio/detail/impl/win_iocp_file_service.ipp b/3rdparty/asio/include/asio/detail/impl/win_iocp_file_service.ipp new file mode 100644 index 00000000000..faaab48ad52 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/impl/win_iocp_file_service.ipp @@ -0,0 +1,280 @@ +// +// detail/impl/win_iocp_file_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP +#define ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + && defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +#include <cstring> +#include <sys/stat.h> +#include "asio/detail/win_iocp_file_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +win_iocp_file_service::win_iocp_file_service( + execution_context& context) + : execution_context_service_base<win_iocp_file_service>(context), + handle_service_(context), + nt_flush_buffers_file_ex_(0) +{ + if (FARPROC nt_flush_buffers_file_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx")) + { + nt_flush_buffers_file_ex_ = reinterpret_cast<nt_flush_buffers_file_ex_fn>( + reinterpret_cast<void*>(nt_flush_buffers_file_ex_ptr)); + } +} + +void win_iocp_file_service::shutdown() +{ + handle_service_.shutdown(); +} + +asio::error_code win_iocp_file_service::open( + win_iocp_file_service::implementation_type& impl, + const char* path, file_base::flags open_flags, + asio::error_code& ec) +{ + if (is_open(impl)) + { + ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); + return ec; + } + + DWORD access = 0; + if ((open_flags & file_base::read_only) != 0) + access = GENERIC_READ; + else if ((open_flags & file_base::write_only) != 0) + access = GENERIC_WRITE; + else if ((open_flags & file_base::read_write) != 0) + access = GENERIC_READ | GENERIC_WRITE; + + DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE; + + DWORD disposition = 0; + if ((open_flags & file_base::create) != 0) + { + if ((open_flags & file_base::exclusive) != 0) + disposition = CREATE_NEW; + else + disposition = OPEN_ALWAYS; + } + else + { + if ((open_flags & file_base::truncate) != 0) + disposition = TRUNCATE_EXISTING; + else + disposition = OPEN_EXISTING; + } + + DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED; + if (impl.is_stream_) + flags |= FILE_FLAG_SEQUENTIAL_SCAN; + else + flags |= FILE_FLAG_RANDOM_ACCESS; + if ((open_flags & file_base::sync_all_on_write) != 0) + flags |= FILE_FLAG_WRITE_THROUGH; + + HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0); + if (handle != INVALID_HANDLE_VALUE) + { + if (disposition == OPEN_ALWAYS) + { + if ((open_flags & file_base::truncate) != 0) + { + if (!::SetEndOfFile(handle)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return ec; + } + } + else if ((open_flags & file_base::append) != 0) + { + if (::SetFilePointer(handle, 0, 0, FILE_END) + == INVALID_SET_FILE_POINTER) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return ec; + } + } + } + + handle_service_.assign(impl, handle, ec); + if (ec) + ::CloseHandle(handle); + impl.offset_ = 0; + ASIO_ERROR_LOCATION(ec); + return ec; + } + else + { + DWORD last_error = ::GetLastError(); + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return ec; + } +} + +uint64_t win_iocp_file_service::size( + const win_iocp_file_service::implementation_type& impl, + asio::error_code& ec) const +{ + LARGE_INTEGER result; + if (::GetFileSizeEx(native_handle(impl), &result)) + { + asio::error::clear(ec); + return static_cast<uint64_t>(result.QuadPart); + } + else + { + DWORD last_error = ::GetLastError(); + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return 0; + } +} + +asio::error_code win_iocp_file_service::resize( + win_iocp_file_service::implementation_type& impl, + uint64_t n, asio::error_code& ec) +{ + LARGE_INTEGER distance; + distance.QuadPart = n; + if (::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN)) + { + BOOL result = ::SetEndOfFile(native_handle(impl)); + DWORD last_error = ::GetLastError(); + + distance.QuadPart = static_cast<LONGLONG>(impl.offset_); + if (!::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN)) + { + result = FALSE; + last_error = ::GetLastError(); + } + + if (result) + asio::error::clear(ec); + else + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return ec; + } + else + { + DWORD last_error = ::GetLastError(); + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return ec; + } +} + +asio::error_code win_iocp_file_service::sync_all( + win_iocp_file_service::implementation_type& impl, + asio::error_code& ec) +{ + BOOL result = ::FlushFileBuffers(native_handle(impl)); + if (result) + { + asio::error::clear(ec); + return ec; + } + else + { + DWORD last_error = ::GetLastError(); + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return ec; + } +} + +asio::error_code win_iocp_file_service::sync_data( + win_iocp_file_service::implementation_type& impl, + asio::error_code& ec) +{ + if (nt_flush_buffers_file_ex_) + { + io_status_block status = {}; + if (!nt_flush_buffers_file_ex_(native_handle(impl), + flush_flags_file_data_sync_only, 0, 0, &status)) + { + asio::error::clear(ec); + return ec; + } + } + return sync_all(impl, ec); +} + +uint64_t win_iocp_file_service::seek( + win_iocp_file_service::implementation_type& impl, int64_t offset, + file_base::seek_basis whence, asio::error_code& ec) +{ + DWORD method; + switch (whence) + { + case file_base::seek_set: + method = FILE_BEGIN; + break; + case file_base::seek_cur: + method = FILE_BEGIN; + offset = static_cast<int64_t>(impl.offset_) + offset; + break; + case file_base::seek_end: + method = FILE_END; + break; + default: + ec = asio::error::invalid_argument; + ASIO_ERROR_LOCATION(ec); + return 0; + } + + LARGE_INTEGER distance, new_offset; + distance.QuadPart = offset; + if (::SetFilePointerEx(native_handle(impl), distance, &new_offset, method)) + { + impl.offset_ = new_offset.QuadPart; + asio::error::clear(ec); + return impl.offset_; + } + else + { + DWORD last_error = ::GetLastError(); + ec.assign(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); + return 0; + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_FILE) + // && defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +#endif // ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP diff --git a/3rdparty/asio/include/asio/detail/impl/win_iocp_handle_service.ipp b/3rdparty/asio/include/asio/detail/impl/win_iocp_handle_service.ipp index 7e6fcb9015c..6136e27fb32 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_iocp_handle_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_iocp_handle_service.ipp @@ -2,7 +2,7 @@ // detail/impl/win_iocp_handle_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -65,10 +65,10 @@ public: } }; -win_iocp_handle_service::win_iocp_handle_service( - asio::io_context& io_context) - : service_base<win_iocp_handle_service>(io_context), - iocp_service_(asio::use_service<win_iocp_io_context>(io_context)), +win_iocp_handle_service::win_iocp_handle_service(execution_context& context) + : execution_context_service_base<win_iocp_handle_service>(context), + iocp_service_(asio::use_service<win_iocp_io_context>(context)), + nt_set_info_(0), mutex_(), impl_list_(0) { @@ -183,11 +183,15 @@ asio::error_code win_iocp_handle_service::assign( if (is_open(impl)) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } if (iocp_service_.register_handle(handle, ec)) + { + ASIO_ERROR_LOCATION(ec); return ec; + } impl.handle_ = handle; ec = asio::error_code(); @@ -222,9 +226,47 @@ asio::error_code win_iocp_handle_service::close( ec = asio::error_code(); } + ASIO_ERROR_LOCATION(ec); return ec; } +win_iocp_handle_service::native_handle_type win_iocp_handle_service::release( + win_iocp_handle_service::implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return INVALID_HANDLE_VALUE; + + cancel(impl, ec); + if (ec) + { + ASIO_ERROR_LOCATION(ec); + return INVALID_HANDLE_VALUE; + } + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = asio::error::operation_not_supported; + ASIO_ERROR_LOCATION(ec); + return INVALID_HANDLE_VALUE; + } + + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(impl.handle_, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = asio::error::operation_not_supported; + ASIO_ERROR_LOCATION(ec); + return INVALID_HANDLE_VALUE; + } + + native_handle_type tmp = impl.handle_; + impl.handle_ = INVALID_HANDLE_VALUE; + return tmp; +} + asio::error_code win_iocp_handle_service::cancel( win_iocp_handle_service::implementation_type& impl, asio::error_code& ec) @@ -232,6 +274,7 @@ asio::error_code win_iocp_handle_service::cancel( if (!is_open(impl)) { ec = asio::error::bad_descriptor; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -243,7 +286,8 @@ asio::error_code win_iocp_handle_service::cancel( { // The version of Windows supports cancellation from any thread. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); - cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>( + reinterpret_cast<void*>(cancel_io_ex_ptr)); if (!cancel_io_ex(impl.handle_, 0)) { DWORD last_error = ::GetLastError(); @@ -292,6 +336,7 @@ asio::error_code win_iocp_handle_service::cancel( ec = asio::error::operation_not_supported; } + ASIO_ERROR_LOCATION(ec); return ec; } @@ -302,6 +347,7 @@ size_t win_iocp_handle_service::do_write( if (!is_open(impl)) { ec = asio::error::bad_descriptor; + ASIO_ERROR_LOCATION(ec); return 0; } @@ -315,6 +361,7 @@ size_t win_iocp_handle_service::do_write( overlapped_wrapper overlapped(ec); if (ec) { + ASIO_ERROR_LOCATION(ec); return 0; } @@ -330,6 +377,7 @@ size_t win_iocp_handle_service::do_write( { ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return 0; } } @@ -343,6 +391,7 @@ size_t win_iocp_handle_service::do_write( DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return 0; } @@ -394,6 +443,7 @@ size_t win_iocp_handle_service::do_read( if (!is_open(impl)) { ec = asio::error::bad_descriptor; + ASIO_ERROR_LOCATION(ec); return 0; } @@ -407,6 +457,7 @@ size_t win_iocp_handle_service::do_read( overlapped_wrapper overlapped(ec); if (ec) { + ASIO_ERROR_LOCATION(ec); return 0; } @@ -429,6 +480,7 @@ size_t win_iocp_handle_service::do_read( ec = asio::error_code(last_error, asio::error::get_system_category()); } + ASIO_ERROR_LOCATION(ec); return 0; } } @@ -449,6 +501,7 @@ size_t win_iocp_handle_service::do_read( ec = asio::error_code(last_error, asio::error::get_system_category()); } + ASIO_ERROR_LOCATION(ec); return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0; } @@ -515,6 +568,47 @@ void win_iocp_handle_service::close_for_destruction(implementation_type& impl) } } +win_iocp_handle_service::nt_set_info_fn +win_iocp_handle_service::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr); +} + +void* win_iocp_handle_service::interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp) +{ +#if defined(_M_IX86) + return reinterpret_cast<void*>(InterlockedCompareExchange( + reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch), + reinterpret_cast<LONG>(cmp))); +#else + return InterlockedCompareExchangePointer(dest, exch, cmp); +#endif +} + +void* win_iocp_handle_service::interlocked_exchange_pointer( + void** dest, void* val) +{ +#if defined(_M_IX86) + return reinterpret_cast<void*>(InterlockedExchange( + reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val))); +#else + return InterlockedExchangePointer(dest, val); +#endif +} + } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.hpp b/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.hpp index 4d1d75a9187..6479500184a 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.hpp +++ b/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.hpp @@ -2,7 +2,7 @@ // detail/impl/win_iocp_io_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,7 +22,6 @@ #include "asio/detail/completion_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/push_options.hpp" @@ -76,11 +75,28 @@ std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue, mutex::scoped_lock lock(dispatch_mutex_); op_queue<win_iocp_operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); post_deferred_completions(ops); return n; } template <typename Time_Traits> +void win_iocp_io_context::cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key) +{ + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return; + + mutex::scoped_lock lock(dispatch_mutex_); + op_queue<win_iocp_operation> ops; + queue.cancel_timer_by_key(timer, ops, cancellation_key); + lock.unlock(); + post_deferred_completions(ops); +} + +template <typename Time_Traits> void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& to, typename timer_queue<Time_Traits>::per_timer_data& from) diff --git a/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.ipp b/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.ipp index d4a16381d8d..1c7fb28b2d6 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_iocp_io_context.ipp @@ -2,7 +2,7 @@ // detail/impl/win_iocp_io_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,8 +22,8 @@ #include "asio/error.hpp" #include "asio/detail/cstdint.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/limits.hpp" +#include "asio/detail/thread.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/win_iocp_io_context.hpp" @@ -32,9 +32,25 @@ namespace asio { namespace detail { +struct win_iocp_io_context::thread_function +{ + explicit thread_function(win_iocp_io_context* s) + : this_(s) + { + } + + void operator()() + { + asio::error_code ec; + this_->run(ec); + } + + win_iocp_io_context* this_; +}; + struct win_iocp_io_context::work_finished_on_block_exit { - ~work_finished_on_block_exit() + ~work_finished_on_block_exit() noexcept(false) { io_context_->work_finished(); } @@ -62,7 +78,7 @@ struct win_iocp_io_context::timer_thread_function }; win_iocp_io_context::win_iocp_io_context( - asio::execution_context& ctx, int concurrency_hint) + asio::execution_context& ctx, int concurrency_hint, bool own_thread) : execution_context_service_base<win_iocp_io_context>(ctx), iocp_(), outstanding_work_(0), @@ -84,6 +100,22 @@ win_iocp_io_context::win_iocp_io_context( asio::error::get_system_category()); asio::detail::throw_error(ec, "iocp"); } + + if (own_thread) + { + ::InterlockedIncrement(&outstanding_work_); + thread_.reset(new asio::detail::thread(thread_function(this))); + } +} + +win_iocp_io_context::~win_iocp_io_context() +{ + if (thread_.get()) + { + stop(); + thread_->join(); + thread_.reset(); + } } void win_iocp_io_context::shutdown() @@ -97,6 +129,14 @@ void win_iocp_io_context::shutdown() ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); } + if (thread_.get()) + { + stop(); + thread_->join(); + thread_.reset(); + ::InterlockedDecrement(&outstanding_work_); + } + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) { op_queue<win_iocp_operation> ops; @@ -127,7 +167,10 @@ void win_iocp_io_context::shutdown() } if (timer_thread_.get()) + { timer_thread_->join(); + timer_thread_.reset(); + } } asio::error_code win_iocp_io_context::register_handle( @@ -159,7 +202,7 @@ size_t win_iocp_io_context::run(asio::error_code& ec) thread_call_stack::context ctx(this, this_thread); size_t n = 0; - while (do_one(INFINITE, ec)) + while (do_one(INFINITE, this_thread, ec)) if (n != (std::numeric_limits<size_t>::max)()) ++n; return n; @@ -177,7 +220,7 @@ size_t win_iocp_io_context::run_one(asio::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(INFINITE, ec); + return do_one(INFINITE, this_thread, ec); } size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec) @@ -192,7 +235,7 @@ size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec); + return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec); } size_t win_iocp_io_context::poll(asio::error_code& ec) @@ -208,7 +251,7 @@ size_t win_iocp_io_context::poll(asio::error_code& ec) thread_call_stack::context ctx(this, this_thread); size_t n = 0; - while (do_one(0, ec)) + while (do_one(0, this_thread, ec)) if (n != (std::numeric_limits<size_t>::max)()) ++n; return n; @@ -226,7 +269,7 @@ size_t win_iocp_io_context::poll_one(asio::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(0, ec); + return do_one(0, this_thread, ec); } void win_iocp_io_context::stop() @@ -246,6 +289,17 @@ void win_iocp_io_context::stop() } } +bool win_iocp_io_context::can_dispatch() +{ + return thread_call_stack::contains(this) != 0; +} + +void win_iocp_io_context::capture_current_exception() +{ + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + this_thread->capture_current_exception(); +} + void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op) { // Flag the operation as ready. @@ -355,7 +409,8 @@ void win_iocp_io_context::on_completion(win_iocp_operation* op, } } -size_t win_iocp_io_context::do_one(DWORD msec, asio::error_code& ec) +size_t win_iocp_io_context::do_one(DWORD msec, + win_iocp_thread_info& this_thread, asio::error_code& ec) { for (;;) { @@ -417,6 +472,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, asio::error_code& ec) (void)on_exit; op->complete(this, result_ec, bytes_transferred); + this_thread.rethrow_pending_exception(); ec = asio::error_code(); return 1; } @@ -473,6 +529,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, asio::error_code& ec) DWORD win_iocp_io_context::get_gqcs_timeout() { +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(osvi); @@ -485,6 +542,9 @@ DWORD win_iocp_io_context::get_gqcs_timeout() return INFINITE; return default_gqcs_timeout; +#else // !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) + return INFINITE; +#endif // !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) } void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue) diff --git a/3rdparty/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp b/3rdparty/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp index d84f4b2130b..abeb3cecb0a 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -2,7 +2,7 @@ // detail/impl/win_iocp_serial_port_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -29,9 +29,9 @@ namespace asio { namespace detail { win_iocp_serial_port_service::win_iocp_serial_port_service( - asio::io_context& io_context) - : service_base<win_iocp_serial_port_service>(io_context), - handle_service_(io_context) + execution_context& context) + : execution_context_service_base<win_iocp_serial_port_service>(context), + handle_service_(context) { } @@ -46,6 +46,7 @@ asio::error_code win_iocp_serial_port_service::open( if (is_open(impl)) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -61,6 +62,7 @@ asio::error_code win_iocp_serial_port_service::open( DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -75,21 +77,34 @@ asio::error_code win_iocp_serial_port_service::open( ::CloseHandle(handle); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } // Set some default serial port parameters. This implementation does not - // support changing these, so they might as well be in a known state. + // support changing all of these, so they might as well be in a known state. dcb.fBinary = TRUE; // Win32 only supports binary mode. - dcb.fDsrSensitivity = FALSE; dcb.fNull = FALSE; // Do not ignore NULL characters. dcb.fAbortOnError = FALSE; // Ignore serial framing errors. + dcb.BaudRate = CBR_9600; // 9600 baud by default + dcb.ByteSize = 8; // 8 bit bytes + dcb.fOutxCtsFlow = FALSE; // No flow control + dcb.fOutxDsrFlow = FALSE; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fDsrSensitivity = FALSE; + dcb.fOutX = FALSE; + dcb.fInX = FALSE; + dcb.fRtsControl = RTS_CONTROL_DISABLE; + dcb.fParity = FALSE; // No parity + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; // One stop bit if (!::SetCommState(handle, &dcb)) { DWORD last_error = ::GetLastError(); ::CloseHandle(handle); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -108,6 +123,7 @@ asio::error_code win_iocp_serial_port_service::open( ::CloseHandle(handle); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -132,6 +148,7 @@ asio::error_code win_iocp_serial_port_service::do_set_option( DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -143,6 +160,7 @@ asio::error_code win_iocp_serial_port_service::do_set_option( DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -165,6 +183,7 @@ asio::error_code win_iocp_serial_port_service::do_get_option( DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); return ec; } diff --git a/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp b/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp index 4230f5c586a..af28718c905 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -2,7 +2,7 @@ // detail/impl/win_iocp_socket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -27,11 +27,12 @@ namespace asio { namespace detail { win_iocp_socket_service_base::win_iocp_socket_service_base( - asio::io_context& io_context) - : io_context_(io_context), - iocp_service_(use_service<win_iocp_io_context>(io_context)), + execution_context& context) + : context_(context), + iocp_service_(use_service<win_iocp_io_context>(context)), reactor_(0), connect_ex_(0), + nt_set_info_(0), mutex_(), impl_list_(0) { @@ -44,7 +45,6 @@ void win_iocp_socket_service_base::base_shutdown() base_implementation_type* impl = impl_list_; while (impl) { - asio::error_code ignored_ec; close_for_destruction(*impl); impl = impl->next_; } @@ -72,6 +72,7 @@ void win_iocp_socket_service_base::construct( void win_iocp_socket_service_base::base_move_construct( win_iocp_socket_service_base::base_implementation_type& impl, win_iocp_socket_service_base::base_implementation_type& other_impl) + noexcept { impl.socket_ = other_impl.socket_; other_impl.socket_ = invalid_socket; @@ -177,9 +178,16 @@ asio::error_code win_iocp_socket_service_base::close( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); - } - socket_ops::close(impl.socket_, impl.state_, false, ec); + socket_ops::close(impl.socket_, impl.state_, false, ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } impl.socket_ = invalid_socket; impl.state_ = 0; @@ -191,6 +199,39 @@ asio::error_code win_iocp_socket_service_base::close( return ec; } +socket_type win_iocp_socket_service_base::release( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return invalid_socket; + + cancel(impl, ec); + if (ec) + return invalid_socket; + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_); + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(sock_as_handle, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + socket_type tmp = impl.socket_; + impl.socket_ = invalid_socket; + return tmp; +} + asio::error_code win_iocp_socket_service_base::cancel( win_iocp_socket_service_base::base_implementation_type& impl, asio::error_code& ec) @@ -209,7 +250,8 @@ asio::error_code win_iocp_socket_service_base::cancel( { // The version of Windows supports cancellation from any thread. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); - cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>( + reinterpret_cast<void*>(cancel_io_ex_ptr)); socket_type sock = impl.socket_; HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); if (!cancel_io_ex(sock_as_handle, 0)) @@ -368,9 +410,8 @@ void win_iocp_socket_service_base::start_send_op( void win_iocp_socket_service_base::start_send_to_op( win_iocp_socket_service_base::base_implementation_type& impl, - WSABUF* buffers, std::size_t buffer_count, - const socket_addr_type* addr, int addrlen, - socket_base::message_flags flags, operation* op) + WSABUF* buffers, std::size_t buffer_count, const void* addr, + int addrlen, socket_base::message_flags flags, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); @@ -381,8 +422,8 @@ void win_iocp_socket_service_base::start_send_to_op( { DWORD bytes_transferred = 0; int result = ::WSASendTo(impl.socket_, buffers, - static_cast<DWORD>(buffer_count), - &bytes_transferred, flags, addr, addrlen, op, 0); + static_cast<DWORD>(buffer_count), &bytes_transferred, flags, + static_cast<const socket_addr_type*>(addr), addrlen, op, 0); DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; @@ -424,29 +465,30 @@ void win_iocp_socket_service_base::start_receive_op( } } -void win_iocp_socket_service_base::start_null_buffers_receive_op( +int win_iocp_socket_service_base::start_null_buffers_receive_op( win_iocp_socket_service_base::base_implementation_type& impl, - socket_base::message_flags flags, reactor_op* op) + socket_base::message_flags flags, reactor_op* op, operation* iocp_op) { if ((impl.state_ & socket_ops::stream_oriented) != 0) { // For stream sockets on Windows, we may issue a 0-byte overlapped // WSARecv to wait until there is data available on the socket. ::WSABUF buf = { 0, 0 }; - start_receive_op(impl, &buf, 1, flags, false, op); + start_receive_op(impl, &buf, 1, flags, false, iocp_op); + return -1; } else { - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? select_reactor::except_op : select_reactor::read_op, - op); + int op_type = (flags & socket_base::message_out_of_band) + ? select_reactor::except_op : select_reactor::read_op; + start_reactor_op(impl, op_type, op); + return op_type; } } void win_iocp_socket_service_base::start_receive_from_op( win_iocp_socket_service_base::base_implementation_type& impl, - WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + WSABUF* buffers, std::size_t buffer_count, void* addr, socket_base::message_flags flags, int* addrlen, operation* op) { update_cancellation_thread_id(impl); @@ -459,8 +501,8 @@ void win_iocp_socket_service_base::start_receive_from_op( DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecvFrom(impl.socket_, buffers, - static_cast<DWORD>(buffer_count), - &bytes_transferred, &recv_flags, addr, addrlen, op, 0); + static_cast<DWORD>(buffer_count), &bytes_transferred, &recv_flags, + static_cast<socket_addr_type*>(addr), addrlen, op, 0); DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; @@ -505,11 +547,17 @@ void win_iocp_socket_service_base::start_accept_op( void win_iocp_socket_service_base::restart_accept_op( socket_type s, socket_holder& new_socket, int family, int type, - int protocol, void* output_buffer, DWORD address_length, operation* op) + int protocol, void* output_buffer, DWORD address_length, + long* cancel_requested, operation* op) { new_socket.reset(); iocp_service_.work_started(); + // Check if we were cancelled after the first AcceptEx completed. + if (cancel_requested) + if (::InterlockedExchangeAdd(cancel_requested, 0) == 1) + iocp_service_.on_completion(op, asio::error::operation_aborted); + asio::error_code ec; new_socket.reset(socket_ops::socket(family, type, protocol, ec)); if (new_socket.get() == invalid_socket) @@ -523,7 +571,19 @@ void win_iocp_socket_service_base::restart_accept_op( if (!result && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error); else + { +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + if (cancel_requested) + { + if (::InterlockedExchangeAdd(cancel_requested, 0) == 1) + { + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(s); + ::CancelIoEx(sock_as_handle, op); + } + } +#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) iocp_service_.on_pending(op); + } } } @@ -545,10 +605,10 @@ void win_iocp_socket_service_base::start_reactor_op( iocp_service_.post_immediate_completion(op, false); } -void win_iocp_socket_service_base::start_connect_op( +int win_iocp_socket_service_base::start_connect_op( win_iocp_socket_service_base::base_implementation_type& impl, - int family, int type, const socket_addr_type* addr, - std::size_t addrlen, win_iocp_socket_connect_op_base* op) + int family, int type, const void* addr, std::size_t addrlen, + win_iocp_socket_connect_op_base* op, operation* iocp_op) { // If ConnectEx is available, use that. if (family == ASIO_OS_DEF(AF_INET) @@ -573,7 +633,7 @@ void win_iocp_socket_service_base::start_connect_op( if (op->ec_ && op->ec_ != asio::error::invalid_argument) { iocp_service_.post_immediate_completion(op, false); - return; + return -1; } op->connect_ex_ = true; @@ -581,13 +641,14 @@ void win_iocp_socket_service_base::start_connect_op( iocp_service_.work_started(); BOOL result = connect_ex(impl.socket_, - addr, static_cast<int>(addrlen), 0, 0, 0, op); + static_cast<const socket_addr_type*>(addr), + static_cast<int>(addrlen), 0, 0, 0, iocp_op); DWORD last_error = ::WSAGetLastError(); if (!result && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error); + iocp_service_.on_completion(iocp_op, last_error); else - iocp_service_.on_pending(op); - return; + iocp_service_.on_pending(iocp_op); + return -1; } } @@ -607,12 +668,13 @@ void win_iocp_socket_service_base::start_connect_op( op->ec_ = asio::error_code(); r.start_op(select_reactor::connect_op, impl.socket_, impl.reactor_data_, op, false, false); - return; + return select_reactor::connect_op; } } } r.post_immediate_completion(op, false); + return -1; } void win_iocp_socket_service_base::close_for_destruction( @@ -631,10 +693,14 @@ void win_iocp_socket_service_base::close_for_destruction( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); } - asio::error_code ignored_ec; - socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); impl.socket_ = invalid_socket; impl.state_ = 0; impl.cancel_token_.reset(); @@ -663,7 +729,7 @@ select_reactor& win_iocp_socket_service_base::get_reactor() reinterpret_cast<void**>(&reactor_), 0, 0)); if (!r) { - r = &(use_service<select_reactor>(io_context_)); + r = &(use_service<select_reactor>(context_)); interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r); } return *r; @@ -704,6 +770,24 @@ win_iocp_socket_service_base::get_connect_ex( #endif // defined(ASIO_DISABLE_CONNECTEX) } +win_iocp_socket_service_base::nt_set_info_fn +win_iocp_socket_service_base::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr); +} + void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( void** dest, void* exch, void* cmp) { diff --git a/3rdparty/asio/include/asio/detail/impl/win_mutex.ipp b/3rdparty/asio/include/asio/detail/impl/win_mutex.ipp index 2e14c4aef2e..6340b6e1256 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_mutex.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_mutex.ipp @@ -2,7 +2,7 @@ // detail/impl/win_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -44,7 +44,7 @@ int win_mutex::do_init() # if defined(UNDER_CE) ::InitializeCriticalSection(&crit_section_); # elif defined(ASIO_WINDOWS_APP) - if (!::InitializeCriticalSectionEx(&crit_section_, 0xFFFFFF, 0)) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) return ::GetLastError(); # else if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) @@ -57,8 +57,8 @@ int win_mutex::do_init() # if defined(UNDER_CE) ::InitializeCriticalSection(&crit_section_); # elif defined(ASIO_WINDOWS_APP) - if (!::InitializeCriticalSectionEx(&crit_section_, 0xFFFFFF, 0)) - return ::GetLastError(); + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + return ::GetLastError(); # else if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) return ::GetLastError(); diff --git a/3rdparty/asio/include/asio/detail/impl/win_object_handle_service.ipp b/3rdparty/asio/include/asio/detail/impl/win_object_handle_service.ipp index 9b3da7f0959..d7db3e3f3a1 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_object_handle_service.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_object_handle_service.ipp @@ -2,7 +2,7 @@ // detail/impl/win_object_handle_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2011 Boris Schaeling (boris@highscore.de) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -27,10 +27,9 @@ namespace asio { namespace detail { -win_object_handle_service::win_object_handle_service( - asio::io_context& io_context) - : service_base<win_object_handle_service>(io_context), - io_context_(asio::use_service<io_context_impl>(io_context)), +win_object_handle_service::win_object_handle_service(execution_context& context) + : execution_context_service_base<win_object_handle_service>(context), + scheduler_(asio::use_service<scheduler_impl>(context)), mutex_(), impl_list_(0), shutdown_(false) @@ -52,7 +51,7 @@ void win_object_handle_service::shutdown() lock.unlock(); - io_context_.abandon_operations(ops); + scheduler_.abandon_operations(ops); } void win_object_handle_service::construct( @@ -178,7 +177,7 @@ void win_object_handle_service::destroy( if (is_open(impl)) { - ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close")); HANDLE wait_handle = impl.wait_handle_; @@ -203,7 +202,7 @@ void win_object_handle_service::destroy( ::CloseHandle(impl.handle_); impl.handle_ = INVALID_HANDLE_VALUE; - io_context_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); } } @@ -214,6 +213,7 @@ asio::error_code win_object_handle_service::assign( if (is_open(impl)) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -228,7 +228,7 @@ asio::error_code win_object_handle_service::close( { if (is_open(impl)) { - ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close")); mutex::scoped_lock lock(mutex_); @@ -264,13 +264,14 @@ asio::error_code win_object_handle_service::close( asio::error::get_system_category()); } - io_context_.post_deferred_completions(completed_ops); + scheduler_.post_deferred_completions(completed_ops); } else { ec = asio::error_code(); } + ASIO_ERROR_LOCATION(ec); return ec; } @@ -280,7 +281,7 @@ asio::error_code win_object_handle_service::cancel( { if (is_open(impl)) { - ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel")); mutex::scoped_lock lock(mutex_); @@ -306,13 +307,14 @@ asio::error_code win_object_handle_service::cancel( ec = asio::error_code(); - io_context_.post_deferred_completions(completed_ops); + scheduler_.post_deferred_completions(completed_ops); } else { ec = asio::error::bad_descriptor; } + ASIO_ERROR_LOCATION(ec); return ec; } @@ -327,6 +329,7 @@ void win_object_handle_service::wait( DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); + ASIO_ERROR_LOCATION(ec); break; } case WAIT_OBJECT_0: @@ -340,7 +343,7 @@ void win_object_handle_service::wait( void win_object_handle_service::start_wait_op( win_object_handle_service::implementation_type& impl, wait_op* op) { - io_context_.work_started(); + scheduler_.work_started(); if (is_open(impl)) { @@ -358,13 +361,13 @@ void win_object_handle_service::start_wait_op( else { lock.unlock(); - io_context_.post_deferred_completion(op); + scheduler_.post_deferred_completion(op); } } else { op->ec_ = asio::error::bad_descriptor; - io_context_.post_deferred_completion(op); + scheduler_.post_deferred_completion(op); } } @@ -391,7 +394,7 @@ void win_object_handle_service::register_wait_callback( } lock.unlock(); - io_context_.post_deferred_completions(completed_ops); + scheduler_.post_deferred_completions(completed_ops); } } @@ -433,9 +436,9 @@ void win_object_handle_service::wait_callback(PVOID param, BOOLEAN) } } - io_context_impl& ioc = impl->owner_->io_context_; + scheduler_impl& sched = impl->owner_->scheduler_; lock.unlock(); - ioc.post_deferred_completions(completed_ops); + sched.post_deferred_completions(completed_ops); } } diff --git a/3rdparty/asio/include/asio/detail/impl/win_static_mutex.ipp b/3rdparty/asio/include/asio/detail/impl/win_static_mutex.ipp index 359752dc266..5b459843338 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_static_mutex.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_static_mutex.ipp @@ -2,7 +2,7 @@ // detail/impl/win_static_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -94,7 +94,13 @@ int win_static_mutex::do_init() # if defined(UNDER_CE) ::InitializeCriticalSection(&crit_section_); # elif defined(ASIO_WINDOWS_APP) - ::InitializeCriticalSectionEx(&crit_section_, 0x80000000, 0); + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } # else if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) { diff --git a/3rdparty/asio/include/asio/detail/impl/win_thread.ipp b/3rdparty/asio/include/asio/detail/impl/win_thread.ipp index 4269e6b8b77..0ebc5db86b4 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_thread.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_thread.ipp @@ -2,7 +2,7 @@ // detail/impl/win_thread.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/impl/win_tss_ptr.ipp b/3rdparty/asio/include/asio/detail/impl/win_tss_ptr.ipp index 75a436c942f..5bc9de2c308 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_tss_ptr.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_tss_ptr.ipp @@ -2,7 +2,7 @@ // detail/impl/win_tss_ptr.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -31,9 +31,9 @@ namespace detail { DWORD win_tss_ptr_create() { #if defined(UNDER_CE) - enum { out_of_indexes = 0xFFFFFFFF }; + const DWORD out_of_indexes = 0xFFFFFFFF; #else - enum { out_of_indexes = TLS_OUT_OF_INDEXES }; + const DWORD out_of_indexes = TLS_OUT_OF_INDEXES; #endif DWORD tss_key = ::TlsAlloc(); diff --git a/3rdparty/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp b/3rdparty/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp index f3d74cf0bd5..90a03542a9c 100644 --- a/3rdparty/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp +++ b/3rdparty/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp @@ -2,7 +2,7 @@ // detail/impl/winrt_ssocket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,9 +30,9 @@ namespace asio { namespace detail { winrt_ssocket_service_base::winrt_ssocket_service_base( - asio::io_context& io_context) - : io_context_(use_service<io_context_impl>(io_context)), - async_manager_(use_service<winrt_async_manager>(io_context)), + execution_context& context) + : scheduler_(use_service<scheduler_impl>(context)), + async_manager_(use_service<winrt_async_manager>(context)), mutex_(), impl_list_(0) { @@ -66,6 +66,7 @@ void winrt_ssocket_service_base::construct( void winrt_ssocket_service_base::base_move_construct( winrt_ssocket_service_base::base_implementation_type& impl, winrt_ssocket_service_base::base_implementation_type& other_impl) + noexcept { impl.socket_ = other_impl.socket_; other_impl.socket_ = nullptr; @@ -138,16 +139,29 @@ asio::error_code winrt_ssocket_service_base::close( winrt_ssocket_service_base::base_implementation_type& impl, asio::error_code& ec) { - if (impl.socket_) - { - delete impl.socket_; - impl.socket_ = nullptr; - } - + delete impl.socket_; + impl.socket_ = nullptr; ec = asio::error_code(); return ec; } +winrt_ssocket_service_base::native_handle_type +winrt_ssocket_service_base::release( + winrt_ssocket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return nullptr; + + cancel(impl, ec); + if (ec) + return nullptr; + + native_handle_type tmp = impl.socket_; + impl.socket_ = nullptr; + return tmp; +} + std::size_t winrt_ssocket_service_base::do_get_endpoint( const base_implementation_type& impl, bool local, void* addr, std::size_t addr_len, asio::error_code& ec) const @@ -168,7 +182,7 @@ std::size_t winrt_ssocket_service_base::do_get_endpoint( : impl.socket_->Information->RemotePort); unsigned long scope = 0; - switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) + switch (static_cast<const socket_addr_type*>(addr)->sa_family) { case ASIO_OS_DEF(AF_INET): if (addr_len < sizeof(sockaddr_in4_type)) @@ -337,7 +351,7 @@ asio::error_code winrt_ssocket_service_base::do_connect( char addr_string[max_addr_v6_str_len]; unsigned short port; - switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) + switch (static_cast<const socket_addr_type*>(addr)->sa_family) { case ASIO_OS_DEF(AF_INET): socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET), @@ -381,13 +395,13 @@ void winrt_ssocket_service_base::start_connect_op( if (!is_open(impl)) { op->ec_ = asio::error::bad_descriptor; - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } char addr_string[max_addr_v6_str_len]; unsigned short port = 0; - switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) + switch (static_cast<const socket_addr_type*>(addr)->sa_family) { case ASIO_OS_DEF(AF_INET): socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET), @@ -410,7 +424,7 @@ void winrt_ssocket_service_base::start_connect_op( if (op->ec_) { - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } @@ -425,7 +439,7 @@ void winrt_ssocket_service_base::start_connect_op( { op->ec_ = asio::error_code( e->HResult, asio::system_category()); - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); } } @@ -476,14 +490,14 @@ void winrt_ssocket_service_base::start_send_op( if (flags) { op->ec_ = asio::error::operation_not_supported; - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } if (!is_open(impl)) { op->ec_ = asio::error::bad_descriptor; - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } @@ -494,7 +508,7 @@ void winrt_ssocket_service_base::start_send_op( if (bufs.all_empty()) { - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } @@ -505,7 +519,7 @@ void winrt_ssocket_service_base::start_send_op( { op->ec_ = asio::error_code(e->HResult, asio::system_category()); - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); } } @@ -567,14 +581,14 @@ void winrt_ssocket_service_base::start_receive_op( if (flags) { op->ec_ = asio::error::operation_not_supported; - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } if (!is_open(impl)) { op->ec_ = asio::error::bad_descriptor; - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } @@ -585,7 +599,7 @@ void winrt_ssocket_service_base::start_receive_op( if (bufs.all_empty()) { - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } @@ -598,7 +612,7 @@ void winrt_ssocket_service_base::start_receive_op( { op->ec_ = asio::error_code(e->HResult, asio::system_category()); - io_context_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); } } diff --git a/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp b/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp index e8447316d29..9c967508e4f 100644 --- a/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp +++ b/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp @@ -2,7 +2,7 @@ // detail/impl/winrt_timer_scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -46,12 +46,12 @@ void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue, if (shutdown_) { - io_context_.post_immediate_completion(op, false); + scheduler_.post_immediate_completion(op, false); return; } bool earliest = queue.enqueue_timer(time, timer, op); - io_context_.work_started(); + scheduler_.work_started(); if (earliest) event_.signal(lock); } @@ -65,7 +65,7 @@ std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue, op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); - io_context_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); return n; } diff --git a/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp b/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp index 2bc92b764b0..028b5f9f3cb 100644 --- a/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp +++ b/3rdparty/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp @@ -2,7 +2,7 @@ // detail/impl/winrt_timer_scheduler.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -27,10 +27,9 @@ namespace asio { namespace detail { -winrt_timer_scheduler::winrt_timer_scheduler( - asio::io_context& io_context) - : asio::detail::service_base<winrt_timer_scheduler>(io_context), - io_context_(use_service<io_context_impl>(io_context)), +winrt_timer_scheduler::winrt_timer_scheduler(execution_context& context) + : execution_context_service_base<winrt_timer_scheduler>(context), + scheduler_(use_service<scheduler_impl>(context)), mutex_(), event_(), timer_queues_(), @@ -64,10 +63,10 @@ void winrt_timer_scheduler::shutdown() op_queue<operation> ops; timer_queues_.get_all_timers(ops); - io_context_.abandon_operations(ops); + scheduler_.abandon_operations(ops); } -void winrt_timer_scheduler::notify_fork(asio::io_context::fork_event) +void winrt_timer_scheduler::notify_fork(execution_context::fork_event) { } @@ -89,7 +88,7 @@ void winrt_timer_scheduler::run_thread() if (!ops.empty()) { lock.unlock(); - io_context_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); lock.lock(); } } diff --git a/3rdparty/asio/include/asio/detail/impl/winsock_init.ipp b/3rdparty/asio/include/asio/detail/impl/winsock_init.ipp index 094b58bdc54..5b5f56037ea 100644 --- a/3rdparty/asio/include/asio/detail/impl/winsock_init.ipp +++ b/3rdparty/asio/include/asio/detail/impl/winsock_init.ipp @@ -2,7 +2,7 @@ // detail/impl/winsock_init.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/initiate_defer.hpp b/3rdparty/asio/include/asio/detail/initiate_defer.hpp new file mode 100644 index 00000000000..92abb0aa2f0 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/initiate_defer.hpp @@ -0,0 +1,207 @@ +// +// detail/initiate_defer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_INITIATE_DEFER_HPP +#define ASIO_DETAIL_INITIATE_DEFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/work_dispatcher.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/relationship.hpp" +#include "asio/prefer.hpp" +#include "asio/require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class initiate_defer +{ +public: + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + associated_executor_t<decay_t<CompletionHandler>> + >::value + >* = 0) const + { + associated_executor_t<decay_t<CompletionHandler>> ex( + (get_associated_executor)(handler)); + + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + asio::prefer( + asio::require(ex, execution::blocking.never), + execution::relationship.continuation, + execution::allocator(alloc) + ).execute( + asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler))); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + associated_executor_t<decay_t<CompletionHandler>> + >::value + >* = 0) const + { + associated_executor_t<decay_t<CompletionHandler>> ex( + (get_associated_executor)(handler)); + + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + ex.defer(asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler)), alloc); + } +}; + +template <typename Executor> +class initiate_defer_with_executor +{ +public: + typedef Executor executor_type; + + explicit initiate_defer_with_executor(const Executor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const noexcept + { + return ex_; + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + !detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + asio::prefer( + asio::require(ex_, execution::blocking.never), + execution::relationship.continuation, + execution::allocator(alloc) + ).execute( + asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler))); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + typedef decay_t<CompletionHandler> handler_t; + + typedef associated_executor_t<handler_t, Executor> handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + associated_allocator_t<handler_t> alloc( + (get_associated_allocator)(handler)); + + asio::prefer( + asio::require(ex_, execution::blocking.never), + execution::relationship.continuation, + execution::allocator(alloc) + ).execute( + detail::work_dispatcher<handler_t, handler_ex_t>( + static_cast<CompletionHandler&&>(handler), handler_ex)); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + !detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + ex_.defer(asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler)), alloc); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + typedef decay_t<CompletionHandler> handler_t; + + typedef associated_executor_t<handler_t, Executor> handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + associated_allocator_t<handler_t> alloc( + (get_associated_allocator)(handler)); + + ex_.defer(detail::work_dispatcher<handler_t, handler_ex_t>( + static_cast<CompletionHandler&&>(handler), handler_ex), alloc); + } + +private: + Executor ex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_INITIATE_DEFER_HPP diff --git a/3rdparty/asio/include/asio/detail/initiate_dispatch.hpp b/3rdparty/asio/include/asio/detail/initiate_dispatch.hpp new file mode 100644 index 00000000000..ba2f68f0579 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/initiate_dispatch.hpp @@ -0,0 +1,193 @@ +// +// detail/initiate_dispatch.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_INITIATE_DISPATCH_HPP +#define ASIO_DETAIL_INITIATE_DISPATCH_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/work_dispatcher.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/prefer.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class initiate_dispatch +{ +public: + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + associated_executor_t<decay_t<CompletionHandler>> + >::value + >* = 0) const + { + associated_executor_t<decay_t<CompletionHandler>> ex( + (get_associated_executor)(handler)); + + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + asio::prefer(ex, execution::allocator(alloc)).execute( + asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler))); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + associated_executor_t<decay_t<CompletionHandler>> + >::value + >* = 0) const + { + associated_executor_t<decay_t<CompletionHandler>> ex( + (get_associated_executor)(handler)); + + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + ex.dispatch(asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler)), alloc); + } +}; + +template <typename Executor> +class initiate_dispatch_with_executor +{ +public: + typedef Executor executor_type; + + explicit initiate_dispatch_with_executor(const Executor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const noexcept + { + return ex_; + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + !detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + asio::prefer(ex_, execution::allocator(alloc)).execute( + asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler))); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + typedef decay_t<CompletionHandler> handler_t; + + typedef associated_executor_t<handler_t, Executor> handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + associated_allocator_t<handler_t> alloc( + (get_associated_allocator)(handler)); + + asio::prefer(ex_, execution::allocator(alloc)).execute( + detail::work_dispatcher<handler_t, handler_ex_t>( + static_cast<CompletionHandler&&>(handler), handler_ex)); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + !detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + ex_.dispatch(asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler)), alloc); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + typedef decay_t<CompletionHandler> handler_t; + + typedef associated_executor_t<handler_t, Executor> handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + associated_allocator_t<handler_t> alloc( + (get_associated_allocator)(handler)); + + ex_.dispatch(detail::work_dispatcher<handler_t, handler_ex_t>( + static_cast<CompletionHandler&&>(handler), handler_ex), alloc); + } + +private: + Executor ex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_INITIATE_DISPATCH_HPP diff --git a/3rdparty/asio/include/asio/detail/initiate_post.hpp b/3rdparty/asio/include/asio/detail/initiate_post.hpp new file mode 100644 index 00000000000..f73c8ee0b81 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/initiate_post.hpp @@ -0,0 +1,207 @@ +// +// detail/initiate_post.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_INITIATE_POST_HPP +#define ASIO_DETAIL_INITIATE_POST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/work_dispatcher.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/relationship.hpp" +#include "asio/prefer.hpp" +#include "asio/require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class initiate_post +{ +public: + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + associated_executor_t<decay_t<CompletionHandler>> + >::value + >* = 0) const + { + associated_executor_t<decay_t<CompletionHandler>> ex( + (get_associated_executor)(handler)); + + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + asio::prefer( + asio::require(ex, execution::blocking.never), + execution::relationship.fork, + execution::allocator(alloc) + ).execute( + asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler))); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + associated_executor_t<decay_t<CompletionHandler>> + >::value + >* = 0) const + { + associated_executor_t<decay_t<CompletionHandler>> ex( + (get_associated_executor)(handler)); + + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + ex.post(asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler)), alloc); + } +}; + +template <typename Executor> +class initiate_post_with_executor +{ +public: + typedef Executor executor_type; + + explicit initiate_post_with_executor(const Executor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const noexcept + { + return ex_; + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + !detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + asio::prefer( + asio::require(ex_, execution::blocking.never), + execution::relationship.fork, + execution::allocator(alloc) + ).execute( + asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler))); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + typedef decay_t<CompletionHandler> handler_t; + + typedef associated_executor_t<handler_t, Executor> handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + associated_allocator_t<handler_t> alloc( + (get_associated_allocator)(handler)); + + asio::prefer( + asio::require(ex_, execution::blocking.never), + execution::relationship.fork, + execution::allocator(alloc) + ).execute( + detail::work_dispatcher<handler_t, handler_ex_t>( + static_cast<CompletionHandler&&>(handler), handler_ex)); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + !detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + associated_allocator_t<decay_t<CompletionHandler>> alloc( + (get_associated_allocator)(handler)); + + ex_.post(asio::detail::bind_handler( + static_cast<CompletionHandler&&>(handler)), alloc); + } + + template <typename CompletionHandler> + void operator()(CompletionHandler&& handler, + enable_if_t< + !execution::is_executor< + conditional_t<true, executor_type, CompletionHandler> + >::value + >* = 0, + enable_if_t< + detail::is_work_dispatcher_required< + decay_t<CompletionHandler>, + Executor + >::value + >* = 0) const + { + typedef decay_t<CompletionHandler> handler_t; + + typedef associated_executor_t<handler_t, Executor> handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + associated_allocator_t<handler_t> alloc( + (get_associated_allocator)(handler)); + + ex_.post(detail::work_dispatcher<handler_t, handler_ex_t>( + static_cast<CompletionHandler&&>(handler), handler_ex), alloc); + } + +private: + Executor ex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_INITIATE_POST_HPP diff --git a/3rdparty/asio/include/asio/detail/io_control.hpp b/3rdparty/asio/include/asio/detail/io_control.hpp index 81b3d49c71c..14daf85730a 100644 --- a/3rdparty/asio/include/asio/detail/io_control.hpp +++ b/3rdparty/asio/include/asio/detail/io_control.hpp @@ -2,7 +2,7 @@ // detail/io_control.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/io_object_impl.hpp b/3rdparty/asio/include/asio/detail/io_object_impl.hpp new file mode 100644 index 00000000000..bd7312b8491 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_object_impl.hpp @@ -0,0 +1,177 @@ +// +// detail/io_object_impl.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_OBJECT_IMPL_HPP +#define ASIO_DETAIL_IO_OBJECT_IMPL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <new> +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/context.hpp" +#include "asio/io_context.hpp" +#include "asio/query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename IoObjectService, + typename Executor = io_context::executor_type> +class io_object_impl +{ +public: + // The type of the service that will be used to provide I/O operations. + typedef IoObjectService service_type; + + // The underlying implementation type of I/O object. + typedef typename service_type::implementation_type implementation_type; + + // The type of the executor associated with the object. + typedef Executor executor_type; + + // Construct an I/O object using an executor. + explicit io_object_impl(int, const executor_type& ex) + : service_(&asio::use_service<IoObjectService>( + io_object_impl::get_context(ex))), + executor_(ex) + { + service_->construct(implementation_); + } + + // Construct an I/O object using an execution context. + template <typename ExecutionContext> + explicit io_object_impl(int, int, ExecutionContext& context) + : service_(&asio::use_service<IoObjectService>(context)), + executor_(context.get_executor()) + { + service_->construct(implementation_); + } + + // Move-construct an I/O object. + io_object_impl(io_object_impl&& other) + : service_(&other.get_service()), + executor_(other.get_executor()) + { + service_->move_construct(implementation_, other.implementation_); + } + + // Perform converting move-construction of an I/O object on the same service. + template <typename Executor1> + io_object_impl(io_object_impl<IoObjectService, Executor1>&& other) + : service_(&other.get_service()), + executor_(other.get_executor()) + { + service_->move_construct(implementation_, other.get_implementation()); + } + + // Perform converting move-construction of an I/O object on another service. + template <typename IoObjectService1, typename Executor1> + io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other) + : service_(&asio::use_service<IoObjectService>( + io_object_impl::get_context(other.get_executor()))), + executor_(other.get_executor()) + { + service_->converting_move_construct(implementation_, + other.get_service(), other.get_implementation()); + } + + // Destructor. + ~io_object_impl() + { + service_->destroy(implementation_); + } + + // Move-assign an I/O object. + io_object_impl& operator=(io_object_impl&& other) + { + if (this != &other) + { + service_->move_assign(implementation_, + *other.service_, other.implementation_); + executor_.~executor_type(); + new (&executor_) executor_type(other.executor_); + service_ = other.service_; + } + return *this; + } + + // Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return executor_; + } + + // Get the service associated with the I/O object. + service_type& get_service() + { + return *service_; + } + + // Get the service associated with the I/O object. + const service_type& get_service() const + { + return *service_; + } + + // Get the underlying implementation of the I/O object. + implementation_type& get_implementation() + { + return implementation_; + } + + // Get the underlying implementation of the I/O object. + const implementation_type& get_implementation() const + { + return implementation_; + } + +private: + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<execution::is_executor<T>::value>* = 0) + { + return asio::query(t, execution::context); + } + + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<!execution::is_executor<T>::value>* = 0) + { + return t.context(); + } + + // Disallow copying and copy assignment. + io_object_impl(const io_object_impl&); + io_object_impl& operator=(const io_object_impl&); + + // The service associated with the I/O object. + service_type* service_; + + // The underlying implementation of the I/O object. + implementation_type implementation_; + + // The associated executor. + executor_type executor_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IO_OBJECT_IMPL_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_descriptor_read_at_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_descriptor_read_at_op.hpp new file mode 100644 index 00000000000..114bdb54297 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_descriptor_read_at_op.hpp @@ -0,0 +1,195 @@ +// +// detail/io_uring_descriptor_read_at_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_DESCRIPTOR_READ_AT_OP_HPP +#define ASIO_DETAIL_IO_URING_DESCRIPTOR_READ_AT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/cstdint.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class io_uring_descriptor_read_at_op_base : public io_uring_operation +{ +public: + io_uring_descriptor_read_at_op_base( + const asio::error_code& success_ec, int descriptor, + descriptor_ops::state_type state, uint64_t offset, + const MutableBufferSequence& buffers, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_descriptor_read_at_op_base::do_prepare, + &io_uring_descriptor_read_at_op_base::do_perform, complete_func), + descriptor_(descriptor), + state_(state), + offset_(offset), + buffers_(buffers), + bufs_(buffers) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_read_at_op_base* o( + static_cast<io_uring_descriptor_read_at_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + ::io_uring_prep_poll_add(sqe, o->descriptor_, POLLIN); + } + else if (o->bufs_.is_single_buffer && o->bufs_.is_registered_buffer) + { + ::io_uring_prep_read_fixed(sqe, o->descriptor_, + o->bufs_.buffers()->iov_base, o->bufs_.buffers()->iov_len, + o->offset_, o->bufs_.registered_id().native_handle()); + } + else + { + ::io_uring_prep_readv(sqe, o->descriptor_, + o->bufs_.buffers(), o->bufs_.count(), o->offset_); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_read_at_op_base* o( + static_cast<io_uring_descriptor_read_at_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + if (o->bufs_.is_single_buffer) + { + return descriptor_ops::non_blocking_read_at1(o->descriptor_, + o->offset_, o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->ec_, + o->bytes_transferred_); + } + else + { + return descriptor_ops::non_blocking_read_at(o->descriptor_, + o->offset_, o->bufs_.buffers(), o->bufs_.count(), + o->ec_, o->bytes_transferred_); + } + } + else if (after_completion) + { + if (!o->ec_ && o->bytes_transferred_ == 0) + o->ec_ = asio::error::eof; + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= descriptor_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + int descriptor_; + descriptor_ops::state_type state_; + uint64_t offset_; + MutableBufferSequence buffers_; + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_; +}; + +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> +class io_uring_descriptor_read_at_op + : public io_uring_descriptor_read_at_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_descriptor_read_at_op); + + io_uring_descriptor_read_at_op(const asio::error_code& success_ec, + int descriptor, descriptor_ops::state_type state, uint64_t offset, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : io_uring_descriptor_read_at_op_base<MutableBufferSequence>( + success_ec, descriptor, state, offset, buffers, + &io_uring_descriptor_read_at_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_descriptor_read_at_op* o + (static_cast<io_uring_descriptor_read_at_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_DESCRIPTOR_READ_AT_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_descriptor_read_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_descriptor_read_op.hpp new file mode 100644 index 00000000000..9f8cf70bca3 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_descriptor_read_op.hpp @@ -0,0 +1,190 @@ +// +// detail/io_uring_descriptor_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_DESCRIPTOR_READ_OP_HPP +#define ASIO_DETAIL_IO_URING_DESCRIPTOR_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class io_uring_descriptor_read_op_base : public io_uring_operation +{ +public: + io_uring_descriptor_read_op_base(const asio::error_code& success_ec, + int descriptor, descriptor_ops::state_type state, + const MutableBufferSequence& buffers, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_descriptor_read_op_base::do_prepare, + &io_uring_descriptor_read_op_base::do_perform, complete_func), + descriptor_(descriptor), + state_(state), + buffers_(buffers), + bufs_(buffers) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_read_op_base* o( + static_cast<io_uring_descriptor_read_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + ::io_uring_prep_poll_add(sqe, o->descriptor_, POLLIN); + } + else if (o->bufs_.is_single_buffer && o->bufs_.is_registered_buffer) + { + ::io_uring_prep_read_fixed(sqe, o->descriptor_, + o->bufs_.buffers()->iov_base, o->bufs_.buffers()->iov_len, + 0, o->bufs_.registered_id().native_handle()); + } + else + { + ::io_uring_prep_readv(sqe, o->descriptor_, + o->bufs_.buffers(), o->bufs_.count(), -1); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_read_op_base* o( + static_cast<io_uring_descriptor_read_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + if (o->bufs_.is_single_buffer) + { + return descriptor_ops::non_blocking_read1( + o->descriptor_, o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->ec_, + o->bytes_transferred_); + } + else + { + return descriptor_ops::non_blocking_read( + o->descriptor_, o->bufs_.buffers(), o->bufs_.count(), + o->ec_, o->bytes_transferred_); + } + } + else if (after_completion) + { + if (!o->ec_ && o->bytes_transferred_ == 0) + o->ec_ = asio::error::eof; + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= descriptor_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + int descriptor_; + descriptor_ops::state_type state_; + MutableBufferSequence buffers_; + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_; +}; + +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> +class io_uring_descriptor_read_op + : public io_uring_descriptor_read_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_descriptor_read_op); + + io_uring_descriptor_read_op(const asio::error_code& success_ec, + int descriptor, descriptor_ops::state_type state, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : io_uring_descriptor_read_op_base<MutableBufferSequence>(success_ec, + descriptor, state, buffers, &io_uring_descriptor_read_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_descriptor_read_op* o + (static_cast<io_uring_descriptor_read_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_DESCRIPTOR_READ_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_descriptor_service.hpp b/3rdparty/asio/include/asio/detail/io_uring_descriptor_service.hpp new file mode 100644 index 00000000000..04d1e36edd8 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_descriptor_service.hpp @@ -0,0 +1,687 @@ +// +// detail/io_uring_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_DESCRIPTOR_SERVICE_HPP +#define ASIO_DETAIL_IO_URING_DESCRIPTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/associated_cancellation_slot.hpp" +#include "asio/buffer.hpp" +#include "asio/cancellation_type.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/io_uring_descriptor_read_at_op.hpp" +#include "asio/detail/io_uring_descriptor_read_op.hpp" +#include "asio/detail/io_uring_descriptor_write_at_op.hpp" +#include "asio/detail/io_uring_descriptor_write_op.hpp" +#include "asio/detail/io_uring_null_buffers_op.hpp" +#include "asio/detail/io_uring_service.hpp" +#include "asio/detail/io_uring_wait_op.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/posix/descriptor_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class io_uring_descriptor_service : + public execution_context_service_base<io_uring_descriptor_service> +{ +public: + // The native type of a descriptor. + typedef int native_handle_type; + + // The implementation type of the descriptor. + class implementation_type + : private asio::detail::noncopyable + { + public: + // Default constructor. + implementation_type() + : descriptor_(-1), + state_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class io_uring_descriptor_service; + + // The native descriptor representation. + int descriptor_; + + // The current state of the descriptor. + descriptor_ops::state_type state_; + + // Per I/O object data used by the io_uring_service. + io_uring_service::per_io_object_data io_object_data_; + }; + + // Constructor. + ASIO_DECL io_uring_descriptor_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new descriptor implementation. + ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new descriptor implementation. + ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl) noexcept; + + // Move-assign from another descriptor implementation. + ASIO_DECL void move_assign(implementation_type& impl, + io_uring_descriptor_service& other_service, + implementation_type& other_impl); + + // Destroy a descriptor implementation. + ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native descriptor to a descriptor implementation. + ASIO_DECL asio::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + asio::error_code& ec); + + // Determine whether the descriptor is open. + bool is_open(const implementation_type& impl) const + { + return impl.descriptor_ != -1; + } + + // Destroy a descriptor implementation. + ASIO_DECL asio::error_code close(implementation_type& impl, + asio::error_code& ec); + + // Get the native descriptor representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.descriptor_; + } + + // Release ownership of the native descriptor representation. + ASIO_DECL native_handle_type release(implementation_type& impl); + + // Release ownership of the native descriptor representation. + native_handle_type release(implementation_type& impl, + asio::error_code& ec) + { + ec = success_ec_; + return release(impl); + } + + // Cancel all operations associated with the descriptor. + ASIO_DECL asio::error_code cancel(implementation_type& impl, + asio::error_code& ec); + + // Perform an IO control command on the descriptor. + template <typename IO_Control_Command> + asio::error_code io_control(implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + descriptor_ops::ioctl(impl.descriptor_, impl.state_, + command.name(), static_cast<ioctl_arg_type*>(command.data()), ec); + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Gets the non-blocking mode of the descriptor. + bool non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the descriptor. + asio::error_code non_blocking(implementation_type& impl, + bool mode, asio::error_code& ec) + { + descriptor_ops::set_user_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Gets the non-blocking mode of the native descriptor implementation. + bool native_non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native descriptor implementation. + asio::error_code native_non_blocking(implementation_type& impl, + bool mode, asio::error_code& ec) + { + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Wait for the descriptor to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(implementation_type& impl, + posix::descriptor_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case posix::descriptor_base::wait_read: + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_write: + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_error: + descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Asynchronously wait for the descriptor to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler, typename IoExecutor> + void async_wait(implementation_type& impl, + posix::descriptor_base::wait_type w, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + int op_type; + int poll_flags; + switch (w) + { + case posix::descriptor_base::wait_read: + op_type = io_uring_service::read_op; + poll_flags = POLLIN; + break; + case posix::descriptor_base::wait_write: + op_type = io_uring_service::write_op; + poll_flags = POLLOUT; + break; + case posix::descriptor_base::wait_error: + op_type = io_uring_service::except_op; + poll_flags = POLLPRI | POLLERR | POLLHUP; + break; + default: + op_type = -1; + poll_flags = -1; + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_wait_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, + poll_flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected() && op_type != -1) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "descriptor", &impl, impl.descriptor_, "async_wait")); + + start_op(impl, op_type, p.p, is_continuation, op_type == -1); + p.v = p.p = 0; + } + + // Write some data to the descriptor. + template <typename ConstBufferSequence> + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; + + size_t n; + if (bufs_type::is_single_buffer) + { + n = descriptor_ops::sync_write1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + n = descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + ASIO_ERROR_LOCATION(ec); + return n; + } + + // Wait until data can be written without blocking. + size_t write_some(implementation_type& impl, + const null_buffers&, asio::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + + ASIO_ERROR_LOCATION(ec); + return 0; + } + + // Start an asynchronous write. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_descriptor_write_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, + impl.state_, buffers, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "descriptor", &impl, impl.descriptor_, "async_write_some")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::all_empty(buffers)); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be written without blocking. + template <typename Handler, typename IoExecutor> + void async_write_some(implementation_type& impl, + const null_buffers&, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_null_buffers_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, POLLOUT, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), + *p.p, "descriptor", &impl, impl.descriptor_, + "async_write_some(null_buffers)")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Write some data to the descriptor at the specified offset. + template <typename ConstBufferSequence> + size_t write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; + + size_t n; + if (bufs_type::is_single_buffer) + { + n = descriptor_ops::sync_write_at1(impl.descriptor_, + impl.state_, offset, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + n = descriptor_ops::sync_write_at(impl.descriptor_, impl.state_, + offset, bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + ASIO_ERROR_LOCATION(ec); + return n; + } + + // Wait until data can be written without blocking. + size_t write_some_at(implementation_type& impl, uint64_t, + const null_buffers& buffers, asio::error_code& ec) + { + return write_some(impl, buffers, ec); + } + + // Start an asynchronous write at the specified offset. The data being sent + // must be valid for the lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_descriptor_write_at_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, + impl.state_, offset, buffers, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "descriptor", &impl, impl.descriptor_, "async_write_some")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::all_empty(buffers)); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be written without blocking. + template <typename Handler, typename IoExecutor> + void async_write_some_at(implementation_type& impl, + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex) + { + return async_write_some(impl, buffers, handler, io_ex); + } + + // Read some data from the stream. Returns the number of bytes read. + template <typename MutableBufferSequence> + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; + + size_t n; + if (bufs_type::is_single_buffer) + { + n = descriptor_ops::sync_read1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + n = descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + ASIO_ERROR_LOCATION(ec); + return n; + } + + // Wait until data can be read without blocking. + size_t read_some(implementation_type& impl, + const null_buffers&, asio::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + + ASIO_ERROR_LOCATION(ec); + return 0; + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_descriptor_read_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, + impl.state_, buffers, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::read_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "descriptor", &impl, impl.descriptor_, "async_read_some")); + + start_op(impl, io_uring_service::read_op, p.p, is_continuation, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(buffers)); + p.v = p.p = 0; + } + + // Wait until data can be read without blocking. + template <typename Handler, typename IoExecutor> + void async_read_some(implementation_type& impl, + const null_buffers&, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_null_buffers_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, POLLIN, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::read_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), + *p.p, "descriptor", &impl, impl.descriptor_, + "async_read_some(null_buffers)")); + + start_op(impl, io_uring_service::read_op, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Read some data at the specified offset. Returns the number of bytes read. + template <typename MutableBufferSequence> + size_t read_some_at(implementation_type& impl, uint64_t offset, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; + + if (bufs_type::is_single_buffer) + { + return descriptor_ops::sync_read_at1(impl.descriptor_, + impl.state_, offset, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + return descriptor_ops::sync_read_at(impl.descriptor_, impl.state_, + offset, bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + } + + // Wait until data can be read without blocking. + size_t read_some_at(implementation_type& impl, uint64_t, + const null_buffers& buffers, asio::error_code& ec) + { + return read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_read_some_at(implementation_type& impl, + uint64_t offset, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_descriptor_read_at_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.descriptor_, + impl.state_, offset, buffers, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::read_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "descriptor", &impl, impl.descriptor_, "async_read_some")); + + start_op(impl, io_uring_service::read_op, p.p, is_continuation, + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(buffers)); + p.v = p.p = 0; + } + + // Wait until data can be read without blocking. + template <typename Handler, typename IoExecutor> + void async_read_some_at(implementation_type& impl, uint64_t, + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex) + { + return async_read_some(impl, buffers, handler, io_ex); + } + +private: + // Start the asynchronous operation. + ASIO_DECL void start_op(implementation_type& impl, int op_type, + io_uring_operation* op, bool is_continuation, bool noop); + + // Helper class used to implement per-operation cancellation + class io_uring_op_cancellation + { + public: + io_uring_op_cancellation(io_uring_service* s, + io_uring_service::per_io_object_data* p, int o) + : io_uring_service_(s), + io_object_data_(p), + op_type_(o) + { + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + io_uring_service_->cancel_ops_by_key(*io_object_data_, op_type_, this); + } + } + + private: + io_uring_service* io_uring_service_; + io_uring_service::per_io_object_data* io_object_data_; + int op_type_; + }; + + // The io_uring_service that performs event demultiplexing for the service. + io_uring_service& io_uring_service_; + + // Cached success value to avoid accessing category singleton. + const asio::error_code success_ec_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/io_uring_descriptor_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_DESCRIPTOR_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_descriptor_write_at_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_descriptor_write_at_op.hpp new file mode 100644 index 00000000000..10a3f7a6c3d --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_descriptor_write_at_op.hpp @@ -0,0 +1,189 @@ +// +// detail/io_uring_descriptor_write_at_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_DESCRIPTOR_WRITE_AT_OP_HPP +#define ASIO_DETAIL_IO_URING_DESCRIPTOR_WRITE_AT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence> +class io_uring_descriptor_write_at_op_base : public io_uring_operation +{ +public: + io_uring_descriptor_write_at_op_base( + const asio::error_code& success_ec, int descriptor, + descriptor_ops::state_type state, uint64_t offset, + const ConstBufferSequence& buffers, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_descriptor_write_at_op_base::do_prepare, + &io_uring_descriptor_write_at_op_base::do_perform, complete_func), + descriptor_(descriptor), + state_(state), + offset_(offset), + buffers_(buffers), + bufs_(buffers) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_write_at_op_base* o( + static_cast<io_uring_descriptor_write_at_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + ::io_uring_prep_poll_add(sqe, o->descriptor_, POLLOUT); + } + else if (o->bufs_.is_single_buffer && o->bufs_.is_registered_buffer) + { + ::io_uring_prep_write_fixed(sqe, o->descriptor_, + o->bufs_.buffers()->iov_base, o->bufs_.buffers()->iov_len, + o->offset_, o->bufs_.registered_id().native_handle()); + } + else + { + ::io_uring_prep_writev(sqe, o->descriptor_, + o->bufs_.buffers(), o->bufs_.count(), o->offset_); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_write_at_op_base* o( + static_cast<io_uring_descriptor_write_at_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + if (o->bufs_.is_single_buffer) + { + return descriptor_ops::non_blocking_write_at1(o->descriptor_, + o->offset_, o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->ec_, + o->bytes_transferred_); + } + else + { + return descriptor_ops::non_blocking_write_at(o->descriptor_, + o->offset_, o->bufs_.buffers(), o->bufs_.count(), + o->ec_, o->bytes_transferred_); + } + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= descriptor_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + int descriptor_; + descriptor_ops::state_type state_; + uint64_t offset_; + ConstBufferSequence buffers_; + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_; +}; + +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> +class io_uring_descriptor_write_at_op + : public io_uring_descriptor_write_at_op_base<ConstBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_descriptor_write_at_op); + + io_uring_descriptor_write_at_op(const asio::error_code& success_ec, + int descriptor, descriptor_ops::state_type state, uint64_t offset, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : io_uring_descriptor_write_at_op_base<ConstBufferSequence>( + success_ec, descriptor, state, offset, buffers, + &io_uring_descriptor_write_at_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_descriptor_write_at_op* o + (static_cast<io_uring_descriptor_write_at_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_DESCRIPTOR_WRITE_AT_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_descriptor_write_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_descriptor_write_op.hpp new file mode 100644 index 00000000000..090d644c7c8 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_descriptor_write_op.hpp @@ -0,0 +1,185 @@ +// +// detail/io_uring_descriptor_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_DESCRIPTOR_WRITE_OP_HPP +#define ASIO_DETAIL_IO_URING_DESCRIPTOR_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence> +class io_uring_descriptor_write_op_base : public io_uring_operation +{ +public: + io_uring_descriptor_write_op_base(const asio::error_code& success_ec, + int descriptor, descriptor_ops::state_type state, + const ConstBufferSequence& buffers, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_descriptor_write_op_base::do_prepare, + &io_uring_descriptor_write_op_base::do_perform, complete_func), + descriptor_(descriptor), + state_(state), + buffers_(buffers), + bufs_(buffers) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_write_op_base* o( + static_cast<io_uring_descriptor_write_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + ::io_uring_prep_poll_add(sqe, o->descriptor_, POLLOUT); + } + else if (o->bufs_.is_single_buffer && o->bufs_.is_registered_buffer) + { + ::io_uring_prep_write_fixed(sqe, o->descriptor_, + o->bufs_.buffers()->iov_base, o->bufs_.buffers()->iov_len, + 0, o->bufs_.registered_id().native_handle()); + } + else + { + ::io_uring_prep_writev(sqe, o->descriptor_, + o->bufs_.buffers(), o->bufs_.count(), -1); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_descriptor_write_op_base* o( + static_cast<io_uring_descriptor_write_op_base*>(base)); + + if ((o->state_ & descriptor_ops::internal_non_blocking) != 0) + { + if (o->bufs_.is_single_buffer) + { + return descriptor_ops::non_blocking_write1( + o->descriptor_, o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->ec_, + o->bytes_transferred_); + } + else + { + return descriptor_ops::non_blocking_write( + o->descriptor_, o->bufs_.buffers(), o->bufs_.count(), + o->ec_, o->bytes_transferred_); + } + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= descriptor_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + int descriptor_; + descriptor_ops::state_type state_; + ConstBufferSequence buffers_; + buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_; +}; + +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> +class io_uring_descriptor_write_op + : public io_uring_descriptor_write_op_base<ConstBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_descriptor_write_op); + + io_uring_descriptor_write_op(const asio::error_code& success_ec, + int descriptor, descriptor_ops::state_type state, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : io_uring_descriptor_write_op_base<ConstBufferSequence>(success_ec, + descriptor, state, buffers, &io_uring_descriptor_write_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_descriptor_write_op* o + (static_cast<io_uring_descriptor_write_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_DESCRIPTOR_WRITE_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_file_service.hpp b/3rdparty/asio/include/asio/detail/io_uring_file_service.hpp new file mode 100644 index 00000000000..3a0a4538623 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_file_service.hpp @@ -0,0 +1,261 @@ +// +// detail/io_uring_file_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_FILE_SERVICE_HPP +#define ASIO_DETAIL_IO_URING_FILE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + && defined(ASIO_HAS_IO_URING) + +#include <string> +#include "asio/detail/cstdint.hpp" +#include "asio/detail/descriptor_ops.hpp" +#include "asio/detail/io_uring_descriptor_service.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/file_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Extend the io_uring_descriptor_service to provide file support. +class io_uring_file_service : + public execution_context_service_base<io_uring_file_service> +{ +public: + typedef io_uring_descriptor_service descriptor_service; + + // The native type of a file. + typedef descriptor_service::native_handle_type native_handle_type; + + // The implementation type of the file. + class implementation_type : descriptor_service::implementation_type + { + private: + // Only this service will have access to the internal values. + friend class io_uring_file_service; + + bool is_stream_; + }; + + ASIO_DECL io_uring_file_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new file implementation. + void construct(implementation_type& impl) + { + descriptor_service_.construct(impl); + impl.is_stream_ = false; + } + + // Move-construct a new file implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + descriptor_service_.move_construct(impl, other_impl); + impl.is_stream_ = other_impl.is_stream_; + } + + // Move-assign from another file implementation. + void move_assign(implementation_type& impl, + io_uring_file_service& other_service, + implementation_type& other_impl) + { + descriptor_service_.move_assign(impl, + other_service.descriptor_service_, other_impl); + impl.is_stream_ = other_impl.is_stream_; + } + + // Destroy a file implementation. + void destroy(implementation_type& impl) + { + descriptor_service_.destroy(impl); + } + + // Open the file using the specified path name. + ASIO_DECL asio::error_code open(implementation_type& impl, + const char* path, file_base::flags open_flags, + asio::error_code& ec); + + // Assign a native descriptor to a file implementation. + asio::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + asio::error_code& ec) + { + return descriptor_service_.assign(impl, native_descriptor, ec); + } + + // Set whether the implementation is stream-oriented. + void set_is_stream(implementation_type& impl, bool is_stream) + { + impl.is_stream_ = is_stream; + } + + // Determine whether the file is open. + bool is_open(const implementation_type& impl) const + { + return descriptor_service_.is_open(impl); + } + + // Destroy a file implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + return descriptor_service_.close(impl, ec); + } + + // Get the native file representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return descriptor_service_.native_handle(impl); + } + + // Release ownership of the native descriptor representation. + native_handle_type release(implementation_type& impl, + asio::error_code& ec) + { + return descriptor_service_.release(impl, ec); + } + + // Cancel all operations associated with the file. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + return descriptor_service_.cancel(impl, ec); + } + + // Get the size of the file. + ASIO_DECL uint64_t size(const implementation_type& impl, + asio::error_code& ec) const; + + // Alter the size of the file. + ASIO_DECL asio::error_code resize(implementation_type& impl, + uint64_t n, asio::error_code& ec); + + // Synchronise the file to disk. + ASIO_DECL asio::error_code sync_all(implementation_type& impl, + asio::error_code& ec); + + // Synchronise the file data to disk. + ASIO_DECL asio::error_code sync_data(implementation_type& impl, + asio::error_code& ec); + + // Seek to a position in the file. + ASIO_DECL uint64_t seek(implementation_type& impl, int64_t offset, + file_base::seek_basis whence, asio::error_code& ec); + + // Write the given data. Returns the number of bytes written. + template <typename ConstBufferSequence> + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_write_some(impl, buffers, handler, io_ex); + } + + // Write the given data at the specified location. Returns the number of + // bytes written. + template <typename ConstBufferSequence> + size_t write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.write_some_at(impl, offset, buffers, ec); + } + + // Start an asynchronous write at the specified location. The data being + // written must be valid for the lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_write_some_at(implementation_type& impl, + uint64_t offset, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_write_some_at( + impl, offset, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes read. + template <typename MutableBufferSequence> + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_read_some(impl, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes read. + template <typename MutableBufferSequence> + size_t read_some_at(implementation_type& impl, uint64_t offset, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return descriptor_service_.read_some_at(impl, offset, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_read_some_at(implementation_type& impl, + uint64_t offset, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_read_some_at( + impl, offset, buffers, handler, io_ex); + } + +private: + // The implementation used for initiating asynchronous operations. + descriptor_service descriptor_service_; + + // Cached success value to avoid accessing category singleton. + const asio::error_code success_ec_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/io_uring_file_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_FILE) + // && defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_FILE_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_null_buffers_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_null_buffers_op.hpp new file mode 100644 index 00000000000..61fe6a6aafb --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_null_buffers_op.hpp @@ -0,0 +1,114 @@ +// +// detail/io_uring_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_NULL_BUFFERS_OP_HPP +#define ASIO_DETAIL_IO_URING_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler, typename IoExecutor> +class io_uring_null_buffers_op : public io_uring_operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_null_buffers_op); + + io_uring_null_buffers_op(const asio::error_code& success_ec, + int descriptor, int poll_flags, Handler& handler, const IoExecutor& io_ex) + : io_uring_operation(success_ec, + &io_uring_null_buffers_op::do_prepare, + &io_uring_null_buffers_op::do_perform, + &io_uring_null_buffers_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex), + descriptor_(descriptor), + poll_flags_(poll_flags) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_null_buffers_op* o(static_cast<io_uring_null_buffers_op*>(base)); + + ::io_uring_prep_poll_add(sqe, o->descriptor_, o->poll_flags_); + } + + static bool do_perform(io_uring_operation*, bool after_completion) + { + return after_completion; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_null_buffers_op* o(static_cast<io_uring_null_buffers_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; + int descriptor_; + int poll_flags_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IO_URING_NULL_BUFFERS_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_operation.hpp b/3rdparty/asio/include/asio/detail/io_uring_operation.hpp new file mode 100644 index 00000000000..f2635cc4074 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_operation.hpp @@ -0,0 +1,84 @@ +// +// detail/io_uring_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_OPERATION_HPP +#define ASIO_DETAIL_IO_URING_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include <liburing.h> +#include "asio/detail/cstdint.hpp" +#include "asio/detail/operation.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class io_uring_operation + : public operation +{ +public: + // The error code to be passed to the completion handler. + asio::error_code ec_; + + // The number of bytes transferred, to be passed to the completion handler. + std::size_t bytes_transferred_; + + // The operation key used for targeted cancellation. + void* cancellation_key_; + + // Prepare the operation. + void prepare(::io_uring_sqe* sqe) + { + return prepare_func_(this, sqe); + } + + // Perform actions associated with the operation. Returns true when complete. + bool perform(bool after_completion) + { + return perform_func_(this, after_completion); + } + +protected: + typedef void (*prepare_func_type)(io_uring_operation*, ::io_uring_sqe*); + typedef bool (*perform_func_type)(io_uring_operation*, bool); + + io_uring_operation(const asio::error_code& success_ec, + prepare_func_type prepare_func, perform_func_type perform_func, + func_type complete_func) + : operation(complete_func), + ec_(success_ec), + bytes_transferred_(0), + cancellation_key_(0), + prepare_func_(prepare_func), + perform_func_(perform_func) + { + } + +private: + prepare_func_type prepare_func_; + perform_func_type perform_func_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_OPERATION_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_service.hpp b/3rdparty/asio/include/asio/detail/io_uring_service.hpp new file mode 100644 index 00000000000..2dd3c0bf14d --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_service.hpp @@ -0,0 +1,319 @@ +// +// detail/io_uring_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SERVICE_HPP +#define ASIO_DETAIL_IO_URING_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include <liburing.h> +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/conditionally_enabled_mutex.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/object_pool.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/reactor.hpp" +#include "asio/detail/scheduler_task.hpp" +#include "asio/detail/timer_queue_base.hpp" +#include "asio/detail/timer_queue_set.hpp" +#include "asio/detail/wait_op.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class io_uring_service + : public execution_context_service_base<io_uring_service>, + public scheduler_task +{ +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + +public: + enum op_types { read_op = 0, write_op = 1, except_op = 2, max_ops = 3 }; + + class io_object; + + // An I/O queue stores operations that must run serially. + class io_queue : operation + { + friend class io_uring_service; + + io_object* io_object_; + op_queue<io_uring_operation> op_queue_; + bool cancel_requested_; + + ASIO_DECL io_queue(); + void set_result(int r) { task_result_ = static_cast<unsigned>(r); } + ASIO_DECL operation* perform_io(int result); + ASIO_DECL static void do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred); + }; + + // Per I/O object state. + class io_object + { + friend class io_uring_service; + friend class object_pool_access; + + io_object* next_; + io_object* prev_; + + mutex mutex_; + io_uring_service* service_; + io_queue queues_[max_ops]; + bool shutdown_; + + ASIO_DECL io_object(bool locking); + }; + + // Per I/O object data. + typedef io_object* per_io_object_data; + + // Constructor. + ASIO_DECL io_uring_service(asio::execution_context& ctx); + + // Destructor. + ASIO_DECL ~io_uring_service(); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Recreate internal state following a fork. + ASIO_DECL void notify_fork( + asio::execution_context::fork_event fork_ev); + + // Initialise the task. + ASIO_DECL void init_task(); + + // Register an I/O object with io_uring. + ASIO_DECL void register_io_object(io_object*& io_obj); + + // Register an internal I/O object with io_uring. + ASIO_DECL void register_internal_io_object( + io_object*& io_obj, int op_type, io_uring_operation* op); + + // Register buffers with io_uring. + ASIO_DECL void register_buffers(const ::iovec* v, unsigned n); + + // Unregister buffers from io_uring. + ASIO_DECL void unregister_buffers(); + + // Post an operation for immediate completion. + void post_immediate_completion(operation* op, bool is_continuation); + + // Start a new operation. The operation will be prepared and submitted to the + // io_uring when it is at the head of its I/O operation queue. + ASIO_DECL void start_op(int op_type, per_io_object_data& io_obj, + io_uring_operation* op, bool is_continuation); + + // Cancel all operations associated with the given I/O object. The handlers + // associated with the I/O object will be invoked with the operation_aborted + // error. + ASIO_DECL void cancel_ops(per_io_object_data& io_obj); + + // Cancel all operations associated with the given I/O object and key. The + // handlers associated with the object and key will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops_by_key(per_io_object_data& io_obj, + int op_type, void* cancellation_key); + + // Cancel any operations that are running against the I/O object and remove + // its registration from the service. The service resources associated with + // the I/O object must be released by calling cleanup_io_object. + ASIO_DECL void deregister_io_object(per_io_object_data& io_obj); + + // Perform any post-deregistration cleanup tasks associated with the I/O + // object. + ASIO_DECL void cleanup_io_object(per_io_object_data& io_obj); + + // Add a new timer queue to the reactor. + template <typename Time_Traits> + void add_timer_queue(timer_queue<Time_Traits>& timer_queue); + + // Remove a timer queue from the reactor. + template <typename Time_Traits> + void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template <typename Time_Traits> + void schedule_timer(timer_queue<Time_Traits>& queue, + const typename Time_Traits::time_type& time, + typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template <typename Time_Traits> + std::size_t cancel_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + + // Cancel the timer operations associated with the given key. + template <typename Time_Traits> + void cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key); + + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + + // Wait on io_uring once until interrupted or events are ready to be + // dispatched. + ASIO_DECL void run(long usec, op_queue<operation>& ops); + + // Interrupt the io_uring wait. + ASIO_DECL void interrupt(); + +private: + // The hint to pass to io_uring_queue_init to size its data structures. + enum { ring_size = 16384 }; + + // The number of operations to submit in a batch. + enum { submit_batch_size = 128 }; + + // The number of operations to complete in a batch. + enum { complete_batch_size = 128 }; + + // The type used for processing eventfd readiness notifications. + class event_fd_read_op; + + // Initialise the ring. + ASIO_DECL void init_ring(); + + // Register the eventfd descriptor for readiness notifications. + ASIO_DECL void register_with_reactor(); + + // Allocate a new I/O object. + ASIO_DECL io_object* allocate_io_object(); + + // Free an existing I/O object. + ASIO_DECL void free_io_object(io_object* s); + + // Helper function to cancel all operations associated with the given I/O + // object. This function must be called while the I/O object's mutex is held. + // Returns true if there are operations for which cancellation is pending. + ASIO_DECL bool do_cancel_ops( + per_io_object_data& io_obj, op_queue<operation>& ops); + + // Helper function to add a new timer queue. + ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + ASIO_DECL void update_timeout(); + + // Get the current timeout value. + ASIO_DECL __kernel_timespec get_timeout() const; + + // Get a new submission queue entry, flushing the queue if necessary. + ASIO_DECL ::io_uring_sqe* get_sqe(); + + // Submit pending submission queue entries. + ASIO_DECL void submit_sqes(); + + // Post an operation to submit the pending submission queue entries. + ASIO_DECL void post_submit_sqes_op(mutex::scoped_lock& lock); + + // Push an operation to submit the pending submission queue entries. + ASIO_DECL void push_submit_sqes_op(op_queue<operation>& ops); + + // Helper operation to submit pending submission queue entries. + class submit_sqes_op : operation + { + friend class io_uring_service; + + io_uring_service* service_; + + ASIO_DECL submit_sqes_op(io_uring_service* s); + ASIO_DECL static void do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred); + }; + + // The scheduler implementation used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + mutex mutex_; + + // The ring. + ::io_uring ring_; + + // The count of unfinished work. + atomic_count outstanding_work_; + + // The operation used to submit the pending submission queue entries. + submit_sqes_op submit_sqes_op_; + + // The number of pending submission queue entries_. + int pending_sqes_; + + // Whether there is a pending submission operation. + bool pending_submit_sqes_op_; + + // Whether the service has been shut down. + bool shutdown_; + + // The timer queues. + timer_queue_set timer_queues_; + + // The timespec for the pending timeout operation. Must remain valid while the + // operation is outstanding. + __kernel_timespec timeout_; + + // Mutex to protect access to the registered I/O objects. + mutex registration_mutex_; + + // Keep track of all registered I/O objects. + object_pool<io_object> registered_io_objects_; + + // Helper class to do post-perform_io cleanup. + struct perform_io_cleanup_on_block_exit; + friend struct perform_io_cleanup_on_block_exit; + + // The reactor used to register for eventfd readiness. + reactor& reactor_; + + // The per-descriptor reactor data used for the eventfd. + reactor::per_descriptor_data reactor_data_; + + // The eventfd descriptor used to wait for readiness. + int event_fd_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/impl/io_uring_service.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/io_uring_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_accept_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_accept_op.hpp new file mode 100644 index 00000000000..dbf1a98b536 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_accept_op.hpp @@ -0,0 +1,280 @@ +// +// detail/io_uring_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_ACCEPT_OP_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Socket, typename Protocol> +class io_uring_socket_accept_op_base : public io_uring_operation +{ +public: + io_uring_socket_accept_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_socket_accept_op_base::do_prepare, + &io_uring_socket_accept_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_socket_accept_op_base* o( + static_cast<io_uring_socket_accept_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + ::io_uring_prep_poll_add(sqe, o->socket_, POLLIN); + } + else + { + ::io_uring_prep_accept(sqe, o->socket_, + o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &o->addrlen_ : 0, 0); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_socket_accept_op_base* o( + static_cast<io_uring_socket_accept_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + socket_type new_socket = invalid_socket; + std::size_t addrlen = static_cast<std::size_t>(o->addrlen_); + bool result = socket_ops::non_blocking_accept(o->socket_, + o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket); + o->new_socket_.reset(new_socket); + o->addrlen_ = static_cast<socklen_t>(addrlen); + return result; + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= socket_ops::internal_non_blocking; + return false; + } + + if (after_completion && !o->ec_) + o->new_socket_.reset(static_cast<int>(o->bytes_transferred_)); + + return after_completion; + } + + void do_assign() + { + if (new_socket_.get() != invalid_socket) + { + if (peer_endpoint_) + peer_endpoint_->resize(addrlen_); + peer_.assign(protocol_, new_socket_.get(), ec_); + if (!ec_) + new_socket_.release(); + } + } + +private: + socket_type socket_; + socket_ops::state_type state_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + socklen_t addrlen_; +}; + +template <typename Socket, typename Protocol, + typename Handler, typename IoExecutor> +class io_uring_socket_accept_op : + public io_uring_socket_accept_op_base<Socket, Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_accept_op); + + io_uring_socket_accept_op(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + : io_uring_socket_accept_op_base<Socket, Protocol>( + success_ec, socket, state, peer, protocol, peer_endpoint, + &io_uring_socket_accept_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_accept_op* o(static_cast<io_uring_socket_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +template <typename Protocol, typename PeerIoExecutor, + typename Handler, typename IoExecutor> +class io_uring_socket_move_accept_op : + private Protocol::socket::template rebind_executor<PeerIoExecutor>::other, + public io_uring_socket_accept_op_base< + typename Protocol::socket::template rebind_executor<PeerIoExecutor>::other, + Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_move_accept_op); + + io_uring_socket_move_accept_op(const asio::error_code& success_ec, + const PeerIoExecutor& peer_io_ex, socket_type socket, + socket_ops::state_type state, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler, + const IoExecutor& io_ex) + : peer_socket_type(peer_io_ex), + io_uring_socket_accept_op_base<peer_socket_type, Protocol>( + success_ec, socket, state, *this, protocol, peer_endpoint, + &io_uring_socket_move_accept_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_move_accept_op* o( + static_cast<io_uring_socket_move_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2<Handler, + asio::error_code, peer_socket_type> + handler(0, static_cast<Handler&&>(o->handler_), o->ec_, + static_cast<peer_socket_type&&>(*o)); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + typedef typename Protocol::socket::template + rebind_executor<PeerIoExecutor>::other peer_socket_type; + + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_ACCEPT_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_connect_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_connect_op.hpp new file mode 100644 index 00000000000..45d30c6bb0a --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_connect_op.hpp @@ -0,0 +1,140 @@ +// +// detail/io_uring_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_CONNECT_OP_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/socket_ops.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class io_uring_socket_connect_op_base : public io_uring_operation +{ +public: + io_uring_socket_connect_op_base(const asio::error_code& success_ec, + socket_type socket, const typename Protocol::endpoint& endpoint, + func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_socket_connect_op_base::do_prepare, + &io_uring_socket_connect_op_base::do_perform, complete_func), + socket_(socket), + endpoint_(endpoint) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_socket_connect_op_base* o( + static_cast<io_uring_socket_connect_op_base*>(base)); + + ::io_uring_prep_connect(sqe, o->socket_, + static_cast<sockaddr*>(o->endpoint_.data()), + static_cast<socklen_t>(o->endpoint_.size())); + } + + static bool do_perform(io_uring_operation*, bool after_completion) + { + return after_completion; + } + +private: + socket_type socket_; + typename Protocol::endpoint endpoint_; +}; + +template <typename Protocol, typename Handler, typename IoExecutor> +class io_uring_socket_connect_op : + public io_uring_socket_connect_op_base<Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_connect_op); + + io_uring_socket_connect_op(const asio::error_code& success_ec, + socket_type socket, const typename Protocol::endpoint& endpoint, + Handler& handler, const IoExecutor& io_ex) + : io_uring_socket_connect_op_base<Protocol>(success_ec, socket, + endpoint, &io_uring_socket_connect_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_connect_op* o + (static_cast<io_uring_socket_connect_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_CONNECT_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_recv_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_recv_op.hpp new file mode 100644 index 00000000000..b1936c1ab93 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_recv_op.hpp @@ -0,0 +1,205 @@ +// +// detail/io_uring_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_RECV_OP_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class io_uring_socket_recv_op_base : public io_uring_operation +{ +public: + io_uring_socket_recv_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_socket_recv_op_base::do_prepare, + &io_uring_socket_recv_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags), + bufs_(buffers), + msghdr_() + { + msghdr_.msg_iov = bufs_.buffers(); + msghdr_.msg_iovlen = static_cast<int>(bufs_.count()); + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_socket_recv_op_base* o( + static_cast<io_uring_socket_recv_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + bool except_op = (o->flags_ & socket_base::message_out_of_band) != 0; + ::io_uring_prep_poll_add(sqe, o->socket_, except_op ? POLLPRI : POLLIN); + } + else if (o->bufs_.is_single_buffer + && o->bufs_.is_registered_buffer && o->flags_ == 0) + { + ::io_uring_prep_read_fixed(sqe, o->socket_, + o->bufs_.buffers()->iov_base, o->bufs_.buffers()->iov_len, + 0, o->bufs_.registered_id().native_handle()); + } + else + { + ::io_uring_prep_recvmsg(sqe, o->socket_, &o->msghdr_, o->flags_); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_socket_recv_op_base* o( + static_cast<io_uring_socket_recv_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + bool except_op = (o->flags_ & socket_base::message_out_of_band) != 0; + if (after_completion || !except_op) + { + if (o->bufs_.is_single_buffer) + { + return socket_ops::non_blocking_recv1(o->socket_, + o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_); + } + else + { + return socket_ops::non_blocking_recv(o->socket_, + o->bufs_.buffers(), o->bufs_.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_); + } + } + } + else if (after_completion) + { + if (!o->ec_ && o->bytes_transferred_ == 0) + if ((o->state_ & socket_ops::stream_oriented) != 0) + o->ec_ = asio::error::eof; + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= socket_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_; + msghdr msghdr_; +}; + +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> +class io_uring_socket_recv_op + : public io_uring_socket_recv_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_recv_op); + + io_uring_socket_recv_op(const asio::error_code& success_ec, + int socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : io_uring_socket_recv_op_base<MutableBufferSequence>(success_ec, + socket, state, buffers, flags, &io_uring_socket_recv_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_recv_op* o + (static_cast<io_uring_socket_recv_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_RECV_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_recvfrom_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_recvfrom_op.hpp new file mode 100644 index 00000000000..dfd30e4f2a1 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_recvfrom_op.hpp @@ -0,0 +1,206 @@ +// +// detail/io_uring_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_RECVFROM_OP_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence, typename Endpoint> +class io_uring_socket_recvfrom_op_base : public io_uring_operation +{ +public: + io_uring_socket_recvfrom_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_socket_recvfrom_op_base::do_prepare, + &io_uring_socket_recvfrom_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags), + bufs_(buffers), + msghdr_() + { + msghdr_.msg_iov = bufs_.buffers(); + msghdr_.msg_iovlen = static_cast<int>(bufs_.count()); + msghdr_.msg_name = static_cast<sockaddr*>( + static_cast<void*>(sender_endpoint_.data())); + msghdr_.msg_namelen = sender_endpoint_.capacity(); + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_socket_recvfrom_op_base* o( + static_cast<io_uring_socket_recvfrom_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + bool except_op = (o->flags_ & socket_base::message_out_of_band) != 0; + ::io_uring_prep_poll_add(sqe, o->socket_, except_op ? POLLPRI : POLLIN); + } + else + { + ::io_uring_prep_recvmsg(sqe, o->socket_, &o->msghdr_, o->flags_); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_socket_recvfrom_op_base* o( + static_cast<io_uring_socket_recvfrom_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + bool except_op = (o->flags_ & socket_base::message_out_of_band) != 0; + if (after_completion || !except_op) + { + std::size_t addr_len = o->sender_endpoint_.capacity(); + bool result; + if (o->bufs_.is_single_buffer) + { + result = socket_ops::non_blocking_recvfrom1(o->socket_, + o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_); + } + else + { + result = socket_ops::non_blocking_recvfrom(o->socket_, + o->bufs_.buffers(), o->bufs_.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_); + } + if (result && !o->ec_) + o->sender_endpoint_.resize(addr_len); + } + } + else if (after_completion && !o->ec_) + o->sender_endpoint_.resize(o->msghdr_.msg_namelen); + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= socket_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + Endpoint& sender_endpoint_; + socket_base::message_flags flags_; + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_; + msghdr msghdr_; +}; + +template <typename MutableBufferSequence, typename Endpoint, + typename Handler, typename IoExecutor> +class io_uring_socket_recvfrom_op + : public io_uring_socket_recvfrom_op_base<MutableBufferSequence, Endpoint> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_recvfrom_op); + + io_uring_socket_recvfrom_op(const asio::error_code& success_ec, + int socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : io_uring_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>( + success_ec, socket, state, buffers, endpoint, flags, + &io_uring_socket_recvfrom_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_recvfrom_op* o + (static_cast<io_uring_socket_recvfrom_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_RECVFROM_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_recvmsg_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_recvmsg_op.hpp new file mode 100644 index 00000000000..778d0fa3acf --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_recvmsg_op.hpp @@ -0,0 +1,192 @@ +// +// detail/io_uring_socket_recvmsg_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_RECVMSG_OP_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_RECVMSG_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename MutableBufferSequence> +class io_uring_socket_recvmsg_op_base : public io_uring_operation +{ +public: + io_uring_socket_recvmsg_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_socket_recvmsg_op_base::do_prepare, + &io_uring_socket_recvmsg_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + in_flags_(in_flags), + out_flags_(out_flags), + bufs_(buffers), + msghdr_() + { + msghdr_.msg_iov = bufs_.buffers(); + msghdr_.msg_iovlen = static_cast<int>(bufs_.count()); + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_socket_recvmsg_op_base* o( + static_cast<io_uring_socket_recvmsg_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + bool except_op = (o->in_flags_ & socket_base::message_out_of_band) != 0; + ::io_uring_prep_poll_add(sqe, o->socket_, except_op ? POLLPRI : POLLIN); + } + else + { + ::io_uring_prep_recvmsg(sqe, o->socket_, &o->msghdr_, o->in_flags_); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_socket_recvmsg_op_base* o( + static_cast<io_uring_socket_recvmsg_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + bool except_op = (o->in_flags_ & socket_base::message_out_of_band) != 0; + if (after_completion || !except_op) + { + return socket_ops::non_blocking_recvmsg(o->socket_, + o->bufs_.buffers(), o->bufs_.count(), o->in_flags_, + o->out_flags_, o->ec_, o->bytes_transferred_); + } + } + else if (after_completion) + { + if (!o->ec_) + o->out_flags_ = o->msghdr_.msg_flags; + else + o->out_flags_ = 0; + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= socket_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags in_flags_; + socket_base::message_flags& out_flags_; + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_; + msghdr msghdr_; +}; + +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> +class io_uring_socket_recvmsg_op + : public io_uring_socket_recvmsg_op_base<MutableBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_recvmsg_op); + + io_uring_socket_recvmsg_op(const asio::error_code& success_ec, + int socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, + Handler& handler, const IoExecutor& io_ex) + : io_uring_socket_recvmsg_op_base<MutableBufferSequence>(success_ec, + socket, state, buffers, in_flags, out_flags, + &io_uring_socket_recvmsg_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_recvmsg_op* o + (static_cast<io_uring_socket_recvmsg_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_RECVMSG_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_send_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_send_op.hpp new file mode 100644 index 00000000000..2f57dae920d --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_send_op.hpp @@ -0,0 +1,191 @@ +// +// detail/io_uring_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_SEND_OP_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence> +class io_uring_socket_send_op_base : public io_uring_operation +{ +public: + io_uring_socket_send_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_socket_send_op_base::do_prepare, + &io_uring_socket_send_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags), + bufs_(buffers), + msghdr_() + { + msghdr_.msg_iov = bufs_.buffers(); + msghdr_.msg_iovlen = static_cast<int>(bufs_.count()); + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_socket_send_op_base* o( + static_cast<io_uring_socket_send_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + ::io_uring_prep_poll_add(sqe, o->socket_, POLLOUT); + } + else if (o->bufs_.is_single_buffer + && o->bufs_.is_registered_buffer && o->flags_ == 0) + { + ::io_uring_prep_write_fixed(sqe, o->socket_, + o->bufs_.buffers()->iov_base, o->bufs_.buffers()->iov_len, + 0, o->bufs_.registered_id().native_handle()); + } + else + { + ::io_uring_prep_sendmsg(sqe, o->socket_, &o->msghdr_, o->flags_); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_socket_send_op_base* o( + static_cast<io_uring_socket_send_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + if (o->bufs_.is_single_buffer) + { + return socket_ops::non_blocking_send1(o->socket_, + o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->flags_, + o->ec_, o->bytes_transferred_); + } + else + { + return socket_ops::non_blocking_send(o->socket_, + o->bufs_.buffers(), o->bufs_.count(), o->flags_, + o->ec_, o->bytes_transferred_); + } + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= socket_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; + buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs_; + msghdr msghdr_; +}; + +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> +class io_uring_socket_send_op + : public io_uring_socket_send_op_base<ConstBufferSequence> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_send_op); + + io_uring_socket_send_op(const asio::error_code& success_ec, + int socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : io_uring_socket_send_op_base<ConstBufferSequence>(success_ec, + socket, state, buffers, flags, &io_uring_socket_send_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_send_op* o + (static_cast<io_uring_socket_send_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_SEND_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_sendto_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_sendto_op.hpp new file mode 100644 index 00000000000..1866938a4b4 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_sendto_op.hpp @@ -0,0 +1,194 @@ +// +// detail/io_uring_socket_sendto_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_SENDTO_OP_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_SENDTO_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename ConstBufferSequence, typename Endpoint> +class io_uring_socket_sendto_op_base : public io_uring_operation +{ +public: + io_uring_socket_sendto_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : io_uring_operation(success_ec, + &io_uring_socket_sendto_op_base::do_prepare, + &io_uring_socket_sendto_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + destination_(endpoint), + flags_(flags), + bufs_(buffers), + msghdr_() + { + msghdr_.msg_iov = bufs_.buffers(); + msghdr_.msg_iovlen = static_cast<int>(bufs_.count()); + msghdr_.msg_name = static_cast<sockaddr*>( + static_cast<void*>(destination_.data())); + msghdr_.msg_namelen = destination_.size(); + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_socket_sendto_op_base* o( + static_cast<io_uring_socket_sendto_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + ::io_uring_prep_poll_add(sqe, o->socket_, POLLOUT); + } + else + { + ::io_uring_prep_sendmsg(sqe, o->socket_, &o->msghdr_, o->flags_); + } + } + + static bool do_perform(io_uring_operation* base, bool after_completion) + { + ASIO_ASSUME(base != 0); + io_uring_socket_sendto_op_base* o( + static_cast<io_uring_socket_sendto_op_base*>(base)); + + if ((o->state_ & socket_ops::internal_non_blocking) != 0) + { + if (o->bufs_.is_single_buffer) + { + return socket_ops::non_blocking_sendto1(o->socket_, + o->bufs_.first(o->buffers_).data(), + o->bufs_.first(o->buffers_).size(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_); + } + else + { + return socket_ops::non_blocking_sendto(o->socket_, + o->bufs_.buffers(), o->bufs_.count(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_); + } + } + + if (o->ec_ && o->ec_ == asio::error::would_block) + { + o->state_ |= socket_ops::internal_non_blocking; + return false; + } + + return after_completion; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + ConstBufferSequence buffers_; + Endpoint destination_; + socket_base::message_flags flags_; + buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs_; + msghdr msghdr_; +}; + +template <typename ConstBufferSequence, typename Endpoint, + typename Handler, typename IoExecutor> +class io_uring_socket_sendto_op + : public io_uring_socket_sendto_op_base<ConstBufferSequence, Endpoint> +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_socket_sendto_op); + + io_uring_socket_sendto_op(const asio::error_code& success_ec, + int socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : io_uring_socket_sendto_op_base<ConstBufferSequence, Endpoint>( + success_ec, socket, state, buffers, endpoint, flags, + &io_uring_socket_sendto_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_socket_sendto_op* o + (static_cast<io_uring_socket_sendto_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_SENDTO_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_service.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_service.hpp new file mode 100644 index 00000000000..3daa22ef797 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_service.hpp @@ -0,0 +1,629 @@ +// +// detail/io_uring_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_SERVICE_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/io_uring_null_buffers_op.hpp" +#include "asio/detail/io_uring_service.hpp" +#include "asio/detail/io_uring_socket_accept_op.hpp" +#include "asio/detail/io_uring_socket_connect_op.hpp" +#include "asio/detail/io_uring_socket_recvfrom_op.hpp" +#include "asio/detail/io_uring_socket_sendto_op.hpp" +#include "asio/detail/io_uring_socket_service_base.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Protocol> +class io_uring_socket_service : + public execution_context_service_base<io_uring_socket_service<Protocol>>, + public io_uring_socket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct implementation_type : + io_uring_socket_service_base::base_implementation_type + { + // Default constructor. + implementation_type() + : protocol_(endpoint_type().protocol()) + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + }; + + // Constructor. + io_uring_socket_service(execution_context& context) + : execution_context_service_base< + io_uring_socket_service<Protocol>>(context), + io_uring_socket_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) noexcept + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + io_uring_socket_service_base& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-construct a new socket implementation from another protocol type. + template <typename Protocol1> + void converting_move_construct(implementation_type& impl, + io_uring_socket_service<Protocol1>&, + typename io_uring_socket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + } + + // Open a new socket implementation. + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) + { + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + impl.protocol_ = protocol; + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Assign a native socket to a socket implementation. + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + asio::error_code& ec) + { + if (!do_assign(impl, protocol.type(), native_socket, ec)) + impl.protocol_ = protocol; + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type& impl) + { + return impl.socket_; + } + + // Bind the socket to the specified local endpoint. + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) + { + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) + { + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Set a socket option. + template <typename Option> + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + { + ASIO_ERROR_LOCATION(ec); + return endpoint_type(); + } + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, + endpoint.data(), &addr_len, false, ec)) + { + ASIO_ERROR_LOCATION(ec); + return endpoint_type(); + } + endpoint.resize(addr_len); + return endpoint; + } + + // Disable sends or receives on the socket. + asio::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template <typename ConstBufferSequence> + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; + + size_t n; + if (bufs_type::is_single_buffer) + { + n = socket_ops::sync_sendto1(impl.socket_, impl.state_, + bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, + destination.data(), destination.size(), ec); + } + else + { + bufs_type bufs(buffers); + n = socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + + ASIO_ERROR_LOCATION(ec); + return n; + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + ASIO_ERROR_LOCATION(ec); + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_sendto_op<ConstBufferSequence, + endpoint_type, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, + buffers, destination, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_send_to")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler, typename IoExecutor> + void async_send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_null_buffers_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, POLLOUT, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template <typename MutableBufferSequence> + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; + + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t n; + if (bufs_type::is_single_buffer) + { + n = socket_ops::sync_recvfrom1(impl.socket_, impl.state_, + bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), + flags, sender_endpoint.data(), &addr_len, ec); + } + else + { + bufs_type bufs(buffers); + n = socket_ops::sync_recvfrom(impl.socket_, impl.state_, bufs.buffers(), + bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); + } + + if (!ec) + sender_endpoint.resize(addr_len); + + ASIO_ERROR_LOCATION(ec); + return n; + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags, + asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + ASIO_ERROR_LOCATION(ec); + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + int op_type = (flags & socket_base::message_out_of_band) + ? io_uring_service::except_op : io_uring_service::read_op; + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_recvfrom_op<MutableBufferSequence, + endpoint_type, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, + buffers, sender_endpoint, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_receive_from")); + + start_op(impl, op_type, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler, typename IoExecutor> + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + int op_type; + int poll_flags; + if ((flags & socket_base::message_out_of_band) != 0) + { + op_type = io_uring_service::except_op; + poll_flags = POLLPRI; + } + else + { + op_type = io_uring_service::read_op; + poll_flags = POLLIN; + } + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_null_buffers_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, poll_flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_op(impl, op_type, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Accept a new connection. + template <typename Socket> + asio::error_code accept(implementation_type& impl, + Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) + { + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); + return ec; + } + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + ASIO_ERROR_LOCATION(ec); + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects must be + // valid until the accept's handler is invoked. + template <typename Socket, typename Handler, typename IoExecutor> + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, + peer, impl.protocol_, peer_endpoint, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected() && !peer.is_open()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::read_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, peer.is_open()); + p.v = p.p = 0; + } + + // Start an asynchronous accept. The peer_endpoint object must be valid until + // the accept's handler is invoked. + template <typename PeerIoExecutor, typename Handler, typename IoExecutor> + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_move_accept_op<Protocol, + PeerIoExecutor, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_, + impl.state_, impl.protocol_, peer_endpoint, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::read_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Connect the socket to the specified endpoint. + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) + { + socket_ops::sync_connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; + } + + // Start an asynchronous connect. + template <typename Handler, typename IoExecutor> + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_connect_op<Protocol, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + peer_endpoint, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_connect")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, false); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_socket_service_base.hpp b/3rdparty/asio/include/asio/detail/io_uring_socket_service_base.hpp new file mode 100644 index 00000000000..99b075c9fe5 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_socket_service_base.hpp @@ -0,0 +1,663 @@ +// +// detail/io_uring_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_SOCKET_SERVICE_BASE_HPP +#define ASIO_DETAIL_IO_URING_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IO_URING) + +#include "asio/associated_cancellation_slot.hpp" +#include "asio/buffer.hpp" +#include "asio/cancellation_type.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/socket_base.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/io_uring_null_buffers_op.hpp" +#include "asio/detail/io_uring_service.hpp" +#include "asio/detail/io_uring_socket_recv_op.hpp" +#include "asio/detail/io_uring_socket_recvmsg_op.hpp" +#include "asio/detail/io_uring_socket_send_op.hpp" +#include "asio/detail/io_uring_wait_op.hpp" +#include "asio/detail/socket_holder.hpp" +#include "asio/detail/socket_ops.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class io_uring_socket_service_base +{ +public: + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // Per I/O object data used by the io_uring_service. + io_uring_service::per_io_object_data io_object_data_; + }; + + // Constructor. + ASIO_DECL io_uring_socket_service_base(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + ASIO_DECL void construct(base_implementation_type& impl); + + // Move-construct a new socket implementation. + ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl) noexcept; + + // Move-assign from another socket implementation. + ASIO_DECL void base_move_assign(base_implementation_type& impl, + io_uring_socket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + ASIO_DECL asio::error_code close( + base_implementation_type& impl, asio::error_code& ec); + + // Release ownership of the socket. + ASIO_DECL socket_type release( + base_implementation_type& impl, asio::error_code& ec); + + // Get the native socket representation. + native_handle_type native_handle(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + ASIO_DECL asio::error_code cancel( + base_implementation_type& impl, asio::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + asio::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + asio::error_code listen(base_implementation_type& impl, + int backlog, asio::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template <typename IO_Control_Command> + asio::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast<ioctl_arg_type*>(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the socket. + asio::error_code non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native socket implementation. + asio::error_code native_non_blocking(base_implementation_type& impl, + bool mode, asio::error_code& ec) + { + socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + asio::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, asio::error_code& ec) + { + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler, typename IoExecutor> + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + int op_type; + int poll_flags; + switch (w) + { + case socket_base::wait_read: + op_type = io_uring_service::read_op; + poll_flags = POLLIN; + break; + case socket_base::wait_write: + op_type = io_uring_service::write_op; + poll_flags = POLLOUT; + break; + case socket_base::wait_error: + op_type = io_uring_service::except_op; + poll_flags = POLLPRI | POLLERR | POLLHUP; + break; + default: + op_type = -1; + poll_flags = -1; + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_wait_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + poll_flags, handler, io_ex); + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_wait")); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + start_op(impl, op_type, p.p, is_continuation, op_type == -1); + p.v = p.p = 0; + } + + // Send the given data to the peer. + template <typename ConstBufferSequence> + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; + + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_send1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_send")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template <typename Handler, typename IoExecutor> + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_null_buffers_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, POLLOUT, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>(&io_uring_service_, + &impl.io_object_data_, io_uring_service::write_op); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_send(null_buffers)")); + + start_op(impl, io_uring_service::write_op, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template <typename MutableBufferSequence> + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; + + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_recv1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + int op_type = (flags & socket_base::message_out_of_band) + ? io_uring_service::except_op : io_uring_service::read_op; + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_recv_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_receive")); + + start_op(impl, op_type, p.p, is_continuation, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence>::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler, typename IoExecutor> + void async_receive(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + int op_type; + int poll_flags; + if ((flags & socket_base::message_out_of_band) != 0) + { + op_type = io_uring_service::except_op; + poll_flags = POLLPRI; + } + else + { + op_type = io_uring_service::read_op; + poll_flags = POLLIN; + } + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_null_buffers_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, poll_flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_receive(null_buffers)")); + + start_op(impl, op_type, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template <typename MutableBufferSequence> + size_t receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs(buffers); + + return socket_ops::sync_recvmsg(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), in_flags, out_flags, ec); + } + + // Wait until data can be received without blocking. + size_t receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + int op_type = (in_flags & socket_base::message_out_of_band) + ? io_uring_service::except_op : io_uring_service::read_op; + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_socket_recvmsg_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, + buffers, in_flags, out_flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, + "socket", &impl, impl.socket_, "async_receive_with_flags")); + + start_op(impl, op_type, p.p, is_continuation, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template <typename Handler, typename IoExecutor> + void async_receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + int op_type; + int poll_flags; + if ((in_flags & socket_base::message_out_of_band) != 0) + { + op_type = io_uring_service::except_op; + poll_flags = POLLPRI; + } + else + { + op_type = io_uring_service::read_op; + poll_flags = POLLIN; + } + + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef io_uring_null_buffers_op<Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(success_ec_, impl.socket_, poll_flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<io_uring_op_cancellation>( + &io_uring_service_, &impl.io_object_data_, op_type); + } + + ASIO_HANDLER_CREATION((io_uring_service_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + start_op(impl, op_type, p.p, is_continuation, false); + p.v = p.p = 0; + } + +protected: + // Open a new socket implementation. + ASIO_DECL asio::error_code do_open( + base_implementation_type& impl, int af, + int type, int protocol, asio::error_code& ec); + + // Assign a native socket to a socket implementation. + ASIO_DECL asio::error_code do_assign( + base_implementation_type& impl, int type, + const native_handle_type& native_socket, asio::error_code& ec); + + // Start the asynchronous read or write operation. + ASIO_DECL void start_op(base_implementation_type& impl, int op_type, + io_uring_operation* op, bool is_continuation, bool noop); + + // Start the asynchronous accept operation. + ASIO_DECL void start_accept_op(base_implementation_type& impl, + io_uring_operation* op, bool is_continuation, bool peer_is_open); + + // Helper class used to implement per-operation cancellation + class io_uring_op_cancellation + { + public: + io_uring_op_cancellation(io_uring_service* s, + io_uring_service::per_io_object_data* p, int o) + : io_uring_service_(s), + io_object_data_(p), + op_type_(o) + { + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + io_uring_service_->cancel_ops_by_key(*io_object_data_, op_type_, this); + } + } + + private: + io_uring_service* io_uring_service_; + io_uring_service::per_io_object_data* io_object_data_; + int op_type_; + }; + + // The io_uring_service that performs event demultiplexing for the service. + io_uring_service& io_uring_service_; + + // Cached success value to avoid accessing category singleton. + const asio::error_code success_ec_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/io_uring_socket_service_base.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IO_URING) + +#endif // ASIO_DETAIL_IO_URING_SOCKET_SERVICE_BASE_HPP diff --git a/3rdparty/asio/include/asio/detail/io_uring_wait_op.hpp b/3rdparty/asio/include/asio/detail/io_uring_wait_op.hpp new file mode 100644 index 00000000000..4dec72ce42c --- /dev/null +++ b/3rdparty/asio/include/asio/detail/io_uring_wait_op.hpp @@ -0,0 +1,112 @@ +// +// detail/io_uring_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IO_URING_WAIT_OP_HPP +#define ASIO_DETAIL_IO_URING_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" +#include "asio/detail/io_uring_operation.hpp" +#include "asio/detail/memory.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Handler, typename IoExecutor> +class io_uring_wait_op : public io_uring_operation +{ +public: + ASIO_DEFINE_HANDLER_PTR(io_uring_wait_op); + + io_uring_wait_op(const asio::error_code& success_ec, int descriptor, + int poll_flags, Handler& handler, const IoExecutor& io_ex) + : io_uring_operation(success_ec, &io_uring_wait_op::do_prepare, + &io_uring_wait_op::do_perform, &io_uring_wait_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex), + descriptor_(descriptor), + poll_flags_(poll_flags) + { + } + + static void do_prepare(io_uring_operation* base, ::io_uring_sqe* sqe) + { + ASIO_ASSUME(base != 0); + io_uring_wait_op* o(static_cast<io_uring_wait_op*>(base)); + + ::io_uring_prep_poll_add(sqe, o->descriptor_, o->poll_flags_); + } + + static bool do_perform(io_uring_operation*, bool after_completion) + { + return after_completion; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + io_uring_wait_op* o(static_cast<io_uring_wait_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + handler_work<Handler, IoExecutor> work_; + int descriptor_; + int poll_flags_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_IO_URING_WAIT_OP_HPP diff --git a/3rdparty/asio/include/asio/detail/is_buffer_sequence.hpp b/3rdparty/asio/include/asio/detail/is_buffer_sequence.hpp index 95f29c503fd..c64e7b16824 100644 --- a/3rdparty/asio/include/asio/detail/is_buffer_sequence.hpp +++ b/3rdparty/asio/include/asio/detail/is_buffer_sequence.hpp @@ -2,7 +2,7 @@ // detail/is_buffer_sequence.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -24,6 +24,8 @@ namespace asio { class mutable_buffer; class const_buffer; +class mutable_registered_buffer; +class const_registered_buffer; namespace detail { @@ -38,6 +40,8 @@ struct buffer_sequence_memfns_base void prepare(); void commit(); void consume(); + void grow(); + void shrink(); }; template <typename T> @@ -52,22 +56,22 @@ struct buffer_sequence_memfns_check }; template <typename> -char (&begin_memfn_helper(...))[2]; +char buffer_sequence_begin_helper(...); template <typename T> -char begin_memfn_helper( - buffer_sequence_memfns_check< - void (buffer_sequence_memfns_base::*)(), - &buffer_sequence_memfns_derived<T>::begin>*); +char (&buffer_sequence_begin_helper(T* t, + enable_if_t<!is_same< + decltype(asio::buffer_sequence_begin(*t)), + void>::value>*))[2]; template <typename> -char (&end_memfn_helper(...))[2]; +char buffer_sequence_end_helper(...); template <typename T> -char end_memfn_helper( - buffer_sequence_memfns_check< - void (buffer_sequence_memfns_base::*)(), - &buffer_sequence_memfns_derived<T>::end>*); +char (&buffer_sequence_end_helper(T* t, + enable_if_t<!is_same< + decltype(asio::buffer_sequence_end(*t)), + void>::value>*))[2]; template <typename> char (&size_memfn_helper(...))[2]; @@ -112,7 +116,7 @@ template <typename T> char prepare_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), - &buffer_sequence_memfns_derived<T>::data>*); + &buffer_sequence_memfns_derived<T>::prepare>*); template <typename> char (&commit_memfn_helper(...))[2]; @@ -132,26 +136,32 @@ char consume_memfn_helper( void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::consume>*); -template <typename, typename> -char (&buffer_element_type_helper(...))[2]; +template <typename> +char (&grow_memfn_helper(...))[2]; -#if defined(ASIO_HAS_DECL_TYPE) +template <typename T> +char grow_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::grow>*); -template <typename T, typename Buffer> -char buffer_element_type_helper(T* t, - typename enable_if<is_convertible< - decltype(*buffer_sequence_begin(*t)), - Buffer>::value>::type*); +template <typename> +char (&shrink_memfn_helper(...))[2]; + +template <typename T> +char shrink_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::shrink>*); -#else // defined(ASIO_HAS_DECL_TYPE) +template <typename, typename> +char (&buffer_sequence_element_type_helper(...))[2]; template <typename T, typename Buffer> -char buffer_element_type_helper( - typename T::const_iterator*, - typename enable_if<is_convertible< - typename T::value_type, Buffer>::value>::type*); - -#endif // defined(ASIO_HAS_DECL_TYPE) +char buffer_sequence_element_type_helper(T* t, + enable_if_t<is_convertible< + decltype(*asio::buffer_sequence_begin(*t)), + Buffer>::value>*); template <typename> char (&const_buffers_type_typedef_helper(...))[2]; @@ -170,9 +180,9 @@ char mutable_buffers_type_typedef_helper( template <typename T, typename Buffer> struct is_buffer_sequence_class : integral_constant<bool, - sizeof(begin_memfn_helper<T>(0)) != 1 && - sizeof(end_memfn_helper<T>(0)) != 1 && - sizeof(buffer_element_type_helper<T, Buffer>(0, 0)) == 1> + sizeof(buffer_sequence_begin_helper<T>(0, 0)) != 1 && + sizeof(buffer_sequence_end_helper<T>(0, 0)) != 1 && + sizeof(buffer_sequence_element_type_helper<T, Buffer>(0, 0)) == 1> { }; @@ -208,8 +218,32 @@ struct is_buffer_sequence<const_buffer, mutable_buffer> { }; +template <> +struct is_buffer_sequence<mutable_registered_buffer, mutable_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<mutable_registered_buffer, const_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<const_registered_buffer, const_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<const_registered_buffer, mutable_buffer> + : false_type +{ +}; + template <typename T> -struct is_dynamic_buffer_class +struct is_dynamic_buffer_class_v1 : integral_constant<bool, sizeof(size_memfn_helper<T>(0)) != 1 && sizeof(max_size_memfn_helper<T>(0)) != 1 && @@ -224,9 +258,32 @@ struct is_dynamic_buffer_class }; template <typename T> -struct is_dynamic_buffer +struct is_dynamic_buffer_v1 + : conditional<is_class<T>::value, + is_dynamic_buffer_class_v1<T>, + false_type>::type +{ +}; + +template <typename T> +struct is_dynamic_buffer_class_v2 + : integral_constant<bool, + sizeof(size_memfn_helper<T>(0)) != 1 && + sizeof(max_size_memfn_helper<T>(0)) != 1 && + sizeof(capacity_memfn_helper<T>(0)) != 1 && + sizeof(data_memfn_helper<T>(0)) != 1 && + sizeof(consume_memfn_helper<T>(0)) != 1 && + sizeof(grow_memfn_helper<T>(0)) != 1 && + sizeof(shrink_memfn_helper<T>(0)) != 1 && + sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1> +{ +}; + +template <typename T> +struct is_dynamic_buffer_v2 : conditional<is_class<T>::value, - is_dynamic_buffer_class<T>, + is_dynamic_buffer_class_v2<T>, false_type>::type { }; diff --git a/3rdparty/asio/include/asio/detail/is_executor.hpp b/3rdparty/asio/include/asio/detail/is_executor.hpp index ec0ee001bbc..2636f9c66f3 100644 --- a/3rdparty/asio/include/asio/detail/is_executor.hpp +++ b/3rdparty/asio/include/asio/detail/is_executor.hpp @@ -2,7 +2,7 @@ // detail/is_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/keyword_tss_ptr.hpp b/3rdparty/asio/include/asio/detail/keyword_tss_ptr.hpp index c1f9b93131d..2e42df8b358 100644 --- a/3rdparty/asio/include/asio/detail/keyword_tss_ptr.hpp +++ b/3rdparty/asio/include/asio/detail/keyword_tss_ptr.hpp @@ -2,7 +2,7 @@ // detail/keyword_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/kqueue_reactor.hpp b/3rdparty/asio/include/asio/detail/kqueue_reactor.hpp index 8d1c66737d5..f034410d6d5 100644 --- a/3rdparty/asio/include/asio/detail/kqueue_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/kqueue_reactor.hpp @@ -2,7 +2,7 @@ // detail/kqueue_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -24,11 +24,12 @@ #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> +#include "asio/detail/conditionally_enabled_mutex.hpp" #include "asio/detail/limits.hpp" -#include "asio/detail/mutex.hpp" #include "asio/detail/object_pool.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" +#include "asio/detail/scheduler_task.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_queue_base.hpp" @@ -50,7 +51,8 @@ namespace detail { class scheduler; class kqueue_reactor - : public execution_context_service_base<kqueue_reactor> + : public execution_context_service_base<kqueue_reactor>, + public scheduler_task { private: // The mutex type used by this reactor. @@ -114,16 +116,30 @@ public: per_descriptor_data& source_descriptor_data); // Post a reactor operation for immediate completion. - void post_immediate_completion(reactor_op* op, bool is_continuation) - { - scheduler_.post_immediate_completion(op, is_continuation); - } + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative); + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &kqueue_reactor::call_post_immediate_completion, this); + } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the @@ -131,15 +147,30 @@ public: ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data); + // Cancel all operations associated with the given descriptor and key. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops_by_key(socket_type descriptor, + per_descriptor_data& descriptor_data, + int op_type, void* cancellation_key); + // Cancel any operations that are running against the descriptor and remove - // its registration from the reactor. + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. ASIO_DECL void deregister_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data, bool closing); - // Remote the descriptor's registration from the reactor. + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. ASIO_DECL void deregister_internal_descriptor( socket_type descriptor, per_descriptor_data& descriptor_data); + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + // Add a new timer queue to the reactor. template <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& queue); @@ -162,6 +193,12 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Cancel the timer operations associated with the given key. + template <typename Time_Traits> + void cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key); + // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, diff --git a/3rdparty/asio/include/asio/detail/limits.hpp b/3rdparty/asio/include/asio/detail/limits.hpp index d32470d2d35..323af22b300 100644 --- a/3rdparty/asio/include/asio/detail/limits.hpp +++ b/3rdparty/asio/include/asio/detail/limits.hpp @@ -16,11 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_BOOST_LIMITS) -# include <boost/limits.hpp> -#else // defined(ASIO_HAS_BOOST_LIMITS) -# include <limits> -#endif // defined(ASIO_HAS_BOOST_LIMITS) +#include <limits> #endif // ASIO_DETAIL_LIMITS_HPP diff --git a/3rdparty/asio/include/asio/detail/local_free_on_block_exit.hpp b/3rdparty/asio/include/asio/detail/local_free_on_block_exit.hpp index a0ea47cceff..212f9c1bcd2 100644 --- a/3rdparty/asio/include/asio/detail/local_free_on_block_exit.hpp +++ b/3rdparty/asio/include/asio/detail/local_free_on_block_exit.hpp @@ -2,7 +2,7 @@ // detail/local_free_on_block_exit.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/macos_fenced_block.hpp b/3rdparty/asio/include/asio/detail/macos_fenced_block.hpp deleted file mode 100644 index e44b900bbda..00000000000 --- a/3rdparty/asio/include/asio/detail/macos_fenced_block.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// detail/macos_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_MACOS_FENCED_BLOCK_HPP -#define ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(__MACH__) && defined(__APPLE__) - -#include <libkern/OSAtomic.h> -#include "asio/detail/noncopyable.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace detail { - -class macos_fenced_block - : private noncopyable -{ -public: - enum half_t { half }; - enum full_t { full }; - - // Constructor for a half fenced block. - explicit macos_fenced_block(half_t) - { - } - - // Constructor for a full fenced block. - explicit macos_fenced_block(full_t) - { - OSMemoryBarrier(); - } - - // Destructor. - ~macos_fenced_block() - { - OSMemoryBarrier(); - } -}; - -} // namespace detail -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(__MACH__) && defined(__APPLE__) - -#endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/3rdparty/asio/include/asio/detail/memory.hpp b/3rdparty/asio/include/asio/detail/memory.hpp index 51f45329b62..173e49fe065 100644 --- a/3rdparty/asio/include/asio/detail/memory.hpp +++ b/3rdparty/asio/include/asio/detail/memory.hpp @@ -2,7 +2,7 @@ // detail/memory.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,37 +16,49 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include <cstddef> +#include <cstdlib> #include <memory> +#include <new> +#include "asio/detail/cstdint.hpp" +#include "asio/detail/throw_exception.hpp" -#if !defined(ASIO_HAS_STD_SHARED_PTR) -# include <boost/shared_ptr.hpp> -# include <boost/weak_ptr.hpp> -#endif // !defined(ASIO_HAS_STD_SHARED_PTR) - -#if !defined(ASIO_HAS_STD_ADDRESSOF) -# include <boost/utility/addressof.hpp> -#endif // !defined(ASIO_HAS_STD_ADDRESSOF) +#if !defined(ASIO_HAS_STD_ALIGNED_ALLOC) \ + && defined(ASIO_HAS_BOOST_ALIGN) +# include <boost/align/aligned_alloc.hpp> +#endif // !defined(ASIO_HAS_STD_ALIGNED_ALLOC) + // && defined(ASIO_HAS_BOOST_ALIGN) namespace asio { namespace detail { -#if defined(ASIO_HAS_STD_SHARED_PTR) +using std::allocate_shared; +using std::make_shared; using std::shared_ptr; using std::weak_ptr; -#else // defined(ASIO_HAS_STD_SHARED_PTR) -using boost::shared_ptr; -using boost::weak_ptr; -#endif // defined(ASIO_HAS_STD_SHARED_PTR) - -#if defined(ASIO_HAS_STD_ADDRESSOF) using std::addressof; -#else // defined(ASIO_HAS_STD_ADDRESSOF) -using boost::addressof; -#endif // defined(ASIO_HAS_STD_ADDRESSOF) + +#if defined(ASIO_HAS_STD_TO_ADDRESS) +using std::to_address; +#else // defined(ASIO_HAS_STD_TO_ADDRESS) +template <typename T> +inline T* to_address(T* p) { return p; } +template <typename T> +inline const T* to_address(const T* p) { return p; } +template <typename T> +inline volatile T* to_address(volatile T* p) { return p; } +template <typename T> +inline const volatile T* to_address(const volatile T* p) { return p; } +#endif // defined(ASIO_HAS_STD_TO_ADDRESS) + +inline void* align(std::size_t alignment, + std::size_t size, void*& ptr, std::size_t& space) +{ + return std::align(alignment, size, ptr, space); +} } // namespace detail -#if defined(ASIO_HAS_NULLPTR) using std::allocator_arg_t; # define ASIO_USES_ALLOCATOR(t) \ namespace std { \ @@ -54,10 +66,60 @@ using std::allocator_arg_t; struct uses_allocator<t, Allocator> : true_type {}; \ } \ /**/ -#else // defined(ASIO_HAS_NULLPTR) -struct allocator_arg_t {}; -# define ASIO_USES_ALLOCATOR(t) -#endif // defined(ASIO_HAS_NULLPTR) +# define ASIO_REBIND_ALLOC(alloc, t) \ + typename std::allocator_traits<alloc>::template rebind_alloc<t> + /**/ + +inline void* aligned_new(std::size_t align, std::size_t size) +{ +#if defined(ASIO_HAS_STD_ALIGNED_ALLOC) + align = (align < ASIO_DEFAULT_ALIGN) ? ASIO_DEFAULT_ALIGN : align; + size = (size % align == 0) ? size : size + (align - size % align); + void* ptr = std::aligned_alloc(align, size); + if (!ptr) + { + std::bad_alloc ex; + asio::detail::throw_exception(ex); + } + return ptr; +#elif defined(ASIO_HAS_BOOST_ALIGN) + align = (align < ASIO_DEFAULT_ALIGN) ? ASIO_DEFAULT_ALIGN : align; + size = (size % align == 0) ? size : size + (align - size % align); + void* ptr = boost::alignment::aligned_alloc(align, size); + if (!ptr) + { + std::bad_alloc ex; + asio::detail::throw_exception(ex); + } + return ptr; +#elif defined(ASIO_MSVC) + align = (align < ASIO_DEFAULT_ALIGN) ? ASIO_DEFAULT_ALIGN : align; + size = (size % align == 0) ? size : size + (align - size % align); + void* ptr = _aligned_malloc(size, align); + if (!ptr) + { + std::bad_alloc ex; + asio::detail::throw_exception(ex); + } + return ptr; +#else // defined(ASIO_MSVC) + (void)align; + return ::operator new(size); +#endif // defined(ASIO_MSVC) +} + +inline void aligned_delete(void* ptr) +{ +#if defined(ASIO_HAS_STD_ALIGNED_ALLOC) + std::free(ptr); +#elif defined(ASIO_HAS_BOOST_ALIGN) + boost::alignment::aligned_free(ptr); +#elif defined(ASIO_MSVC) + _aligned_free(ptr); +#else // defined(ASIO_MSVC) + ::operator delete(ptr); +#endif // defined(ASIO_MSVC) +} } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/mutex.hpp b/3rdparty/asio/include/asio/detail/mutex.hpp index 9821e818093..e701c238296 100644 --- a/3rdparty/asio/include/asio/detail/mutex.hpp +++ b/3rdparty/asio/include/asio/detail/mutex.hpp @@ -2,7 +2,7 @@ // detail/mutex.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,10 +23,8 @@ # include "asio/detail/win_mutex.hpp" #elif defined(ASIO_HAS_PTHREADS) # include "asio/detail/posix_mutex.hpp" -#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) -# include "asio/detail/std_mutex.hpp" #else -# error Only Windows, POSIX and std::mutex are supported! +# include "asio/detail/std_mutex.hpp" #endif namespace asio { @@ -38,7 +36,7 @@ typedef null_mutex mutex; typedef win_mutex mutex; #elif defined(ASIO_HAS_PTHREADS) typedef posix_mutex mutex; -#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +#else typedef std_mutex mutex; #endif diff --git a/3rdparty/asio/include/asio/detail/non_const_lvalue.hpp b/3rdparty/asio/include/asio/detail/non_const_lvalue.hpp new file mode 100644 index 00000000000..940bf251b71 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/non_const_lvalue.hpp @@ -0,0 +1,43 @@ +// +// detail/non_const_lvalue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_NON_CONST_LVALUE_HPP +#define ASIO_DETAIL_NON_CONST_LVALUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename T> +struct non_const_lvalue +{ + explicit non_const_lvalue(T& t) + : value(static_cast<conditional_t< + is_same<T, decay_t<T>>::value, decay_t<T>&, T&&>>(t)) + { + } + + conditional_t<is_same<T, decay_t<T>>::value, decay_t<T>&, decay_t<T>> value; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_NON_CONST_LVALUE_HPP diff --git a/3rdparty/asio/include/asio/detail/noncopyable.hpp b/3rdparty/asio/include/asio/detail/noncopyable.hpp index 31f646a5655..7b80a89457a 100644 --- a/3rdparty/asio/include/asio/detail/noncopyable.hpp +++ b/3rdparty/asio/include/asio/detail/noncopyable.hpp @@ -2,7 +2,7 @@ // detail/noncopyable.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/null_event.hpp b/3rdparty/asio/include/asio/detail/null_event.hpp index 465a701123b..d50724c9e5b 100644 --- a/3rdparty/asio/include/asio/detail/null_event.hpp +++ b/3rdparty/asio/include/asio/detail/null_event.hpp @@ -2,7 +2,7 @@ // detail/null_event.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -55,6 +55,12 @@ public: { } + // Unlock the mutex and signal one waiter who may destroy us. + template <typename Lock> + void unlock_and_signal_one_for_destruction(Lock&) + { + } + // If there's a waiter, unlock the mutex and signal it. template <typename Lock> bool maybe_unlock_and_signal_one(Lock&) diff --git a/3rdparty/asio/include/asio/detail/null_fenced_block.hpp b/3rdparty/asio/include/asio/detail/null_fenced_block.hpp index 2ec3554d001..ccf65c3ca78 100644 --- a/3rdparty/asio/include/asio/detail/null_fenced_block.hpp +++ b/3rdparty/asio/include/asio/detail/null_fenced_block.hpp @@ -2,7 +2,7 @@ // detail/null_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/null_global.hpp b/3rdparty/asio/include/asio/detail/null_global.hpp index 7d3c0dfb03b..ab8b9c87e61 100644 --- a/3rdparty/asio/include/asio/detail/null_global.hpp +++ b/3rdparty/asio/include/asio/detail/null_global.hpp @@ -2,7 +2,7 @@ // detail/null_global.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/null_mutex.hpp b/3rdparty/asio/include/asio/detail/null_mutex.hpp index 582ab1dc70d..77e759473f5 100644 --- a/3rdparty/asio/include/asio/detail/null_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/null_mutex.hpp @@ -2,7 +2,7 @@ // detail/null_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,8 +17,6 @@ #include "asio/detail/config.hpp" -#if !defined(ASIO_HAS_THREADS) - #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" @@ -59,6 +57,4 @@ public: #include "asio/detail/pop_options.hpp" -#endif // !defined(ASIO_HAS_THREADS) - #endif // ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/3rdparty/asio/include/asio/detail/null_reactor.hpp b/3rdparty/asio/include/asio/detail/null_reactor.hpp index 3b6f1d47705..128f2b45329 100644 --- a/3rdparty/asio/include/asio/detail/null_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/null_reactor.hpp @@ -2,7 +2,7 @@ // detail/null_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,9 +17,12 @@ #include "asio/detail/config.hpp" -#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +#if defined(ASIO_HAS_IOCP) \ + || defined(ASIO_WINDOWS_RUNTIME) \ + || defined(ASIO_HAS_IO_URING_AS_DEFAULT) #include "asio/detail/scheduler_operation.hpp" +#include "asio/detail/scheduler_task.hpp" #include "asio/execution_context.hpp" #include "asio/detail/push_options.hpp" @@ -28,9 +31,14 @@ namespace asio { namespace detail { class null_reactor - : public execution_context_service_base<null_reactor> + : public execution_context_service_base<null_reactor>, + public scheduler_task { public: + struct per_descriptor_data + { + }; + // Constructor. null_reactor(asio::execution_context& ctx) : execution_context_service_base<null_reactor>(ctx) @@ -42,6 +50,11 @@ public: { } + // Initialise the task. + void init_task() + { + } + // Destroy all user-defined handler objects owned by the service. void shutdown() { @@ -63,6 +76,8 @@ public: #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +#endif // defined(ASIO_HAS_IOCP) + // || defined(ASIO_WINDOWS_RUNTIME) + // || defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // ASIO_DETAIL_NULL_REACTOR_HPP diff --git a/3rdparty/asio/include/asio/detail/null_signal_blocker.hpp b/3rdparty/asio/include/asio/detail/null_signal_blocker.hpp index 9992bd6653b..1c4030799fa 100644 --- a/3rdparty/asio/include/asio/detail/null_signal_blocker.hpp +++ b/3rdparty/asio/include/asio/detail/null_signal_blocker.hpp @@ -2,7 +2,7 @@ // detail/null_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/null_socket_service.hpp b/3rdparty/asio/include/asio/detail/null_socket_service.hpp index 59df013ca7c..84e21295f63 100644 --- a/3rdparty/asio/include/asio/detail/null_socket_service.hpp +++ b/3rdparty/asio/include/asio/detail/null_socket_service.hpp @@ -2,7 +2,7 @@ // detail/null_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -21,7 +21,8 @@ #include "asio/buffer.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" +#include "asio/post.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" @@ -32,7 +33,7 @@ namespace detail { template <typename Protocol> class null_socket_service : - public service_base<null_socket_service<Protocol> > + public execution_context_service_base<null_socket_service<Protocol>> { public: // The protocol type. @@ -50,9 +51,8 @@ public: }; // Constructor. - null_socket_service(asio::io_context& io_context) - : service_base<null_socket_service<Protocol> >(io_context), - io_context_(io_context) + null_socket_service(execution_context& context) + : execution_context_service_base<null_socket_service<Protocol>>(context) { } @@ -80,6 +80,7 @@ public: // Move-construct a new socket implementation from another protocol type. template <typename Protocol1> void converting_move_construct(implementation_type&, + null_socket_service<Protocol1>&, typename null_socket_service<Protocol1>::implementation_type&) { } @@ -119,6 +120,14 @@ public: return ec; } + // Release ownership of the socket. + native_handle_type release(implementation_type&, + asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return 0; + } + // Get the native socket representation. native_handle_type native_handle(implementation_type&) { @@ -263,23 +272,25 @@ public: // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send(implementation_type&, const ConstBufferSequence&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send(implementation_type&, const null_buffers&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Receive some data from the peer. Returns the number of bytes received. @@ -301,23 +312,26 @@ public: // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive(implementation_type&, const MutableBufferSequence&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Wait until data can be received without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_receive(implementation_type&, const null_buffers&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Receive some data with associated flags. Returns the number of bytes @@ -342,25 +356,28 @@ public: // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive_with_flags(implementation_type&, const MutableBufferSequence&, socket_base::message_flags, - socket_base::message_flags&, Handler& handler) + socket_base::message_flags&, Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Wait until data can be received without blocking. - template <typename Handler> - void async_receive_with_flags(implementation_type&, - const null_buffers&, socket_base::message_flags, - socket_base::message_flags&, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_receive_with_flags(implementation_type&, const null_buffers&, + socket_base::message_flags, socket_base::message_flags&, + Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -385,24 +402,27 @@ public: // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send_to(implementation_type&, const ConstBufferSequence&, const endpoint_type&, socket_base::message_flags, Handler& handler) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send_to(implementation_type&, const null_buffers&, - const endpoint_type&, socket_base::message_flags, Handler& handler) + const endpoint_type&, socket_base::message_flags, + Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -428,25 +448,28 @@ public: // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. - template <typename MutableBufferSequence, typename Handler> - void async_receive_from(implementation_type&, - const MutableBufferSequence&, endpoint_type&, - socket_base::message_flags, Handler& handler) + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_receive_from(implementation_type&, const MutableBufferSequence&, + endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Wait until data can be received without blocking. - template <typename Handler> - void async_receive_from(implementation_type&, - const null_buffers&, endpoint_type&, - socket_base::message_flags, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_receive_from(implementation_type&, const null_buffers&, + endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); + asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); } // Accept a new connection. @@ -460,12 +483,12 @@ public: // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. - template <typename Socket, typename Handler> - void async_accept(implementation_type&, Socket&, - endpoint_type*, Handler& handler) + template <typename Socket, typename Handler, typename IoExecutor> + void async_accept(implementation_type&, Socket&, endpoint_type*, + Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; - io_context_.post(detail::bind_handler(handler, ec)); + asio::post(io_ex, detail::bind_handler(handler, ec)); } // Connect the socket to the specified endpoint. @@ -477,16 +500,13 @@ public: } // Start an asynchronous connect. - template <typename Handler> - void async_connect(implementation_type&, - const endpoint_type&, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_connect(implementation_type&, const endpoint_type&, + Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; - io_context_.post(detail::bind_handler(handler, ec)); + asio::post(io_ex, detail::bind_handler(handler, ec)); } - -private: - asio::io_context& io_context_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/null_static_mutex.hpp b/3rdparty/asio/include/asio/detail/null_static_mutex.hpp index ee301206354..15d649bb0da 100644 --- a/3rdparty/asio/include/asio/detail/null_static_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/null_static_mutex.hpp @@ -2,7 +2,7 @@ // detail/null_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/null_thread.hpp b/3rdparty/asio/include/asio/detail/null_thread.hpp index eb1753faa27..aca261671c5 100644 --- a/3rdparty/asio/include/asio/detail/null_thread.hpp +++ b/3rdparty/asio/include/asio/detail/null_thread.hpp @@ -2,7 +2,7 @@ // detail/null_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/null_tss_ptr.hpp b/3rdparty/asio/include/asio/detail/null_tss_ptr.hpp index 5277ee5d155..cf64a2bcdda 100644 --- a/3rdparty/asio/include/asio/detail/null_tss_ptr.hpp +++ b/3rdparty/asio/include/asio/detail/null_tss_ptr.hpp @@ -2,7 +2,7 @@ // detail/null_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/object_pool.hpp b/3rdparty/asio/include/asio/detail/object_pool.hpp index 82a6dd7d158..41254ce52ee 100644 --- a/3rdparty/asio/include/asio/detail/object_pool.hpp +++ b/3rdparty/asio/include/asio/detail/object_pool.hpp @@ -2,7 +2,7 @@ // detail/object_pool.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/old_win_sdk_compat.hpp b/3rdparty/asio/include/asio/detail/old_win_sdk_compat.hpp index 9b34816ec1c..2c43c1dab80 100644 --- a/3rdparty/asio/include/asio/detail/old_win_sdk_compat.hpp +++ b/3rdparty/asio/include/asio/detail/old_win_sdk_compat.hpp @@ -2,7 +2,7 @@ // detail/old_win_sdk_compat.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/op_queue.hpp b/3rdparty/asio/include/asio/detail/op_queue.hpp index 1ab40465143..db6335f40f6 100644 --- a/3rdparty/asio/include/asio/detail/op_queue.hpp +++ b/3rdparty/asio/include/asio/detail/op_queue.hpp @@ -2,7 +2,7 @@ // detail/op_queue.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -138,6 +138,12 @@ public: return front_ == 0; } + // Test whether an operation is already enqueued. + bool is_enqueued(Operation* o) const + { + return op_queue_access::next(o) != 0 || back_ == o; + } + private: friend class op_queue_access; diff --git a/3rdparty/asio/include/asio/detail/operation.hpp b/3rdparty/asio/include/asio/detail/operation.hpp index 72144d6d881..8721f397a5c 100644 --- a/3rdparty/asio/include/asio/detail/operation.hpp +++ b/3rdparty/asio/include/asio/detail/operation.hpp @@ -2,7 +2,7 @@ // detail/operation.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/pipe_select_interrupter.hpp b/3rdparty/asio/include/asio/detail/pipe_select_interrupter.hpp index b339def0c6b..f7b219644e4 100644 --- a/3rdparty/asio/include/asio/detail/pipe_select_interrupter.hpp +++ b/3rdparty/asio/include/asio/detail/pipe_select_interrupter.hpp @@ -2,7 +2,7 @@ // detail/pipe_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -43,7 +43,7 @@ public: // Interrupt the select call. ASIO_DECL void interrupt(); - // Reset the select interrupt. Returns true if the call was interrupted. + // Reset the select interrupter. Returns true if the reset was successful. ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. diff --git a/3rdparty/asio/include/asio/detail/pop_options.hpp b/3rdparty/asio/include/asio/detail/pop_options.hpp index 880121f63eb..93cdb5abb4d 100644 --- a/3rdparty/asio/include/asio/detail/pop_options.hpp +++ b/3rdparty/asio/include/asio/detail/pop_options.hpp @@ -2,7 +2,7 @@ // detail/pop_options.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -24,9 +24,15 @@ // Intel C++ # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) -# pragma GCC visibility pop +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(ASIO_DISABLE_VISIBILITY) # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma pop_macro ("emit") +# pragma pop_macro ("signal") +# pragma pop_macro ("slot") + #elif defined(__clang__) // Clang @@ -42,9 +48,17 @@ # endif # if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) -# pragma GCC visibility pop +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(ASIO_DISABLE_VISIBILITY) # endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# pragma GCC diagnostic pop + +# pragma pop_macro ("emit") +# pragma pop_macro ("signal") +# pragma pop_macro ("slot") + #elif defined(__GNUC__) // GNU C++ @@ -64,9 +78,17 @@ # endif # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) -# pragma GCC visibility pop +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(ASIO_DISABLE_VISIBILITY) # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC diagnostic pop + +# pragma pop_macro ("emit") +# pragma pop_macro ("signal") +# pragma pop_macro ("slot") + #elif defined(__KCC) // Kai C++ @@ -83,7 +105,7 @@ // Greenhills C++ -#elif defined(__BORLANDC__) +#elif defined(__BORLANDC__) && !defined(__clang__) // Borland C++ @@ -128,4 +150,8 @@ # endif # endif +# pragma pop_macro ("emit") +# pragma pop_macro ("signal") +# pragma pop_macro ("slot") + #endif diff --git a/3rdparty/asio/include/asio/detail/posix_event.hpp b/3rdparty/asio/include/asio/detail/posix_event.hpp index 57ddc11ca08..0c83bd31a30 100644 --- a/3rdparty/asio/include/asio/detail/posix_event.hpp +++ b/3rdparty/asio/include/asio/detail/posix_event.hpp @@ -2,7 +2,7 @@ // detail/posix_event.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,7 @@ #if defined(ASIO_HAS_PTHREADS) +#include <cstddef> #include <pthread.h> #include "asio/detail/assert.hpp" #include "asio/detail/noncopyable.hpp" @@ -70,6 +71,18 @@ public: ::pthread_cond_signal(&cond_); // Ignore EINVAL. } + // Unlock the mutex and signal one waiter who may destroy us. + template <typename Lock> + void unlock_and_signal_one_for_destruction(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + lock.unlock(); + } + // If there's a waiter, unlock the mutex and signal it. template <typename Lock> bool maybe_unlock_and_signal_one(Lock& lock) @@ -116,22 +129,28 @@ public: { state_ += 2; timespec ts; -#if (defined(__MACH__) && defined(__APPLE__)) +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21) \ + && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) ts.tv_sec = usec / 1000000; ts.tv_nsec = (usec % 1000000) * 1000; ::pthread_cond_timedwait_relative_np( &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL. #else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { ts.tv_sec += usec / 1000000; - ts.tv_nsec = (usec % 1000000) * 1000; + ts.tv_nsec += (usec % 1000000) * 1000; ts.tv_sec += ts.tv_nsec / 1000000000; ts.tv_nsec = ts.tv_nsec % 1000000000; ::pthread_cond_timedwait(&cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL. } #endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) state_ -= 2; } return (state_ & 1) != 0; diff --git a/3rdparty/asio/include/asio/detail/posix_fd_set_adapter.hpp b/3rdparty/asio/include/asio/detail/posix_fd_set_adapter.hpp index 5ab9c8e8591..bd28a13fb2c 100644 --- a/3rdparty/asio/include/asio/detail/posix_fd_set_adapter.hpp +++ b/3rdparty/asio/include/asio/detail/posix_fd_set_adapter.hpp @@ -2,7 +2,7 @@ // detail/posix_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/posix_global.hpp b/3rdparty/asio/include/asio/detail/posix_global.hpp index bb9373bafbe..aea71e15c82 100644 --- a/3rdparty/asio/include/asio/detail/posix_global.hpp +++ b/3rdparty/asio/include/asio/detail/posix_global.hpp @@ -2,7 +2,7 @@ // detail/posix_global.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/posix_mutex.hpp b/3rdparty/asio/include/asio/detail/posix_mutex.hpp index 08b220b98fd..38ce2867ff5 100644 --- a/3rdparty/asio/include/asio/detail/posix_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/posix_mutex.hpp @@ -2,7 +2,7 @@ // detail/posix_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/reactive_serial_port_service.hpp b/3rdparty/asio/include/asio/detail/posix_serial_port_service.hpp index 986e87b45fe..79309549845 100644 --- a/3rdparty/asio/include/asio/detail/reactive_serial_port_service.hpp +++ b/3rdparty/asio/include/asio/detail/posix_serial_port_service.hpp @@ -1,16 +1,16 @@ // -// detail/reactive_serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/posix_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP -#define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP +#ifndef ASIO_DETAIL_POSIX_SERIAL_PORT_SERVICE_HPP +#define ASIO_DETAIL_POSIX_SERIAL_PORT_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -23,29 +23,39 @@ #include <string> #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/serial_port_base.hpp" #include "asio/detail/descriptor_ops.hpp" -#include "asio/detail/reactive_descriptor_service.hpp" + +#if defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_descriptor_service.hpp" +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/reactive_descriptor_service.hpp" +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -// Extend reactive_descriptor_service to provide serial port support. -class reactive_serial_port_service : - public service_base<reactive_serial_port_service> +// Extend a descriptor_service to provide serial port support. +class posix_serial_port_service : + public execution_context_service_base<posix_serial_port_service> { public: +#if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef io_uring_descriptor_service descriptor_service; +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef reactive_descriptor_service descriptor_service; +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + // The native type of a serial port. - typedef reactive_descriptor_service::native_handle_type native_handle_type; + typedef descriptor_service::native_handle_type native_handle_type; // The implementation type of the serial port. - typedef reactive_descriptor_service::implementation_type implementation_type; + typedef descriptor_service::implementation_type implementation_type; - ASIO_DECL reactive_serial_port_service( - asio::io_context& io_context); + ASIO_DECL posix_serial_port_service(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown(); @@ -65,7 +75,7 @@ public: // Move-assign from another serial port implementation. void move_assign(implementation_type& impl, - reactive_serial_port_service& other_service, + posix_serial_port_service& other_service, implementation_type& other_impl) { descriptor_service_.move_assign(impl, @@ -122,7 +132,7 @@ public: const SettableSerialPortOption& option, asio::error_code& ec) { return do_set_option(impl, - &reactive_serial_port_service::store_option<SettableSerialPortOption>, + &posix_serial_port_service::store_option<SettableSerialPortOption>, &option, ec); } @@ -132,7 +142,7 @@ public: GettableSerialPortOption& option, asio::error_code& ec) const { return do_get_option(impl, - &reactive_serial_port_service::load_option<GettableSerialPortOption>, + &posix_serial_port_service::load_option<GettableSerialPortOption>, &option, ec); } @@ -140,9 +150,9 @@ public: asio::error_code send_break(implementation_type& impl, asio::error_code& ec) { - errno = 0; - descriptor_ops::error_wrapper(::tcsendbreak( - descriptor_service_.native_handle(impl), 0), ec); + int result = ::tcsendbreak(descriptor_service_.native_handle(impl), 0); + descriptor_ops::get_last_error(ec, result < 0); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -156,11 +166,12 @@ public: // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, Handler& handler) + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { - descriptor_service_.async_write_some(impl, buffers, handler); + descriptor_service_.async_write_some(impl, buffers, handler, io_ex); } // Read some data. Returns the number of bytes received. @@ -173,11 +184,13 @@ public: // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, Handler& handler) + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { - descriptor_service_.async_read_some(impl, buffers, handler); + descriptor_service_.async_read_some(impl, buffers, handler, io_ex); } private: @@ -218,7 +231,7 @@ private: void* option, asio::error_code& ec) const; // The implementation used for initiating asynchronous operations. - reactive_descriptor_service descriptor_service_; + descriptor_service descriptor_service_; }; } // namespace detail @@ -227,10 +240,10 @@ private: #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) -# include "asio/detail/impl/reactive_serial_port_service.ipp" +# include "asio/detail/impl/posix_serial_port_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) #endif // defined(ASIO_HAS_SERIAL_PORT) -#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP +#endif // ASIO_DETAIL_POSIX_SERIAL_PORT_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/posix_signal_blocker.hpp b/3rdparty/asio/include/asio/detail/posix_signal_blocker.hpp index dc476fd7387..a57c09687b8 100644 --- a/3rdparty/asio/include/asio/detail/posix_signal_blocker.hpp +++ b/3rdparty/asio/include/asio/detail/posix_signal_blocker.hpp @@ -2,7 +2,7 @@ // detail/posix_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/posix_static_mutex.hpp b/3rdparty/asio/include/asio/detail/posix_static_mutex.hpp index e65d09affdf..38a44c0327a 100644 --- a/3rdparty/asio/include/asio/detail/posix_static_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/posix_static_mutex.hpp @@ -2,7 +2,7 @@ // detail/posix_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/posix_thread.hpp b/3rdparty/asio/include/asio/detail/posix_thread.hpp index a07d5b3b003..9085a0b4a7b 100644 --- a/3rdparty/asio/include/asio/detail/posix_thread.hpp +++ b/3rdparty/asio/include/asio/detail/posix_thread.hpp @@ -2,7 +2,7 @@ // detail/posix_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/posix_tss_ptr.hpp b/3rdparty/asio/include/asio/detail/posix_tss_ptr.hpp index a677d15dc5f..b0d0653bed5 100644 --- a/3rdparty/asio/include/asio/detail/posix_tss_ptr.hpp +++ b/3rdparty/asio/include/asio/detail/posix_tss_ptr.hpp @@ -2,7 +2,7 @@ // detail/posix_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/push_options.hpp b/3rdparty/asio/include/asio/detail/push_options.hpp index 384bab13eda..d270e9ae13c 100644 --- a/3rdparty/asio/include/asio/detail/push_options.hpp +++ b/3rdparty/asio/include/asio/detail/push_options.hpp @@ -2,7 +2,7 @@ // detail/push_options.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -24,9 +24,20 @@ // Intel C++ # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) -# pragma GCC visibility push (default) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(ASIO_DISABLE_VISIBILITY) # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma push_macro ("emit") +# undef emit + +# pragma push_macro ("signal") +# undef signal + +# pragma push_macro ("slot") +# undef slot + #elif defined(__clang__) // Clang @@ -44,9 +55,26 @@ # endif # if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) -# pragma GCC visibility push (default) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(ASIO_DISABLE_VISIBILITY) # endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +# if (__clang_major__ >= 6) +# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +# endif // (__clang_major__ >= 6) + +# pragma push_macro ("emit") +# undef emit + +# pragma push_macro ("signal") +# undef signal + +# pragma push_macro ("slot") +# undef slot + #elif defined(__GNUC__) // GNU C++ @@ -68,9 +96,29 @@ # endif # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) -# pragma GCC visibility push (default) +# if !defined(ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(ASIO_DISABLE_VISIBILITY) # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4) +# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4) +# if (__GNUC__ >= 7) +# pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +# endif // (__GNUC__ >= 7) + +# pragma push_macro ("emit") +# undef emit + +# pragma push_macro ("signal") +# undef signal + +# pragma push_macro ("slot") +# undef slot + #elif defined(__KCC) // Kai C++ @@ -87,7 +135,7 @@ // Greenhills C++ -#elif defined(__BORLANDC__) +#elif defined(__BORLANDC__) && !defined(__clang__) // Borland C++ @@ -124,12 +172,13 @@ // // Must remain the last #elif since some other vendors (Metrowerks, for example) // also #define _MSC_VER - # pragma warning (disable:4103) # pragma warning (push) +# pragma warning (disable:4619) // suppress 'there is no warning number XXXX' # pragma warning (disable:4127) # pragma warning (disable:4180) # pragma warning (disable:4244) +# pragma warning (disable:4265) # pragma warning (disable:4355) # pragma warning (disable:4510) # pragma warning (disable:4512) @@ -167,4 +216,13 @@ # endif # endif +# pragma push_macro ("emit") +# undef emit + +# pragma push_macro ("signal") +# undef signal + +# pragma push_macro ("slot") +# undef slot + #endif diff --git a/3rdparty/asio/include/asio/detail/reactive_descriptor_service.hpp b/3rdparty/asio/include/asio/detail/reactive_descriptor_service.hpp index 42bc3df55b5..f7c7e86916d 100644 --- a/3rdparty/asio/include/asio/detail/reactive_descriptor_service.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_descriptor_service.hpp @@ -2,7 +2,7 @@ // detail/reactive_descriptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,10 +19,14 @@ #if !defined(ASIO_WINDOWS) \ && !defined(ASIO_WINDOWS_RUNTIME) \ - && !defined(__CYGWIN__) + && !defined(__CYGWIN__) \ + && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) +#include "asio/associated_cancellation_slot.hpp" +#include "asio/associated_immediate_executor.hpp" #include "asio/buffer.hpp" -#include "asio/io_context.hpp" +#include "asio/cancellation_type.hpp" +#include "asio/execution_context.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/descriptor_ops.hpp" @@ -42,7 +46,7 @@ namespace asio { namespace detail { class reactive_descriptor_service : - public service_base<reactive_descriptor_service> + public execution_context_service_base<reactive_descriptor_service> { public: // The native type of a descriptor. @@ -75,8 +79,7 @@ public: }; // Constructor. - ASIO_DECL reactive_descriptor_service( - asio::io_context& io_context); + ASIO_DECL reactive_descriptor_service(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown(); @@ -86,7 +89,7 @@ public: // Move-construct a new descriptor implementation. ASIO_DECL void move_construct(implementation_type& impl, - implementation_type& other_impl); + implementation_type& other_impl) noexcept; // Move-assign from another descriptor implementation. ASIO_DECL void move_assign(implementation_type& impl, @@ -120,6 +123,14 @@ public: // Release ownership of the native descriptor representation. ASIO_DECL native_handle_type release(implementation_type& impl); + // Release ownership of the native descriptor representation. + native_handle_type release(implementation_type& impl, + asio::error_code& ec) + { + ec = success_ec_; + return release(impl); + } + // Cancel all operations associated with the descriptor. ASIO_DECL asio::error_code cancel(implementation_type& impl, asio::error_code& ec); @@ -131,6 +142,7 @@ public: { descriptor_ops::ioctl(impl.descriptor_, impl.state_, command.name(), static_cast<ioctl_arg_type*>(command.data()), ec); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -146,6 +158,7 @@ public: { descriptor_ops::set_user_non_blocking( impl.descriptor_, impl.state_, mode, ec); + ASIO_ERROR_LOCATION(ec); return ec; } @@ -185,23 +198,28 @@ public: break; } + ASIO_ERROR_LOCATION(ec); return ec; } // Asynchronously wait for the descriptor to become ready to read, ready to // write, or to have pending error conditions. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_wait(implementation_type& impl, - posix::descriptor_base::wait_type w, Handler& handler) + posix::descriptor_base::wait_type w, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_wait_op<Handler> op; + typedef reactive_wait_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_wait")); @@ -210,22 +228,31 @@ public: switch (w) { case posix::descriptor_base::wait_read: - op_type = reactor::read_op; - break; + op_type = reactor::read_op; + break; case posix::descriptor_base::wait_write: - op_type = reactor::write_op; - break; + op_type = reactor::write_op; + break; case posix::descriptor_base::wait_error: - op_type = reactor::except_op; - break; - default: - p.p->ec_ = asio::error::invalid_argument; - reactor_.post_immediate_completion(p.p, is_continuation); - p.v = p.p = 0; - return; + op_type = reactor::except_op; + break; + default: + p.p->ec_ = asio::error::invalid_argument; + start_op(impl, reactor::read_op, p.p, + is_continuation, false, true, &io_ex, 0); + p.v = p.p = 0; + return; + } + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.descriptor_, op_type); } - start_op(impl, op_type, p.p, is_continuation, false, false); + start_op(impl, op_type, p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -234,11 +261,26 @@ public: size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(buffers); + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; - return descriptor_ops::sync_write(impl.descriptor_, impl.state_, - bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + size_t n; + if (bufs_type::is_single_buffer) + { + n = descriptor_ops::sync_write1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + n = descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be written without blocking. @@ -247,52 +289,78 @@ public: { // Wait for descriptor to become ready. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); - + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous write. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, Handler& handler) + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef descriptor_write_op<ConstBufferSequence, Handler> op; + typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.descriptor_, buffers, handler); + p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, + impl.descriptor_, reactor::write_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_write_some")); start_op(impl, reactor::write_op, p.p, is_continuation, true, buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::all_empty(buffers)); + ConstBufferSequence>::all_empty(buffers), &io_ex, 0); p.v = p.p = 0; } // Start an asynchronous wait until data can be written without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_write_some(implementation_type& impl, - const null_buffers&, Handler& handler) + const null_buffers&, Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_null_buffers_op<Handler> op; + typedef reactive_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, + impl.descriptor_, reactor::write_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_write_some(null_buffers)")); - start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -301,11 +369,26 @@ public: size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(buffers); + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; - return descriptor_ops::sync_read(impl.descriptor_, impl.state_, - bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + size_t n; + if (bufs_type::is_single_buffer) + { + n = descriptor_ops::sync_read1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + n = descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be read without blocking. @@ -314,62 +397,156 @@ public: { // Wait for descriptor to become ready. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); - + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous read. The buffer for the data being read must be // valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, Handler& handler) + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef descriptor_read_op<MutableBufferSequence, Handler> op; + typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.descriptor_, buffers, handler); + p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, + impl.descriptor_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_read_some")); start_op(impl, reactor::read_op, p.p, is_continuation, true, buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::all_empty(buffers)); + MutableBufferSequence>::all_empty(buffers), &io_ex, 0); p.v = p.p = 0; } // Wait until data can be read without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_read_some(implementation_type& impl, - const null_buffers&, Handler& handler) + const null_buffers&, Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_null_buffers_op<Handler> op; + typedef reactive_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, + impl.descriptor_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_read_some(null_buffers)")); - start_op(impl, reactor::read_op, p.p, is_continuation, false, false); + start_op(impl, reactor::read_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } private: // Start the asynchronous operation. - ASIO_DECL void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + ASIO_DECL void do_start_op(implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous operation for handlers that are specialised for + // immediate completion. + template <typename Op> + void start_op(implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, + const void* io_ex, ...) + { + return do_start_op(impl, op_type, op, is_continuation, + is_non_blocking, noop, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template <typename Op> + void start_op(implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, const void*, + enable_if_t< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >*) + { + return do_start_op(impl, op_type, op, is_continuation, is_non_blocking, + noop, &reactor::call_post_immediate_completion, &reactor_); + } + + // Helper class used to implement per-operation cancellation + class reactor_op_cancellation + { + public: + reactor_op_cancellation(reactor* r, + reactor::per_descriptor_data* p, int d, int o) + : reactor_(r), + reactor_data_(p), + descriptor_(d), + op_type_(o) + { + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + reactor_->cancel_ops_by_key(descriptor_, + *reactor_data_, op_type_, this); + } + } + + private: + reactor* reactor_; + reactor::per_descriptor_data* reactor_data_; + int descriptor_; + int op_type_; + }; // The selector that performs event demultiplexing for the service. reactor& reactor_; + + // Cached success value to avoid accessing category singleton. + const asio::error_code success_ec_; }; } // namespace detail @@ -384,5 +561,6 @@ private: #endif // !defined(ASIO_WINDOWS) // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) + // && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/reactive_null_buffers_op.hpp b/3rdparty/asio/include/asio/detail/reactive_null_buffers_op.hpp index 504e4f66b11..b9a32a91217 100644 --- a/3rdparty/asio/include/asio/detail/reactive_null_buffers_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_null_buffers_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_null_buffers_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" @@ -27,18 +28,22 @@ namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class reactive_null_buffers_op : public reactor_op { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); - reactive_null_buffers_op(Handler& handler) - : reactor_op(&reactive_null_buffers_op::do_perform, + reactive_null_buffers_op(const asio::error_code& success_ec, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(success_ec, &reactive_null_buffers_op::do_perform, &reactive_null_buffers_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static status do_perform(reactor_op*) @@ -51,12 +56,17 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -78,8 +88,39 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_accept_op.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_accept_op.hpp index 11b81d5168d..5ae84fd9966 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_accept_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_accept_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_accept_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,8 +17,9 @@ #include "asio/detail/config.hpp" #include "asio/detail/bind_handler.hpp" -#include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" @@ -33,10 +34,12 @@ template <typename Socket, typename Protocol> class reactive_socket_accept_op_base : public reactor_op { public: - reactive_socket_accept_op_base(socket_type socket, - socket_ops::state_type state, Socket& peer, const Protocol& protocol, - typename Protocol::endpoint* peer_endpoint, func_type complete_func) - : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), + reactive_socket_accept_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_accept_op_base::do_perform, complete_func), socket_(socket), state_(state), peer_(peer), @@ -48,6 +51,7 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); reactive_socket_accept_op_base* o( static_cast<reactive_socket_accept_op_base*>(base)); @@ -85,21 +89,27 @@ private: std::size_t addrlen_; }; -template <typename Socket, typename Protocol, typename Handler> +template <typename Socket, typename Protocol, + typename Handler, typename IoExecutor> class reactive_socket_accept_op : public reactive_socket_accept_op_base<Socket, Protocol> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); - reactive_socket_accept_op(socket_type socket, - socket_ops::state_type state, Socket& peer, const Protocol& protocol, - typename Protocol::endpoint* peer_endpoint, Handler& handler) - : reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer, - protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + reactive_socket_accept_op(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_accept_op_base<Socket, Protocol>( + success_ec, socket, state, peer, protocol, peer_endpoint, + &reactive_socket_accept_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -107,9 +117,9 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); // On success, assign new connection to peer socket object. if (owner) @@ -117,6 +127,13 @@ public: ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -138,30 +155,72 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; -#if defined(ASIO_HAS_MOVE) - -template <typename Protocol, typename Handler> +template <typename Protocol, typename PeerIoExecutor, + typename Handler, typename IoExecutor> class reactive_socket_move_accept_op : - private Protocol::socket, - public reactive_socket_accept_op_base<typename Protocol::socket, Protocol> + private Protocol::socket::template rebind_executor<PeerIoExecutor>::other, + public reactive_socket_accept_op_base< + typename Protocol::socket::template rebind_executor<PeerIoExecutor>::other, + Protocol> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); - reactive_socket_move_accept_op(io_context& ioc, socket_type socket, + reactive_socket_move_accept_op(const asio::error_code& success_ec, + const PeerIoExecutor& peer_io_ex, socket_type socket, socket_ops::state_type state, const Protocol& protocol, - typename Protocol::endpoint* peer_endpoint, Handler& handler) - : Protocol::socket(ioc), - reactive_socket_accept_op_base<typename Protocol::socket, Protocol>( - socket, state, *this, protocol, peer_endpoint, + typename Protocol::endpoint* peer_endpoint, Handler& handler, + const IoExecutor& io_ex) + : peer_socket_type(peer_io_ex), + reactive_socket_accept_op_base<peer_socket_type, Protocol>( + success_ec, socket, state, *this, protocol, peer_endpoint, &reactive_socket_move_accept_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -169,10 +228,10 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_move_accept_op* o( static_cast<reactive_socket_move_accept_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); // On success, assign new connection to peer socket object. if (owner) @@ -180,6 +239,13 @@ public: ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -187,9 +253,9 @@ public: // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::move_binder2<Handler, - asio::error_code, typename Protocol::socket> - handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, - ASIO_MOVE_CAST(typename Protocol::socket)(*o)); + asio::error_code, peer_socket_type> + handler(0, static_cast<Handler&&>(o->handler_), o->ec_, + static_cast<peer_socket_type&&>(*o)); p.h = asio::detail::addressof(handler.handler_); p.reset(); @@ -203,12 +269,52 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_move_accept_op* o( + static_cast<reactive_socket_move_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + o->do_assign(); + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2<Handler, + asio::error_code, peer_socket_type> + handler(0, static_cast<Handler&&>(o->handler_), o->ec_, + static_cast<peer_socket_type&&>(*o)); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: + typedef typename Protocol::socket::template + rebind_executor<PeerIoExecutor>::other peer_socket_type; + Handler handler_; + handler_work<Handler, IoExecutor> work_; }; -#endif // defined(ASIO_HAS_MOVE) - } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_connect_op.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_connect_op.hpp index 428db3f8e39..03c0db2e7dd 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_connect_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_connect_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_connect_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,8 +17,9 @@ #include "asio/detail/config.hpp" #include "asio/detail/bind_handler.hpp" -#include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -31,14 +32,17 @@ namespace detail { class reactive_socket_connect_op_base : public reactor_op { public: - reactive_socket_connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), + reactive_socket_connect_op_base(const asio::error_code& success_ec, + socket_type socket, func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_connect_op_base::do_perform, complete_func), socket_(socket) { } static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); reactive_socket_connect_op_base* o( static_cast<reactive_socket_connect_op_base*>(base)); @@ -54,18 +58,22 @@ private: socket_type socket_; }; -template <typename Handler> +template <typename Handler, typename IoExecutor> class reactive_socket_connect_op : public reactive_socket_connect_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); - reactive_socket_connect_op(socket_type socket, Handler& handler) - : reactive_socket_connect_op_base(socket, + reactive_socket_connect_op(const asio::error_code& success_ec, + socket_type socket, Handler& handler, const IoExecutor& io_ex) + : reactive_socket_connect_op_base(success_ec, socket, &reactive_socket_connect_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -73,13 +81,20 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_connect_op* o (static_cast<reactive_socket_connect_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -101,8 +116,42 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_connect_op* o + (static_cast<reactive_socket_connect_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_recv_op.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_recv_op.hpp index 71f0aec5369..b6533655674 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_recv_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_recv_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,8 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -32,10 +34,12 @@ template <typename MutableBufferSequence> class reactive_socket_recv_op_base : public reactor_op { public: - reactive_socket_recv_op_base(socket_type socket, - socket_ops::state_type state, const MutableBufferSequence& buffers, + reactive_socket_recv_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_recv_op_base::do_perform, complete_func), socket_(socket), state_(state), buffers_(buffers), @@ -45,20 +49,34 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); reactive_socket_recv_op_base* o( static_cast<reactive_socket_recv_op_base*>(base)); - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(o->buffers_); + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; - status result = socket_ops::non_blocking_recv(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, - (o->state_ & socket_ops::stream_oriented) != 0, - o->ec_, o->bytes_transferred_) ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_recv1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + } if (result == done) if ((o->state_ & socket_ops::stream_oriented) != 0) - if (o->bytes_transferred_ < bufs.total_size()) + if (o->bytes_transferred_ == 0) result = done_and_exhausted; ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv", @@ -74,21 +92,25 @@ private: socket_base::message_flags flags_; }; -template <typename MutableBufferSequence, typename Handler> +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class reactive_socket_recv_op : public reactive_socket_recv_op_base<MutableBufferSequence> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); - reactive_socket_recv_op(socket_type socket, - socket_ops::state_type state, const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) - : reactive_socket_recv_op_base<MutableBufferSequence>(socket, state, - buffers, flags, &reactive_socket_recv_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + reactive_socket_recv_op(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_recv_op_base<MutableBufferSequence>(success_ec, socket, + state, buffers, flags, &reactive_socket_recv_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -96,12 +118,19 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -123,8 +152,41 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp index 309a032a7ab..b84ea61794f 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_recvfrom_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,8 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -32,10 +34,12 @@ template <typename MutableBufferSequence, typename Endpoint> class reactive_socket_recvfrom_op_base : public reactor_op { public: - reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, + reactive_socket_recvfrom_op_base(const asio::error_code& success_ec, + socket_type socket, int protocol_type, const MutableBufferSequence& buffers, Endpoint& endpoint, socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_recvfrom_op_base::do_perform, complete_func), socket_(socket), protocol_type_(protocol_type), buffers_(buffers), @@ -46,17 +50,31 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); reactive_socket_recvfrom_op_base* o( static_cast<reactive_socket_recvfrom_op_base*>(base)); - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(o->buffers_); + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; std::size_t addr_len = o->sender_endpoint_.capacity(); - status result = socket_ops::non_blocking_recvfrom(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, - o->sender_endpoint_.data(), &addr_len, - o->ec_, o->bytes_transferred_) ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_recvfrom1( + o->socket_, bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_recvfrom(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + } if (result && !o->ec_) o->sender_endpoint_.resize(addr_len); @@ -75,22 +93,28 @@ private: socket_base::message_flags flags_; }; -template <typename MutableBufferSequence, typename Endpoint, typename Handler> +template <typename MutableBufferSequence, typename Endpoint, + typename Handler, typename IoExecutor> class reactive_socket_recvfrom_op : public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); - reactive_socket_recvfrom_op(socket_type socket, int protocol_type, + reactive_socket_recvfrom_op(const asio::error_code& success_ec, + socket_type socket, int protocol_type, const MutableBufferSequence& buffers, Endpoint& endpoint, - socket_base::message_flags flags, Handler& handler) + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>( - socket, protocol_type, buffers, endpoint, flags, + success_ec, socket, protocol_type, buffers, endpoint, flags, &reactive_socket_recvfrom_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -98,13 +122,20 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_recvfrom_op* o( static_cast<reactive_socket_recvfrom_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -126,8 +157,42 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_recvfrom_op* o( + static_cast<reactive_socket_recvfrom_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp index e0c801fd86d..e4c8117b675 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_recvmsg_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,8 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -33,10 +35,12 @@ template <typename MutableBufferSequence> class reactive_socket_recvmsg_op_base : public reactor_op { public: - reactive_socket_recvmsg_op_base(socket_type socket, - const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + reactive_socket_recvmsg_op_base(const asio::error_code& success_ec, + socket_type socket, const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, socket_base::message_flags& out_flags, func_type complete_func) - : reactor_op(&reactive_socket_recvmsg_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_recvmsg_op_base::do_perform, complete_func), socket_(socket), buffers_(buffers), in_flags_(in_flags), @@ -46,6 +50,7 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); reactive_socket_recvmsg_op_base* o( static_cast<reactive_socket_recvmsg_op_base*>(base)); @@ -70,21 +75,27 @@ private: socket_base::message_flags& out_flags_; }; -template <typename MutableBufferSequence, typename Handler> +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class reactive_socket_recvmsg_op : public reactive_socket_recvmsg_op_base<MutableBufferSequence> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); - reactive_socket_recvmsg_op(socket_type socket, - const MutableBufferSequence& buffers, socket_base::message_flags in_flags, - socket_base::message_flags& out_flags, Handler& handler) - : reactive_socket_recvmsg_op_base<MutableBufferSequence>(socket, buffers, - in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + reactive_socket_recvmsg_op(const asio::error_code& success_ec, + socket_type socket, const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + : reactive_socket_recvmsg_op_base<MutableBufferSequence>( + success_ec, socket, buffers, in_flags, out_flags, + &reactive_socket_recvmsg_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -92,13 +103,20 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_recvmsg_op* o( static_cast<reactive_socket_recvmsg_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -120,8 +138,42 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_recvmsg_op* o( + static_cast<reactive_socket_recvmsg_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_send_op.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_send_op.hpp index 708e8ea0d97..ef7ec69933b 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_send_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_send_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,8 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -32,10 +34,12 @@ template <typename ConstBufferSequence> class reactive_socket_send_op_base : public reactor_op { public: - reactive_socket_send_op_base(socket_type socket, - socket_ops::state_type state, const ConstBufferSequence& buffers, + reactive_socket_send_op_base(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_send_op_base::do_perform, complete_func), socket_(socket), state_(state), buffers_(buffers), @@ -45,20 +49,38 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); reactive_socket_send_op_base* o( static_cast<reactive_socket_send_op_base*>(base)); - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(o->buffers_); + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; - status result = socket_ops::non_blocking_send(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_send1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, o->ec_, o->bytes_transferred_) ? done : not_done; - if (result == done) - if ((o->state_ & socket_ops::stream_oriented) != 0) - if (o->bytes_transferred_ < bufs.total_size()) - result = done_and_exhausted; + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs_type::first(o->buffers_).size()) + result = done_and_exhausted; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs.total_size()) + result = done_and_exhausted; + } ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send", o->ec_, o->bytes_transferred_)); @@ -73,21 +95,25 @@ private: socket_base::message_flags flags_; }; -template <typename ConstBufferSequence, typename Handler> +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> class reactive_socket_send_op : public reactive_socket_send_op_base<ConstBufferSequence> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); - reactive_socket_send_op(socket_type socket, - socket_ops::state_type state, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) - : reactive_socket_send_op_base<ConstBufferSequence>(socket, + reactive_socket_send_op(const asio::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_send_op_base<ConstBufferSequence>(success_ec, socket, state, buffers, flags, &reactive_socket_send_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -95,12 +121,19 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -122,8 +155,42 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_sendto_op.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_sendto_op.hpp index cab8f88a086..e1bbb70389c 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_sendto_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_sendto_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_sendto_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,8 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -32,10 +34,12 @@ template <typename ConstBufferSequence, typename Endpoint> class reactive_socket_sendto_op_base : public reactor_op { public: - reactive_socket_sendto_op_base(socket_type socket, - const ConstBufferSequence& buffers, const Endpoint& endpoint, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), + reactive_socket_sendto_op_base(const asio::error_code& success_ec, + socket_type socket, const ConstBufferSequence& buffers, + const Endpoint& endpoint, socket_base::message_flags flags, + func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_sendto_op_base::do_perform, complete_func), socket_(socket), buffers_(buffers), destination_(endpoint), @@ -45,16 +49,30 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); reactive_socket_sendto_op_base* o( static_cast<reactive_socket_sendto_op_base*>(base)); - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(o->buffers_); + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; - status result = socket_ops::non_blocking_sendto(o->socket_, + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_sendto1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_sendto(o->socket_, bufs.buffers(), bufs.count(), o->flags_, o->destination_.data(), o->destination_.size(), o->ec_, o->bytes_transferred_) ? done : not_done; + } ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto", o->ec_, o->bytes_transferred_)); @@ -69,21 +87,27 @@ private: socket_base::message_flags flags_; }; -template <typename ConstBufferSequence, typename Endpoint, typename Handler> +template <typename ConstBufferSequence, typename Endpoint, + typename Handler, typename IoExecutor> class reactive_socket_sendto_op : public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); - reactive_socket_sendto_op(socket_type socket, - const ConstBufferSequence& buffers, const Endpoint& endpoint, - socket_base::message_flags flags, Handler& handler) - : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(socket, - buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + reactive_socket_sendto_op(const asio::error_code& success_ec, + socket_type socket, const ConstBufferSequence& buffers, + const Endpoint& endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>( + success_ec, socket, buffers, endpoint, flags, + &reactive_socket_sendto_op::do_complete), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -91,12 +115,19 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -118,8 +149,41 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2<Handler, asio::error_code, std::size_t> + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_service.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_service.hpp index 4ba255667c1..c828e7f1f2a 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_service.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_service.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,11 +17,12 @@ #include "asio/detail/config.hpp" -#if !defined(ASIO_HAS_IOCP) +#if !defined(ASIO_HAS_IOCP) \ + && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #include "asio/buffer.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/socket_base.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/memory.hpp" @@ -45,7 +46,7 @@ namespace detail { template <typename Protocol> class reactive_socket_service : - public service_base<reactive_socket_service<Protocol> >, + public execution_context_service_base<reactive_socket_service<Protocol>>, public reactive_socket_service_base { public: @@ -73,9 +74,10 @@ public: }; // Constructor. - reactive_socket_service(asio::io_context& io_context) - : service_base<reactive_socket_service<Protocol> >(io_context), - reactive_socket_service_base(io_context) + reactive_socket_service(execution_context& context) + : execution_context_service_base< + reactive_socket_service<Protocol>>(context), + reactive_socket_service_base(context) { } @@ -87,7 +89,7 @@ public: // Move-construct a new socket implementation. void move_construct(implementation_type& impl, - implementation_type& other_impl) + implementation_type& other_impl) noexcept { this->base_move_construct(impl, other_impl); @@ -109,6 +111,7 @@ public: // Move-construct a new socket implementation from another protocol type. template <typename Protocol1> void converting_move_construct(implementation_type& impl, + reactive_socket_service<Protocol1>&, typename reactive_socket_service< Protocol1>::implementation_type& other_impl) { @@ -125,6 +128,8 @@ public: if (!do_open(impl, protocol.family(), protocol.type(), protocol.protocol(), ec)) impl.protocol_ = protocol; + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -135,6 +140,8 @@ public: { if (!do_assign(impl, protocol.type(), native_socket, ec)) impl.protocol_ = protocol; + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -149,6 +156,8 @@ public: const endpoint_type& endpoint, asio::error_code& ec) { socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -160,6 +169,8 @@ public: socket_ops::setsockopt(impl.socket_, impl.state_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -174,6 +185,8 @@ public: option.data(impl.protocol_), &size, ec); if (!ec) option.resize(impl.protocol_, size); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -184,7 +197,10 @@ public: endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + { + ASIO_ERROR_LOCATION(ec); return endpoint_type(); + } endpoint.resize(addr_len); return endpoint; } @@ -197,7 +213,10 @@ public: std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, false, ec)) + { + ASIO_ERROR_LOCATION(ec); return endpoint_type(); + } endpoint.resize(addr_len); return endpoint; } @@ -207,6 +226,8 @@ public: socket_base::shutdown_type what, asio::error_code& ec) { socket_ops::shutdown(impl.socket_, what, ec); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -217,12 +238,27 @@ public: const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(buffers); + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; - return socket_ops::sync_sendto(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, - destination.data(), destination.size(), ec); + size_t n; + if (bufs_type::is_single_buffer) + { + n = socket_ops::sync_sendto1(impl.socket_, impl.state_, + bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, + destination.data(), destination.size(), ec); + } + else + { + bufs_type bufs(buffers); + n = socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be sent without blocking. @@ -233,52 +269,79 @@ public: // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - Handler& handler) + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. typedef reactive_socket_sendto_op<ConstBufferSequence, - endpoint_type, Handler> op; + endpoint_type, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); + p.p = new (p.v) op(success_ec_, impl.socket_, + buffers, destination, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to")); - start_op(impl, reactor::write_op, p.p, is_continuation, true, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, true, false, &io_ex, 0); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send_to(implementation_type& impl, const null_buffers&, - const endpoint_type&, socket_base::message_flags, Handler& handler) + const endpoint_type&, socket_base::message_flags, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_null_buffers_op<Handler> op; + typedef reactive_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to(null_buffers)")); - start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -290,18 +353,29 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(buffers); + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; std::size_t addr_len = sender_endpoint.capacity(); - std::size_t bytes_recvd = socket_ops::sync_recvfrom( - impl.socket_, impl.state_, bufs.buffers(), bufs.count(), - flags, sender_endpoint.data(), &addr_len, ec); + std::size_t n; + if (bufs_type::is_single_buffer) + { + n = socket_ops::sync_recvfrom1(impl.socket_, impl.state_, + bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), + flags, sender_endpoint.data(), &addr_len, ec); + } + else + { + bufs_type bufs(buffers); + n = socket_ops::sync_recvfrom(impl.socket_, impl.state_, bufs.buffers(), + bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); + } if (!ec) sender_endpoint.resize(addr_len); - return bytes_recvd; + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be received without blocking. @@ -315,28 +389,42 @@ public: // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, Handler& handler) + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. typedef reactive_socket_recvfrom_op<MutableBufferSequence, - endpoint_type, Handler> op; + endpoint_type, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; int protocol = impl.protocol_.type(); - p.p = new (p.v) op(impl.socket_, protocol, - buffers, sender_endpoint, flags, handler); + p.p = new (p.v) op(success_ec_, impl.socket_, protocol, + buffers, sender_endpoint, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_from")); @@ -344,24 +432,35 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, true, false); + p.p, is_continuation, true, false, &io_ex, 0); p.v = p.p = 0; } // Wait until data can be received without blocking. - template <typename Handler> - void async_receive_from(implementation_type& impl, - const null_buffers&, endpoint_type& sender_endpoint, - socket_base::message_flags flags, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_null_buffers_op<Handler> op; + typedef reactive_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_from(null_buffers)")); @@ -372,7 +471,7 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, false, false); + p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -385,6 +484,7 @@ public: if (peer.is_open()) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -403,85 +503,79 @@ public: new_socket.release(); } + ASIO_ERROR_LOCATION(ec); return ec; } -#if defined(ASIO_HAS_MOVE) - // Accept a new connection. - typename Protocol::socket accept(implementation_type& impl, - io_context* peer_io_context, endpoint_type* peer_endpoint, - asio::error_code& ec) - { - typename Protocol::socket peer( - peer_io_context ? *peer_io_context : io_context_); - - std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; - socket_holder new_socket(socket_ops::sync_accept(impl.socket_, - impl.state_, peer_endpoint ? peer_endpoint->data() : 0, - peer_endpoint ? &addr_len : 0, ec)); - - // On success, assign new connection to peer socket object. - if (new_socket.get() != invalid_socket) - { - if (peer_endpoint) - peer_endpoint->resize(addr_len); - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - } - - return peer; - } -#endif // defined(ASIO_HAS_MOVE) - // Start an asynchronous accept. The peer and peer_endpoint objects must be // valid until the accept's handler is invoked. - template <typename Socket, typename Handler> + template <typename Socket, typename Handler, typename IoExecutor> void async_accept(implementation_type& impl, Socket& peer, - endpoint_type* peer_endpoint, Handler& handler) + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_accept_op<Socket, Protocol, Handler> op; + typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, impl.state_, peer, - impl.protocol_, peer_endpoint, handler); + p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, + peer, impl.protocol_, peer_endpoint, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected() && !peer.is_open()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); - start_accept_op(impl, p.p, is_continuation, peer.is_open()); + start_accept_op(impl, p.p, is_continuation, peer.is_open(), &io_ex, 0); p.v = p.p = 0; } -#if defined(ASIO_HAS_MOVE) // Start an asynchronous accept. The peer_endpoint object must be valid until // the accept's handler is invoked. - template <typename Handler> - void async_accept(implementation_type& impl, - asio::io_context* peer_io_context, - endpoint_type* peer_endpoint, Handler& handler) + template <typename PeerIoExecutor, typename Handler, typename IoExecutor> + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_move_accept_op<Protocol, Handler> op; + typedef reactive_socket_move_accept_op<Protocol, + PeerIoExecutor, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(peer_io_context ? *peer_io_context : io_context_, - impl.socket_, impl.state_, impl.protocol_, peer_endpoint, handler); + p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_, + impl.state_, impl.protocol_, peer_endpoint, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); - start_accept_op(impl, p.p, is_continuation, false); + start_accept_op(impl, p.p, is_continuation, false, &io_ex, 0); p.v = p.p = 0; } -#endif // defined(ASIO_HAS_MOVE) // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, @@ -489,28 +583,41 @@ public: { socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); + ASIO_ERROR_LOCATION(ec); return ec; } // Start an asynchronous connect. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, Handler& handler) + const endpoint_type& peer_endpoint, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_connect_op<Handler> op; + typedef reactive_socket_connect_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, handler); + p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::connect_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_connect")); start_connect_op(impl, p.p, is_continuation, - peer_endpoint.data(), peer_endpoint.size()); + peer_endpoint.data(), peer_endpoint.size(), &io_ex, 0); p.v = p.p = 0; } }; @@ -521,5 +628,6 @@ public: #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_HAS_IOCP) + // && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/reactive_socket_service_base.hpp b/3rdparty/asio/include/asio/detail/reactive_socket_service_base.hpp index f2de9db607b..63dcacad582 100644 --- a/3rdparty/asio/include/asio/detail/reactive_socket_service_base.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_socket_service_base.hpp @@ -2,7 +2,7 @@ // detail/reactive_socket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,11 +18,14 @@ #include "asio/detail/config.hpp" #if !defined(ASIO_HAS_IOCP) \ - && !defined(ASIO_WINDOWS_RUNTIME) + && !defined(ASIO_WINDOWS_RUNTIME) \ + && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) +#include "asio/associated_cancellation_slot.hpp" #include "asio/buffer.hpp" +#include "asio/cancellation_type.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/socket_base.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/memory.hpp" @@ -62,8 +65,7 @@ public: }; // Constructor. - ASIO_DECL reactive_socket_service_base( - asio::io_context& io_context); + ASIO_DECL reactive_socket_service_base(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void base_shutdown(); @@ -73,7 +75,7 @@ public: // Move-construct a new socket implementation. ASIO_DECL void base_move_construct(base_implementation_type& impl, - base_implementation_type& other_impl); + base_implementation_type& other_impl) noexcept; // Move-assign from another socket implementation. ASIO_DECL void base_move_assign(base_implementation_type& impl, @@ -93,6 +95,10 @@ public: ASIO_DECL asio::error_code close( base_implementation_type& impl, asio::error_code& ec); + // Release ownership of the socket. + ASIO_DECL socket_type release( + base_implementation_type& impl, asio::error_code& ec); + // Get the native socket representation. native_handle_type native_handle(base_implementation_type& impl) { @@ -189,18 +195,21 @@ public: // Asynchronously wait for the socket to become ready to read, ready to // write, or to have pending error conditions. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_wait(base_implementation_type& impl, - socket_base::wait_type w, Handler& handler) + socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_wait_op<Handler> op; + typedef reactive_wait_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_wait")); @@ -208,23 +217,32 @@ public: int op_type; switch (w) { - case socket_base::wait_read: - op_type = reactor::read_op; - break; - case socket_base::wait_write: - op_type = reactor::write_op; - break; - case socket_base::wait_error: - op_type = reactor::except_op; - break; - default: - p.p->ec_ = asio::error::invalid_argument; - reactor_.post_immediate_completion(p.p, is_continuation); - p.v = p.p = 0; - return; + case socket_base::wait_read: + op_type = reactor::read_op; + break; + case socket_base::wait_write: + op_type = reactor::write_op; + break; + case socket_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = asio::error::invalid_argument; + start_op(impl, reactor::read_op, p.p, + is_continuation, false, true, &io_ex, 0); + p.v = p.p = 0; + return; } - start_op(impl, op_type, p.p, is_continuation, false, false); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, op_type); + } + + start_op(impl, op_type, p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -234,11 +252,21 @@ public: const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence> bufs(buffers); + typedef buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence> bufs_type; - return socket_ops::sync_send(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_send1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } } // Wait until data can be sent without blocking. @@ -253,19 +281,32 @@ public: // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send(base_implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_send_op<ConstBufferSequence, Handler> op; + typedef reactive_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send")); @@ -273,28 +314,40 @@ public: start_op(impl, reactor::write_op, p.p, is_continuation, true, ((impl.state_ & socket_ops::stream_oriented) && buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::all_empty(buffers))); + ConstBufferSequence>::all_empty(buffers)), &io_ex, 0); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send(base_implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_null_buffers_op<Handler> op; + typedef reactive_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send(null_buffers)")); - start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -304,11 +357,21 @@ public: const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { - buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence> bufs(buffers); + typedef buffer_sequence_adapter<asio::mutable_buffer, + MutableBufferSequence> bufs_type; - return socket_ops::sync_recv(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_recv1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } } // Wait until data can be received without blocking. @@ -323,19 +386,33 @@ public: // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive(base_implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op; + typedef reactive_socket_recv_op< + MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive")); @@ -347,23 +424,35 @@ public: (flags & socket_base::message_out_of_band) == 0, ((impl.state_ & socket_ops::stream_oriented) && buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::all_empty(buffers))); + MutableBufferSequence>::all_empty(buffers)), &io_ex, 0); p.v = p.p = 0; } // Wait until data can be received without blocking. - template <typename Handler> - void async_receive(base_implementation_type& impl, const null_buffers&, - socket_base::message_flags flags, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_receive(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_null_buffers_op<Handler> op; + typedef reactive_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive(null_buffers)")); @@ -371,7 +460,7 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, false, false); + p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -407,19 +496,34 @@ public: // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive_with_flags(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags in_flags, - socket_base::message_flags& out_flags, Handler& handler) + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op; + typedef reactive_socket_recvmsg_op< + MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler); + p.p = new (p.v) op(success_ec_, impl.socket_, + buffers, in_flags, out_flags, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags")); @@ -428,24 +532,36 @@ public: (in_flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, p.p, is_continuation, - (in_flags & socket_base::message_out_of_band) == 0, false); + (in_flags & socket_base::message_out_of_band) == 0, false, &io_ex, 0); p.v = p.p = 0; } // Wait until data can be received without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_receive_with_flags(base_implementation_type& impl, const null_buffers&, socket_base::message_flags in_flags, - socket_base::message_flags& out_flags, Handler& handler) + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef reactive_null_buffers_op<Handler> op; + typedef reactive_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(success_ec_, handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<reactor_op_cancellation>( + &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op); + } ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); @@ -457,7 +573,7 @@ public: start_op(impl, (in_flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, false, false); + p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -473,23 +589,149 @@ protected: const native_handle_type& native_socket, asio::error_code& ec); // Start the asynchronous read or write operation. - ASIO_DECL void start_op(base_implementation_type& impl, int op_type, - reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + ASIO_DECL void do_start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous operation for handlers that are specialised for + // immediate completion. + template <typename Op> + void start_op(base_implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, + const void* io_ex, ...) + { + return do_start_op(impl, op_type, op, is_continuation, + is_non_blocking, noop, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template <typename Op> + void start_op(base_implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, const void*, + enable_if_t< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >*) + { + return do_start_op(impl, op_type, op, is_continuation, is_non_blocking, + noop, &reactor::call_post_immediate_completion, &reactor_); + } // Start the asynchronous accept operation. - ASIO_DECL void start_accept_op(base_implementation_type& impl, - reactor_op* op, bool is_continuation, bool peer_is_open); + ASIO_DECL void do_start_accept_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous accept operation for handlers that are specialised + // for immediate completion. + template <typename Op> + void start_accept_op(base_implementation_type& impl, Op* op, + bool is_continuation, bool peer_is_open, const void* io_ex, ...) + { + return do_start_accept_op(impl, op, is_continuation, + peer_is_open, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template <typename Op> + void start_accept_op(base_implementation_type& impl, Op* op, + bool is_continuation, bool peer_is_open, const void*, + enable_if_t< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >*) + { + return do_start_accept_op(impl, op, is_continuation, peer_is_open, + &reactor::call_post_immediate_completion, &reactor_); + } // Start the asynchronous connect operation. - ASIO_DECL void start_connect_op(base_implementation_type& impl, - reactor_op* op, bool is_continuation, - const socket_addr_type* addr, size_t addrlen); + ASIO_DECL void do_start_connect_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, const void* addr, size_t addrlen, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous operation for handlers that are specialised for + // immediate completion. + template <typename Op> + void start_connect_op(base_implementation_type& impl, + Op* op, bool is_continuation, const void* addr, + size_t addrlen, const void* io_ex, ...) + { + return do_start_connect_op(impl, op, is_continuation, + addr, addrlen, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template <typename Op> + void start_connect_op(base_implementation_type& impl, Op* op, + bool is_continuation, const void* addr, size_t addrlen, const void*, + enable_if_t< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >*) + { + return do_start_connect_op(impl, op, is_continuation, addr, + addrlen, &reactor::call_post_immediate_completion, &reactor_); + } - // The io_context that owns this socket service. - io_context& io_context_; + // Helper class used to implement per-operation cancellation + class reactor_op_cancellation + { + public: + reactor_op_cancellation(reactor* r, + reactor::per_descriptor_data* p, socket_type d, int o) + : reactor_(r), + reactor_data_(p), + descriptor_(d), + op_type_(o) + { + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + reactor_->cancel_ops_by_key(descriptor_, + *reactor_data_, op_type_, this); + } + } + + private: + reactor* reactor_; + reactor::per_descriptor_data* reactor_data_; + socket_type descriptor_; + int op_type_; + }; // The selector that performs event demultiplexing for the service. reactor& reactor_; + + // Cached success value to avoid accessing category singleton. + const asio::error_code success_ec_; }; } // namespace detail @@ -503,5 +745,6 @@ protected: #endif // !defined(ASIO_HAS_IOCP) // && !defined(ASIO_WINDOWS_RUNTIME) + // && !defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP diff --git a/3rdparty/asio/include/asio/detail/reactive_wait_op.hpp b/3rdparty/asio/include/asio/detail/reactive_wait_op.hpp index 99f8811cf9a..62938e2d83e 100644 --- a/3rdparty/asio/include/asio/detail/reactive_wait_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactive_wait_op.hpp @@ -2,7 +2,7 @@ // detail/reactive_wait_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" @@ -27,18 +28,22 @@ namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class reactive_wait_op : public reactor_op { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); - reactive_wait_op(Handler& handler) - : reactor_op(&reactive_wait_op::do_perform, + reactive_wait_op(const asio::error_code& success_ec, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(success_ec, &reactive_wait_op::do_perform, &reactive_wait_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static status do_perform(reactor_op*) @@ -51,12 +56,17 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. + ASIO_ASSUME(base != 0); reactive_wait_op* o(static_cast<reactive_wait_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -78,8 +88,39 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + ASIO_ASSUME(base != 0); + reactive_wait_op* o(static_cast<reactive_wait_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1<Handler, asio::error_code> + handler(o->handler_, o->ec_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_, io_ex); + ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/reactor.hpp b/3rdparty/asio/include/asio/detail/reactor.hpp index 1f684a22e2b..054acfdab00 100644 --- a/3rdparty/asio/include/asio/detail/reactor.hpp +++ b/3rdparty/asio/include/asio/detail/reactor.hpp @@ -2,7 +2,7 @@ // detail/reactor.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,18 +15,40 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/reactor_fwd.hpp" +#include "asio/detail/config.hpp" -#if defined(ASIO_HAS_EPOLL) +#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_reactor.hpp" +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/null_reactor.hpp" +#elif defined(ASIO_HAS_EPOLL) # include "asio/detail/epoll_reactor.hpp" #elif defined(ASIO_HAS_KQUEUE) # include "asio/detail/kqueue_reactor.hpp" #elif defined(ASIO_HAS_DEV_POLL) # include "asio/detail/dev_poll_reactor.hpp" -#elif defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/null_reactor.hpp" #else # include "asio/detail/select_reactor.hpp" #endif +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) +typedef null_reactor reactor; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +typedef null_reactor reactor; +#elif defined(ASIO_HAS_EPOLL) +typedef epoll_reactor reactor; +#elif defined(ASIO_HAS_KQUEUE) +typedef kqueue_reactor reactor; +#elif defined(ASIO_HAS_DEV_POLL) +typedef dev_poll_reactor reactor; +#else +typedef select_reactor reactor; +#endif + +} // namespace detail +} // namespace asio + #endif // ASIO_DETAIL_REACTOR_HPP diff --git a/3rdparty/asio/include/asio/detail/reactor_fwd.hpp b/3rdparty/asio/include/asio/detail/reactor_fwd.hpp deleted file mode 100644 index 1b25e69a281..00000000000 --- a/3rdparty/asio/include/asio/detail/reactor_fwd.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// detail/reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_REACTOR_FWD_HPP -#define ASIO_DETAIL_REACTOR_FWD_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -namespace asio { -namespace detail { - -#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME) -typedef class null_reactor reactor; -#elif defined(ASIO_HAS_IOCP) -typedef class select_reactor reactor; -#elif defined(ASIO_HAS_EPOLL) -typedef class epoll_reactor reactor; -#elif defined(ASIO_HAS_KQUEUE) -typedef class kqueue_reactor reactor; -#elif defined(ASIO_HAS_DEV_POLL) -typedef class dev_poll_reactor reactor; -#else -typedef class select_reactor reactor; -#endif - -} // namespace detail -} // namespace asio - -#endif // ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/3rdparty/asio/include/asio/detail/reactor_op.hpp b/3rdparty/asio/include/asio/detail/reactor_op.hpp index 491787b09f2..54d6cd964eb 100644 --- a/3rdparty/asio/include/asio/detail/reactor_op.hpp +++ b/3rdparty/asio/include/asio/detail/reactor_op.hpp @@ -2,7 +2,7 @@ // detail/reactor_op.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,6 +30,9 @@ public: // The error code to be passed to the completion handler. asio::error_code ec_; + // The operation key used for targeted cancellation. + void* cancellation_key_; + // The number of bytes transferred, to be passed to the completion handler. std::size_t bytes_transferred_; @@ -46,8 +49,11 @@ public: protected: typedef status (*perform_func_type)(reactor_op*); - reactor_op(perform_func_type perform_func, func_type complete_func) + reactor_op(const asio::error_code& success_ec, + perform_func_type perform_func, func_type complete_func) : operation(complete_func), + ec_(success_ec), + cancellation_key_(0), bytes_transferred_(0), perform_func_(perform_func) { diff --git a/3rdparty/asio/include/asio/detail/reactor_op_queue.hpp b/3rdparty/asio/include/asio/detail/reactor_op_queue.hpp index 426adfbc94d..fae1a52d9e7 100644 --- a/3rdparty/asio/include/asio/detail/reactor_op_queue.hpp +++ b/3rdparty/asio/include/asio/detail/reactor_op_queue.hpp @@ -2,7 +2,7 @@ // detail/reactor_op_queue.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -100,6 +100,50 @@ public: return this->cancel_operations(operations_.find(descriptor), ops, ec); } + // Cancel operations associated with the descriptor identified by the + // supplied iterator, and the specified cancellation key. Any operations + // pending for the descriptor with the key will be cancelled. Returns true if + // any operations were cancelled, in which case the reactor's event + // demultiplexing function may need to be interrupted and restarted. + bool cancel_operations_by_key(iterator i, op_queue<operation>& ops, + void* cancellation_key, const asio::error_code& ec = + asio::error::operation_aborted) + { + bool result = false; + if (i != operations_.end()) + { + op_queue<reactor_op> other_ops; + while (reactor_op* op = i->second.front()) + { + i->second.pop(); + if (op->cancellation_key_ == cancellation_key) + { + op->ec_ = ec; + ops.push(op); + result = true; + } + else + other_ops.push(op); + } + i->second.push(other_ops); + if (i->second.empty()) + operations_.erase(i); + } + return result; + } + + // Cancel all operations associated with the descriptor. Any operations + // pending for the descriptor will be cancelled. Returns true if any + // operations were cancelled, in which case the reactor's event + // demultiplexing function may need to be interrupted and restarted. + bool cancel_operations_by_key(Descriptor descriptor, op_queue<operation>& ops, + void* cancellation_key, const asio::error_code& ec = + asio::error::operation_aborted) + { + return this->cancel_operations_by_key( + operations_.find(descriptor), ops, cancellation_key, ec); + } + // Whether there are no operations in the queue. bool empty() const { diff --git a/3rdparty/asio/include/asio/detail/recycling_allocator.hpp b/3rdparty/asio/include/asio/detail/recycling_allocator.hpp index 2abc0a2f9aa..d556f22a399 100644 --- a/3rdparty/asio/include/asio/detail/recycling_allocator.hpp +++ b/3rdparty/asio/include/asio/detail/recycling_allocator.hpp @@ -2,7 +2,7 @@ // detail/recycling_allocator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -25,14 +25,16 @@ namespace asio { namespace detail { -template <typename T> +template <typename T, typename Purpose = thread_info_base::default_tag> class recycling_allocator { public: + typedef T value_type; + template <typename U> struct rebind { - typedef recycling_allocator<U> other; + typedef recycling_allocator<U, Purpose> other; }; recycling_allocator() @@ -40,32 +42,35 @@ public: } template <typename U> - recycling_allocator(const recycling_allocator<U>&) + recycling_allocator(const recycling_allocator<U, Purpose>&) { } T* allocate(std::size_t n) { - typedef thread_context::thread_call_stack call_stack; - void* p = thread_info_base::allocate(call_stack::top(), sizeof(T) * n); + void* p = thread_info_base::allocate(Purpose(), + thread_context::top_of_thread_call_stack(), + sizeof(T) * n, alignof(T)); return static_cast<T*>(p); } void deallocate(T* p, std::size_t n) { - typedef thread_context::thread_call_stack call_stack; - thread_info_base::deallocate(call_stack::top(), p, sizeof(T) * n); + thread_info_base::deallocate(Purpose(), + thread_context::top_of_thread_call_stack(), p, sizeof(T) * n); } }; -template <> -class recycling_allocator<void> +template <typename Purpose> +class recycling_allocator<void, Purpose> { public: + typedef void value_type; + template <typename U> struct rebind { - typedef recycling_allocator<U> other; + typedef recycling_allocator<U, Purpose> other; }; recycling_allocator() @@ -73,22 +78,22 @@ public: } template <typename U> - recycling_allocator(const recycling_allocator<U>&) + recycling_allocator(const recycling_allocator<U, Purpose>&) { } }; -template <typename Allocator> +template <typename Allocator, typename Purpose> struct get_recycling_allocator { typedef Allocator type; static type get(const Allocator& a) { return a; } }; -template <typename T> -struct get_recycling_allocator<std::allocator<T> > +template <typename T, typename Purpose> +struct get_recycling_allocator<std::allocator<T>, Purpose> { - typedef recycling_allocator<T> type; + typedef recycling_allocator<T, Purpose> type; static type get(const std::allocator<T>&) { return type(); } }; diff --git a/3rdparty/asio/include/asio/detail/regex_fwd.hpp b/3rdparty/asio/include/asio/detail/regex_fwd.hpp index 447c6b13fd6..a5c6c0a9428 100644 --- a/3rdparty/asio/include/asio/detail/regex_fwd.hpp +++ b/3rdparty/asio/include/asio/detail/regex_fwd.hpp @@ -2,7 +2,7 @@ // detail/regex_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,9 +17,6 @@ #if defined(ASIO_HAS_BOOST_REGEX) -#include <boost/regex_fwd.hpp> -#include <boost/regex/v4/match_flags.hpp> - namespace boost { template <class BidiIterator> @@ -28,6 +25,9 @@ struct sub_match; template <class BidiIterator, class Allocator> class match_results; +template <class CharT, class Traits> +class basic_regex; + } // namespace boost #endif // defined(ASIO_HAS_BOOST_REGEX) diff --git a/3rdparty/asio/include/asio/detail/resolve_endpoint_op.hpp b/3rdparty/asio/include/asio/detail/resolve_endpoint_op.hpp index 234ac2421f1..c7cb2c4c101 100644 --- a/3rdparty/asio/include/asio/detail/resolve_endpoint_op.hpp +++ b/3rdparty/asio/include/asio/detail/resolve_endpoint_op.hpp @@ -2,7 +2,7 @@ // detail/resolve_endpoint_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,23 +16,28 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" -#include "asio/ip/basic_resolver_results.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/resolve_op.hpp" #include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" +#include "asio/ip/basic_resolver_results.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename Protocol, typename Handler> +template <typename Protocol, typename Handler, typename IoExecutor> class resolve_endpoint_op : public resolve_op { public: @@ -41,15 +46,22 @@ public: typedef typename Protocol::endpoint endpoint_type; typedef asio::ip::basic_resolver_results<Protocol> results_type; +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, - const endpoint_type& endpoint, io_context_impl& ioc, Handler& handler) + const endpoint_type& endpoint, scheduler_impl& sched, + Handler& handler, const IoExecutor& io_ex) : resolve_op(&resolve_endpoint_op::do_complete), cancel_token_(cancel_token), endpoint_(endpoint), - io_context_impl_(ioc), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + scheduler_(sched), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -57,25 +69,25 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the operation object. + ASIO_ASSUME(base != 0); resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); - if (owner && owner != &o->io_context_impl_) + if (owner && owner != &o->scheduler_) { // The operation is being run on the worker io_context. Time to perform // the resolver operation. // Perform the blocking endpoint resolution operation. - char host_name[NI_MAXHOST]; - char service_name[NI_MAXSERV]; + char host_name[NI_MAXHOST] = ""; + char service_name[NI_MAXSERV] = ""; socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, o->endpoint_.protocol().type(), o->ec_); o->results_ = results_type::create(o->endpoint_, host_name, service_name); // Pass operation back to main io_context for completion. - o->io_context_impl_.post_deferred_completion(o); + o->scheduler_.post_deferred_completion(o); p.v = p.p = 0; } else @@ -85,6 +97,11 @@ public: ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated // before the upcall is made. Even if we're not about to make an upcall, // a sub-object of the handler may be the true owner of the memory @@ -109,8 +126,9 @@ public: private: socket_ops::weak_cancel_token_type cancel_token_; endpoint_type endpoint_; - io_context_impl& io_context_impl_; + scheduler_impl& scheduler_; Handler handler_; + handler_work<Handler, IoExecutor> work_; results_type results_; }; diff --git a/3rdparty/asio/include/asio/detail/resolve_op.hpp b/3rdparty/asio/include/asio/detail/resolve_op.hpp index 724edc557ec..5b41ad2fe68 100644 --- a/3rdparty/asio/include/asio/detail/resolve_op.hpp +++ b/3rdparty/asio/include/asio/detail/resolve_op.hpp @@ -2,7 +2,7 @@ // detail/resolve_op.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/resolve_query_op.hpp b/3rdparty/asio/include/asio/detail/resolve_query_op.hpp index 0ce450b5ea5..b7f9e35cef0 100644 --- a/3rdparty/asio/include/asio/detail/resolve_query_op.hpp +++ b/3rdparty/asio/include/asio/detail/resolve_query_op.hpp @@ -2,7 +2,7 @@ // detail/resolve_query_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,24 +16,29 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" -#include "asio/ip/basic_resolver_query.hpp" -#include "asio/ip/basic_resolver_results.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/resolve_op.hpp" #include "asio/detail/socket_ops.hpp" +#include "asio/error.hpp" +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/basic_resolver_results.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename Protocol, typename Handler> +template <typename Protocol, typename Handler, typename IoExecutor> class resolve_query_op : public resolve_op { public: @@ -42,16 +47,23 @@ public: typedef asio::ip::basic_resolver_query<Protocol> query_type; typedef asio::ip::basic_resolver_results<Protocol> results_type; +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + resolve_query_op(socket_ops::weak_cancel_token_type cancel_token, - const query_type& query, io_context_impl& ioc, Handler& handler) + const query_type& qry, scheduler_impl& sched, + Handler& handler, const IoExecutor& io_ex) : resolve_op(&resolve_query_op::do_complete), cancel_token_(cancel_token), - query_(query), - io_context_impl_(ioc), - handler_(ASIO_MOVE_CAST(Handler)(handler)), + query_(qry), + scheduler_(sched), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex), addrinfo_(0) { - handler_work<Handler>::start(handler_); } ~resolve_query_op() @@ -65,11 +77,11 @@ public: std::size_t /*bytes_transferred*/) { // Take ownership of the operation object. + ASIO_ASSUME(base != 0); resolve_query_op* o(static_cast<resolve_query_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); - if (owner && owner != &o->io_context_impl_) + if (owner && owner != &o->scheduler_) { // The operation is being run on the worker io_context. Time to perform // the resolver operation. @@ -80,7 +92,7 @@ public: o->query_.hints(), &o->addrinfo_, o->ec_); // Pass operation back to main io_context for completion. - o->io_context_impl_.post_deferred_completion(o); + o->scheduler_.post_deferred_completion(o); p.v = p.p = 0; } else @@ -90,6 +102,11 @@ public: ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated // before the upcall is made. Even if we're not about to make an upcall, // a sub-object of the handler may be the true owner of the memory @@ -119,8 +136,9 @@ public: private: socket_ops::weak_cancel_token_type cancel_token_; query_type query_; - io_context_impl& io_context_impl_; + scheduler_impl& scheduler_; Handler handler_; + handler_work<Handler, IoExecutor> work_; asio::detail::addrinfo_type* addrinfo_; }; diff --git a/3rdparty/asio/include/asio/detail/resolver_service.hpp b/3rdparty/asio/include/asio/detail/resolver_service.hpp index 155e4f30225..2d1fe22b62a 100644 --- a/3rdparty/asio/include/asio/detail/resolver_service.hpp +++ b/3rdparty/asio/include/asio/detail/resolver_service.hpp @@ -2,7 +2,7 @@ // detail/resolver_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -34,7 +34,7 @@ namespace detail { template <typename Protocol> class resolver_service : - public service_base<resolver_service<Protocol> >, + public execution_context_service_base<resolver_service<Protocol>>, public resolver_service_base { public: @@ -52,9 +52,9 @@ public: typedef asio::ip::basic_resolver_results<Protocol> results_type; // Constructor. - resolver_service(asio::io_context& io_context) - : service_base<resolver_service<Protocol> >(io_context), - resolver_service_base(io_context) + resolver_service(execution_context& context) + : execution_context_service_base<resolver_service<Protocol>>(context), + resolver_service_base(context) { } @@ -65,37 +65,38 @@ public: } // Perform any fork-related housekeeping. - void notify_fork(asio::io_context::fork_event fork_ev) + void notify_fork(execution_context::fork_event fork_ev) { this->base_notify_fork(fork_ev); } // Resolve a query to a list of entries. - results_type resolve(implementation_type&, const query_type& query, + results_type resolve(implementation_type&, const query_type& qry, asio::error_code& ec) { asio::detail::addrinfo_type* address_info = 0; - socket_ops::getaddrinfo(query.host_name().c_str(), - query.service_name().c_str(), query.hints(), &address_info, ec); + socket_ops::getaddrinfo(qry.host_name().c_str(), + qry.service_name().c_str(), qry.hints(), &address_info, ec); auto_addrinfo auto_address_info(address_info); + ASIO_ERROR_LOCATION(ec); return ec ? results_type() : results_type::create( - address_info, query.host_name(), query.service_name()); + address_info, qry.host_name(), qry.service_name()); } // Asynchronously resolve a query to a list of entries. - template <typename Handler> - void async_resolve(implementation_type& impl, - const query_type& query, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_resolve(implementation_type& impl, const query_type& qry, + Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. - typedef resolve_query_op<Protocol, Handler> op; + typedef resolve_query_op<Protocol, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl, query, io_context_impl_, handler); + p.p = new (p.v) op(impl, qry, scheduler_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_impl_.context(), + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "resolver", &impl, 0, "async_resolve")); start_resolve_op(p.p); @@ -112,22 +113,23 @@ public: host_name, NI_MAXHOST, service_name, NI_MAXSERV, endpoint.protocol().type(), ec); + ASIO_ERROR_LOCATION(ec); return ec ? results_type() : results_type::create( endpoint, host_name, service_name); } // Asynchronously resolve an endpoint to a list of entries. - template <typename Handler> - void async_resolve(implementation_type& impl, - const endpoint_type& endpoint, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_resolve(implementation_type& impl, const endpoint_type& endpoint, + Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. - typedef resolve_endpoint_op<Protocol, Handler> op; + typedef resolve_endpoint_op<Protocol, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl, endpoint, io_context_impl_, handler); + p.p = new (p.v) op(impl, endpoint, scheduler_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_impl_.context(), + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "resolver", &impl, 0, "async_resolve")); start_resolve_op(p.p); diff --git a/3rdparty/asio/include/asio/detail/resolver_service_base.hpp b/3rdparty/asio/include/asio/detail/resolver_service_base.hpp index e3dd4f7edd7..160793c89cb 100644 --- a/3rdparty/asio/include/asio/detail/resolver_service_base.hpp +++ b/3rdparty/asio/include/asio/detail/resolver_service_base.hpp @@ -2,7 +2,7 @@ // detail/resolver_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,8 +17,7 @@ #include "asio/detail/config.hpp" #include "asio/error.hpp" -#include "asio/executor_work_guard.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/resolve_op.hpp" @@ -27,6 +26,12 @@ #include "asio/detail/scoped_ptr.hpp" #include "asio/detail/thread.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + #include "asio/detail/push_options.hpp" namespace asio { @@ -40,7 +45,7 @@ public: typedef socket_ops::shared_cancel_token_type implementation_type; // Constructor. - ASIO_DECL resolver_service_base(asio::io_context& io_context); + ASIO_DECL resolver_service_base(execution_context& context); // Destructor. ASIO_DECL ~resolver_service_base(); @@ -50,7 +55,7 @@ public: // Perform any fork-related housekeeping. ASIO_DECL void base_notify_fork( - asio::io_context::fork_event fork_ev); + execution_context::fork_event fork_ev); // Construct a new resolver implementation. ASIO_DECL void construct(implementation_type& impl); @@ -67,6 +72,21 @@ public: resolver_service_base& other_service, implementation_type& other_impl); + // Move-construct a new timer implementation. + void converting_move_construct(implementation_type& impl, + resolver_service_base&, implementation_type& other_impl) + { + move_construct(impl, other_impl); + } + + // Move-assign from another timer implementation. + void converting_move_assign(implementation_type& impl, + resolver_service_base& other_service, + implementation_type& other_impl) + { + move_assign(impl, other_service, other_impl); + } + // Cancel pending asynchronous operations. ASIO_DECL void cancel(implementation_type& impl); @@ -101,28 +121,26 @@ protected: }; #endif // !defined(ASIO_WINDOWS_RUNTIME) - // Helper class to run the work io_context in a thread. - class work_io_context_runner; + // Helper class to run the work scheduler in a thread. + class work_scheduler_runner; - // Start the work thread if it's not already running. + // Start the work scheduler if it's not already running. ASIO_DECL void start_work_thread(); - // The io_context implementation used to post completions. - io_context_impl& io_context_impl_; + // The scheduler implementation used to post completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; private: // Mutex to protect access to internal data. asio::detail::mutex mutex_; - // Private io_context used for performing asynchronous host resolution. - asio::detail::scoped_ptr<asio::io_context> work_io_context_; - - // The work io_context implementation used to post completions. - io_context_impl& work_io_context_impl_; - - // Work for the private io_context to perform. - asio::executor_work_guard< - asio::io_context::executor_type> work_; + // Private scheduler used for performing asynchronous host resolution. + asio::detail::scoped_ptr<scheduler_impl> work_scheduler_; // Thread used for running the work io_context's run loop. asio::detail::scoped_ptr<asio::detail::thread> work_thread_; diff --git a/3rdparty/asio/include/asio/detail/scheduler.hpp b/3rdparty/asio/include/asio/detail/scheduler.hpp index 37814723c83..a73ec141ebc 100644 --- a/3rdparty/asio/include/asio/detail/scheduler.hpp +++ b/3rdparty/asio/include/asio/detail/scheduler.hpp @@ -2,7 +2,7 @@ // detail/scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,8 +23,9 @@ #include "asio/detail/conditionally_enabled_event.hpp" #include "asio/detail/conditionally_enabled_mutex.hpp" #include "asio/detail/op_queue.hpp" -#include "asio/detail/reactor_fwd.hpp" #include "asio/detail/scheduler_operation.hpp" +#include "asio/detail/scheduler_task.hpp" +#include "asio/detail/thread.hpp" #include "asio/detail/thread_context.hpp" #include "asio/detail/push_options.hpp" @@ -41,10 +42,18 @@ class scheduler public: typedef scheduler_operation operation; + // The type of a function used to obtain a task instance. + typedef scheduler_task* (*get_task_func_type)( + asio::execution_context&); + // Constructor. Specifies the number of concurrent threads that are likely to // run the scheduler. If set to 1 certain optimisation are performed. ASIO_DECL scheduler(asio::execution_context& ctx, - int concurrency_hint = 0); + int concurrency_hint = 0, bool own_thread = true, + get_task_func_type get_task = &scheduler::get_default_task); + + // Destructor. + ASIO_DECL ~scheduler(); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown(); @@ -95,16 +104,21 @@ public: } // Return whether a handler can be dispatched immediately. - bool can_dispatch() - { - return thread_call_stack::contains(this) != 0; - } + ASIO_DECL bool can_dispatch(); + + /// Capture the current exception so it can be rethrown from a run function. + ASIO_DECL void capture_current_exception(); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. ASIO_DECL void post_immediate_completion( operation* op, bool is_continuation); + // Request invocation of the given operations and return immediately. Assumes + // that work_started() has not yet been called for the operations. + ASIO_DECL void post_immediate_completions(std::size_t n, + op_queue<operation>& ops, bool is_continuation); + // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. ASIO_DECL void post_deferred_completion(operation* op); @@ -156,6 +170,14 @@ private: ASIO_DECL void wake_one_thread_and_unlock( mutex::scoped_lock& lock); + // Get the default task. + ASIO_DECL static scheduler_task* get_default_task( + asio::execution_context& ctx); + + // Helper class to run the scheduler in its own thread. + class thread_function; + friend class thread_function; + // Helper class to perform task-related operations on block exit. struct task_cleanup; friend struct task_cleanup; @@ -174,7 +196,10 @@ private: event wakeup_event_; // The task to be run by this service. - reactor* task_; + scheduler_task* task_; + + // The function used to get the task. + get_task_func_type get_task_; // Operation object to represent the position of the task in the queue. struct task_operation : operation @@ -199,6 +224,9 @@ private: // The concurrency hint used to initialise the scheduler. const int concurrency_hint_; + + // The thread that is running the scheduler. + asio::detail::thread* thread_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/scheduler_operation.hpp b/3rdparty/asio/include/asio/detail/scheduler_operation.hpp index 112b3dfc3d3..1b4ceb36f5c 100644 --- a/3rdparty/asio/include/asio/detail/scheduler_operation.hpp +++ b/3rdparty/asio/include/asio/detail/scheduler_operation.hpp @@ -2,7 +2,7 @@ // detail/scheduler_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/scheduler_task.hpp b/3rdparty/asio/include/asio/detail/scheduler_task.hpp new file mode 100644 index 00000000000..a1a4ec1c85f --- /dev/null +++ b/3rdparty/asio/include/asio/detail/scheduler_task.hpp @@ -0,0 +1,49 @@ +// +// detail/scheduler_task.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_SCHEDULER_TASK_HPP +#define ASIO_DETAIL_SCHEDULER_TASK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/op_queue.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class scheduler_operation; + +// Base class for all tasks that may be run by a scheduler. +class scheduler_task +{ +public: + // Run the task once until interrupted or events are ready to be dispatched. + virtual void run(long usec, op_queue<scheduler_operation>& ops) = 0; + + // Interrupt the task. + virtual void interrupt() = 0; + +protected: + // Prevent deletion through this type. + ~scheduler_task() + { + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SCHEDULER_TASK_HPP diff --git a/3rdparty/asio/include/asio/detail/scheduler_thread_info.hpp b/3rdparty/asio/include/asio/detail/scheduler_thread_info.hpp index aa8260c1d7e..410d2866b59 100644 --- a/3rdparty/asio/include/asio/detail/scheduler_thread_info.hpp +++ b/3rdparty/asio/include/asio/detail/scheduler_thread_info.hpp @@ -2,7 +2,7 @@ // detail/scheduler_thread_info.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/scoped_lock.hpp b/3rdparty/asio/include/asio/detail/scoped_lock.hpp index cf526141691..778832d6350 100644 --- a/3rdparty/asio/include/asio/detail/scoped_lock.hpp +++ b/3rdparty/asio/include/asio/detail/scoped_lock.hpp @@ -2,7 +2,7 @@ // detail/scoped_lock.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/scoped_ptr.hpp b/3rdparty/asio/include/asio/detail/scoped_ptr.hpp index 3bc26f1a3ea..a517c2b947c 100644 --- a/3rdparty/asio/include/asio/detail/scoped_ptr.hpp +++ b/3rdparty/asio/include/asio/detail/scoped_ptr.hpp @@ -2,7 +2,7 @@ // detail/scoped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/select_interrupter.hpp b/3rdparty/asio/include/asio/detail/select_interrupter.hpp index ecac7dbfdfd..57cb4ce8d71 100644 --- a/3rdparty/asio/include/asio/detail/select_interrupter.hpp +++ b/3rdparty/asio/include/asio/detail/select_interrupter.hpp @@ -2,7 +2,7 @@ // detail/select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/select_reactor.hpp b/3rdparty/asio/include/asio/detail/select_reactor.hpp index 7f9b55b2174..7fe647b7e63 100644 --- a/3rdparty/asio/include/asio/detail/select_reactor.hpp +++ b/3rdparty/asio/include/asio/detail/select_reactor.hpp @@ -2,7 +2,7 @@ // detail/select_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,6 +30,7 @@ #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/scheduler_task.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_queue_base.hpp" @@ -48,6 +49,9 @@ namespace detail { class select_reactor : public execution_context_service_base<select_reactor> +#if !defined(ASIO_HAS_IOCP) + , public scheduler_task +#endif // !defined(ASIO_HAS_IOCP) { public: #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) @@ -90,29 +94,57 @@ public: per_descriptor_data& descriptor_data, reactor_op* op); // Post a reactor operation for immediate completion. - void post_immediate_completion(reactor_op* op, bool is_continuation) - { - scheduler_.post_immediate_completion(op, is_continuation); - } + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool is_continuation, bool); + per_descriptor_data&, reactor_op* op, bool is_continuation, bool, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &select_reactor::call_post_immediate_completion, this); + } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + // Cancel all operations associated with the given descriptor and key. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + ASIO_DECL void cancel_ops_by_key(socket_type descriptor, + per_descriptor_data& descriptor_data, + int op_type, void* cancellation_key); + // Cancel any operations that are running against the descriptor and remove - // its registration from the reactor. + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. ASIO_DECL void deregister_descriptor(socket_type descriptor, per_descriptor_data&, bool closing); - // Remote the descriptor's registration from the reactor. + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. ASIO_DECL void deregister_internal_descriptor( - socket_type descriptor, per_descriptor_data& descriptor_data); + socket_type descriptor, per_descriptor_data&); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); // Move descriptor registration from one descriptor_data object to another. ASIO_DECL void move_descriptor(socket_type descriptor, @@ -141,6 +173,12 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Cancel the timer operations associated with the given key. + template <typename Time_Traits> + void cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key); + // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, @@ -206,6 +244,28 @@ private: // The thread that is running the reactor loop. asio::detail::thread* thread_; + + // Helper class to join and restart the reactor thread. + class restart_reactor : public operation + { + public: + restart_reactor(select_reactor* r) + : operation(&restart_reactor::do_complete), + reactor_(r) + { + } + + ASIO_DECL static void do_complete(void* owner, operation* base, + const asio::error_code& ec, std::size_t bytes_transferred); + + private: + select_reactor* reactor_; + }; + + friend class restart_reactor; + + // Operation used to join and restart the reactor thread. + restart_reactor restart_reactor_; #endif // defined(ASIO_HAS_IOCP) // Whether the service has been shut down. diff --git a/3rdparty/asio/include/asio/detail/service_registry.hpp b/3rdparty/asio/include/asio/detail/service_registry.hpp index 06f49de48a9..991b32a4980 100644 --- a/3rdparty/asio/include/asio/detail/service_registry.hpp +++ b/3rdparty/asio/include/asio/detail/service_registry.hpp @@ -2,7 +2,7 @@ // detail/service_registry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -84,8 +84,7 @@ private: // Initalise a service's key when the key_type typedef is available. template <typename Service> static void init_key(execution_context::service::key& key, - typename enable_if< - is_base_of<typename Service::key_type, Service>::value>::type*); + enable_if_t<is_base_of<typename Service::key_type, Service>::value>*); #endif // !defined(ASIO_NO_TYPEID) // Initialise a service's key based on its id. diff --git a/3rdparty/asio/include/asio/detail/signal_blocker.hpp b/3rdparty/asio/include/asio/detail/signal_blocker.hpp index f0fac082023..11d0b0e9633 100644 --- a/3rdparty/asio/include/asio/detail/signal_blocker.hpp +++ b/3rdparty/asio/include/asio/detail/signal_blocker.hpp @@ -2,7 +2,7 @@ // detail/signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/signal_handler.hpp b/3rdparty/asio/include/asio/detail/signal_handler.hpp index 19fee65c0e4..6d43f578cb9 100644 --- a/3rdparty/asio/include/asio/detail/signal_handler.hpp +++ b/3rdparty/asio/include/asio/detail/signal_handler.hpp @@ -2,7 +2,7 @@ // detail/signal_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,7 +19,6 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/signal_op.hpp" @@ -29,17 +28,17 @@ namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class signal_handler : public signal_op { public: ASIO_DEFINE_HANDLER_PTR(signal_handler); - signal_handler(Handler& h) + signal_handler(Handler& h, const IoExecutor& io_ex) : signal_op(&signal_handler::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(h)) + handler_(static_cast<Handler&&>(h)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -49,10 +48,14 @@ public: // Take ownership of the handler object. signal_handler* h(static_cast<signal_handler*>(base)); ptr p = { asio::detail::addressof(h->handler_), h, h }; - handler_work<Handler> w(h->handler_); ASIO_HANDLER_COMPLETION((*h)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + h->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -76,6 +79,7 @@ public: private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/signal_init.hpp b/3rdparty/asio/include/asio/detail/signal_init.hpp index 266a3e0d045..6f2c7c867e2 100644 --- a/3rdparty/asio/include/asio/detail/signal_init.hpp +++ b/3rdparty/asio/include/asio/detail/signal_init.hpp @@ -2,7 +2,7 @@ // detail/signal_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/signal_op.hpp b/3rdparty/asio/include/asio/detail/signal_op.hpp index 9921de02478..5e0071a5d62 100644 --- a/3rdparty/asio/include/asio/detail/signal_op.hpp +++ b/3rdparty/asio/include/asio/detail/signal_op.hpp @@ -2,7 +2,7 @@ // detail/signal_op.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,12 +30,16 @@ public: // The error code to be passed to the completion handler. asio::error_code ec_; + // The operation key used for targeted cancellation. + void* cancellation_key_; + // The signal number to be passed to the completion handler. int signal_number_; protected: signal_op(func_type func) : operation(func), + cancellation_key_(0), signal_number_(0) { } diff --git a/3rdparty/asio/include/asio/detail/signal_set_service.hpp b/3rdparty/asio/include/asio/detail/signal_set_service.hpp index 58ee99baf3b..142ff43851a 100644 --- a/3rdparty/asio/include/asio/detail/signal_set_service.hpp +++ b/3rdparty/asio/include/asio/detail/signal_set_service.hpp @@ -2,7 +2,7 @@ // detail/signal_set_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,8 +19,11 @@ #include <cstddef> #include <signal.h> +#include "asio/associated_cancellation_slot.hpp" +#include "asio/cancellation_type.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" +#include "asio/signal_set_base.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/op_queue.hpp" @@ -28,8 +31,18 @@ #include "asio/detail/signal_op.hpp" #include "asio/detail/socket_types.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + #if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) -# include "asio/detail/reactor.hpp" +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_service.hpp" +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/reactor.hpp" +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) #include "asio/detail/push_options.hpp" @@ -48,7 +61,7 @@ extern ASIO_DECL struct signal_state* get_signal_state(); extern "C" ASIO_DECL void asio_signal_handler(int signal_number); class signal_set_service : - public service_base<signal_set_service> + public execution_context_service_base<signal_set_service> { public: // Type used for tracking an individual signal registration. @@ -109,7 +122,7 @@ public: }; // Constructor. - ASIO_DECL signal_set_service(asio::io_context& io_context); + ASIO_DECL signal_set_service(execution_context& context); // Destructor. ASIO_DECL ~signal_set_service(); @@ -119,7 +132,7 @@ public: // Perform fork-related housekeeping. ASIO_DECL void notify_fork( - asio::io_context::fork_event fork_ev); + asio::execution_context::fork_event fork_ev); // Construct a new signal_set implementation. ASIO_DECL void construct(implementation_type& impl); @@ -128,8 +141,16 @@ public: ASIO_DECL void destroy(implementation_type& impl); // Add a signal to a signal_set. + asio::error_code add(implementation_type& impl, + int signal_number, asio::error_code& ec) + { + return add(impl, signal_number, signal_set_base::flags::dont_care, ec); + } + + // Add a signal to a signal_set with the specified flags. ASIO_DECL asio::error_code add(implementation_type& impl, - int signal_number, asio::error_code& ec); + int signal_number, signal_set_base::flags_t f, + asio::error_code& ec); // Remove a signal to a signal_set. ASIO_DECL asio::error_code remove(implementation_type& impl, @@ -143,17 +164,32 @@ public: ASIO_DECL asio::error_code cancel(implementation_type& impl, asio::error_code& ec); + // Cancel a specific operation associated with the signal set. + ASIO_DECL void cancel_ops_by_key(implementation_type& impl, + void* cancellation_key); + // Start an asynchronous operation to wait for a signal to be delivered. - template <typename Handler> - void async_wait(implementation_type& impl, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef signal_handler<Handler> op; + typedef signal_handler<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<signal_op_cancellation>(this, &impl); + } - ASIO_HANDLER_CREATION((io_context_.context(), + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "signal_set", &impl, 0, "async_wait")); start_wait_op(impl, p.p); @@ -179,20 +215,59 @@ private: // Helper function to start a wait operation. ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op); - // The io_context instance used for dispatching handlers. - io_context_impl& io_context_; + // Helper class used to implement per-operation cancellation + class signal_op_cancellation + { + public: + signal_op_cancellation(signal_set_service* s, implementation_type* i) + : service_(s), + implementation_(i) + { + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + service_->cancel_ops_by_key(*implementation_, this); + } + } + + private: + signal_set_service* service_; + implementation_type* implementation_; + }; + + // The scheduler used for dispatching handlers. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; #if !defined(ASIO_WINDOWS) \ && !defined(ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) - // The type used for registering for pipe reactor notifications. + // The type used for processing pipe readiness notifications. class pipe_read_op; +# if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + // The io_uring service used for waiting for pipe readiness. + io_uring_service& io_uring_service_; + + // The per I/O object data used for the pipe. + io_uring_service::per_io_object_data io_object_data_; +# else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) // The reactor used for waiting for pipe readiness. reactor& reactor_; // The per-descriptor reactor data used for the pipe. reactor::per_descriptor_data reactor_data_; +# endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) #endif // !defined(ASIO_WINDOWS) // && !defined(ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) diff --git a/3rdparty/asio/include/asio/detail/socket_holder.hpp b/3rdparty/asio/include/asio/detail/socket_holder.hpp index 1c9e7213655..300e3736636 100644 --- a/3rdparty/asio/include/asio/detail/socket_holder.hpp +++ b/3rdparty/asio/include/asio/detail/socket_holder.hpp @@ -2,7 +2,7 @@ // detail/socket_holder.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/socket_ops.hpp b/3rdparty/asio/include/asio/detail/socket_ops.hpp index 5529a27649a..fd2dc09c094 100644 --- a/3rdparty/asio/include/asio/detail/socket_ops.hpp +++ b/3rdparty/asio/include/asio/detail/socket_ops.hpp @@ -2,7 +2,7 @@ // detail/socket_ops.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -63,29 +63,27 @@ typedef weak_ptr<void> weak_cancel_token_type; #if !defined(ASIO_WINDOWS_RUNTIME) -ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, +ASIO_DECL socket_type accept(socket_type s, void* addr, std::size_t* addrlen, asio::error_code& ec); -ASIO_DECL socket_type sync_accept(socket_type s, - state_type state, socket_addr_type* addr, - std::size_t* addrlen, asio::error_code& ec); +ASIO_DECL socket_type sync_accept(socket_type s, state_type state, + void* addr, std::size_t* addrlen, asio::error_code& ec); #if defined(ASIO_HAS_IOCP) -ASIO_DECL void complete_iocp_accept(socket_type s, - void* output_buffer, DWORD address_length, - socket_addr_type* addr, std::size_t* addrlen, +ASIO_DECL void complete_iocp_accept(socket_type s, void* output_buffer, + DWORD address_length, void* addr, std::size_t* addrlen, socket_type new_socket, asio::error_code& ec); #else // defined(ASIO_HAS_IOCP) ASIO_DECL bool non_blocking_accept(socket_type s, - state_type state, socket_addr_type* addr, std::size_t* addrlen, + state_type state, void* addr, std::size_t* addrlen, asio::error_code& ec, socket_type& new_socket); #endif // defined(ASIO_HAS_IOCP) -ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, +ASIO_DECL int bind(socket_type s, const void* addr, std::size_t addrlen, asio::error_code& ec); ASIO_DECL int close(socket_type s, state_type& state, @@ -100,10 +98,10 @@ ASIO_DECL bool set_internal_non_blocking(socket_type s, ASIO_DECL int shutdown(socket_type s, int what, asio::error_code& ec); -ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, +ASIO_DECL int connect(socket_type s, const void* addr, std::size_t addrlen, asio::error_code& ec); -ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, +ASIO_DECL void sync_connect(socket_type s, const void* addr, std::size_t addrlen, asio::error_code& ec); #if defined(ASIO_HAS_IOCP) @@ -139,9 +137,15 @@ ASIO_DECL void init_buf(buf& b, const void* data, size_t size); ASIO_DECL signed_size_type recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec); +ASIO_DECL signed_size_type recv1(socket_type s, + void* data, size_t size, int flags, asio::error_code& ec); + ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, size_t count, int flags, bool all_empty, asio::error_code& ec); +ASIO_DECL size_t sync_recv1(socket_type s, state_type state, + void* data, size_t size, int flags, asio::error_code& ec); + #if defined(ASIO_HAS_IOCP) ASIO_DECL void complete_iocp_recv(state_type state, @@ -154,14 +158,26 @@ ASIO_DECL bool non_blocking_recv(socket_type s, buf* bufs, size_t count, int flags, bool is_stream, asio::error_code& ec, size_t& bytes_transferred); +ASIO_DECL bool non_blocking_recv1(socket_type s, + void* data, size_t size, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred); + #endif // defined(ASIO_HAS_IOCP) -ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs, - size_t count, int flags, socket_addr_type* addr, +ASIO_DECL signed_size_type recvfrom(socket_type s, + buf* bufs, size_t count, int flags, void* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL signed_size_type recvfrom1(socket_type s, + void* data, size_t size, int flags, void* addr, std::size_t* addrlen, asio::error_code& ec); ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, - buf* bufs, size_t count, int flags, socket_addr_type* addr, + buf* bufs, size_t count, int flags, void* addr, + std::size_t* addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_recvfrom1(socket_type s, state_type state, + void* data, size_t size, int flags, void* addr, std::size_t* addrlen, asio::error_code& ec); #if defined(ASIO_HAS_IOCP) @@ -172,9 +188,12 @@ ASIO_DECL void complete_iocp_recvfrom( #else // defined(ASIO_HAS_IOCP) -ASIO_DECL bool non_blocking_recvfrom(socket_type s, - buf* bufs, size_t count, int flags, - socket_addr_type* addr, std::size_t* addrlen, +ASIO_DECL bool non_blocking_recvfrom(socket_type s, buf* bufs, + size_t count, int flags, void* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_recvfrom1(socket_type s, void* data, + size_t size, int flags, void* addr, std::size_t* addrlen, asio::error_code& ec, size_t& bytes_transferred); #endif // defined(ASIO_HAS_IOCP) @@ -204,10 +223,16 @@ ASIO_DECL bool non_blocking_recvmsg(socket_type s, ASIO_DECL signed_size_type send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec); +ASIO_DECL signed_size_type send1(socket_type s, + const void* data, size_t size, int flags, asio::error_code& ec); + ASIO_DECL size_t sync_send(socket_type s, state_type state, const buf* bufs, size_t count, int flags, bool all_empty, asio::error_code& ec); +ASIO_DECL size_t sync_send1(socket_type s, state_type state, + const void* data, size_t size, int flags, asio::error_code& ec); + #if defined(ASIO_HAS_IOCP) ASIO_DECL void complete_iocp_send( @@ -220,21 +245,36 @@ ASIO_DECL bool non_blocking_send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec, size_t& bytes_transferred); +ASIO_DECL bool non_blocking_send1(socket_type s, + const void* data, size_t size, int flags, + asio::error_code& ec, size_t& bytes_transferred); + #endif // defined(ASIO_HAS_IOCP) -ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs, - size_t count, int flags, const socket_addr_type* addr, +ASIO_DECL signed_size_type sendto(socket_type s, + const buf* bufs, size_t count, int flags, const void* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL signed_size_type sendto1(socket_type s, + const void* data, size_t size, int flags, const void* addr, std::size_t addrlen, asio::error_code& ec); ASIO_DECL size_t sync_sendto(socket_type s, state_type state, - const buf* bufs, size_t count, int flags, const socket_addr_type* addr, + const buf* bufs, size_t count, int flags, const void* addr, + std::size_t addrlen, asio::error_code& ec); + +ASIO_DECL size_t sync_sendto1(socket_type s, state_type state, + const void* data, size_t size, int flags, const void* addr, std::size_t addrlen, asio::error_code& ec); #if !defined(ASIO_HAS_IOCP) -ASIO_DECL bool non_blocking_sendto(socket_type s, - const buf* bufs, size_t count, int flags, - const socket_addr_type* addr, std::size_t addrlen, +ASIO_DECL bool non_blocking_sendto(socket_type s, const buf* bufs, + size_t count, int flags, const void* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred); + +ASIO_DECL bool non_blocking_sendto1(socket_type s, const void* data, + size_t size, int flags, const void* addr, std::size_t addrlen, asio::error_code& ec, size_t& bytes_transferred); #endif // !defined(ASIO_HAS_IOCP) @@ -250,10 +290,10 @@ ASIO_DECL int getsockopt(socket_type s, state_type state, int level, int optname, void* optval, size_t* optlen, asio::error_code& ec); -ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, +ASIO_DECL int getpeername(socket_type s, void* addr, std::size_t* addrlen, bool cached, asio::error_code& ec); -ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, +ASIO_DECL int getsockname(socket_type s, void* addr, std::size_t* addrlen, asio::error_code& ec); ASIO_DECL int ioctl(socket_type s, state_type& state, @@ -298,19 +338,17 @@ ASIO_DECL asio::error_code background_getaddrinfo( ASIO_DECL void freeaddrinfo(addrinfo_type* ai); -ASIO_DECL asio::error_code getnameinfo( - const socket_addr_type* addr, std::size_t addrlen, - char* host, std::size_t hostlen, char* serv, +ASIO_DECL asio::error_code getnameinfo(const void* addr, + std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec); -ASIO_DECL asio::error_code sync_getnameinfo( - const socket_addr_type* addr, std::size_t addrlen, - char* host, std::size_t hostlen, char* serv, +ASIO_DECL asio::error_code sync_getnameinfo(const void* addr, + std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec); ASIO_DECL asio::error_code background_getnameinfo( const weak_cancel_token_type& cancel_token, - const socket_addr_type* addr, std::size_t addrlen, + const void* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec); diff --git a/3rdparty/asio/include/asio/detail/socket_option.hpp b/3rdparty/asio/include/asio/detail/socket_option.hpp index 02860b92373..760713daad8 100644 --- a/3rdparty/asio/include/asio/detail/socket_option.hpp +++ b/3rdparty/asio/include/asio/detail/socket_option.hpp @@ -2,7 +2,7 @@ // detail/socket_option.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/socket_select_interrupter.hpp b/3rdparty/asio/include/asio/detail/socket_select_interrupter.hpp index 7089640ed6d..e2432622e47 100644 --- a/3rdparty/asio/include/asio/detail/socket_select_interrupter.hpp +++ b/3rdparty/asio/include/asio/detail/socket_select_interrupter.hpp @@ -2,7 +2,7 @@ // detail/socket_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -45,7 +45,7 @@ public: // Interrupt the select call. ASIO_DECL void interrupt(); - // Reset the select interrupt. Returns true if the call was interrupted. + // Reset the select interrupter. Returns true if the reset was successful. ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. diff --git a/3rdparty/asio/include/asio/detail/socket_types.hpp b/3rdparty/asio/include/asio/detail/socket_types.hpp index 60c5929e828..cf4f746a44b 100644 --- a/3rdparty/asio/include/asio/detail/socket_types.hpp +++ b/3rdparty/asio/include/asio/detail/socket_types.hpp @@ -2,7 +2,7 @@ // detail/socket_types.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,13 +30,13 @@ # define ASIO_WSPIAPI_H_DEFINED # endif // !defined(_WSPIAPI_H_) # endif // defined(__BORLANDC__) +# include <winsock2.h> +# include <ws2tcpip.h> # if defined(WINAPI_FAMILY) # if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) # include <windows.h> # endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) # endif // defined(WINAPI_FAMILY) -# include <winsock2.h> -# include <ws2tcpip.h> # if !defined(ASIO_WINDOWS_APP) # include <mswsock.h> # endif // !defined(ASIO_WINDOWS_APP) @@ -89,6 +89,7 @@ # include <sys/filio.h> # include <sys/sockio.h> # endif +# include <signal.h> #endif #include "asio/detail/push_options.hpp" @@ -152,6 +153,7 @@ typedef int signed_size_type; # define ASIO_OS_DEF_SO_DONTROUTE 0x10 # define ASIO_OS_DEF_SO_KEEPALIVE 0x8 # define ASIO_OS_DEF_SO_LINGER 0x80 +# define ASIO_OS_DEF_SO_OOBINLINE 0x100 # define ASIO_OS_DEF_SO_SNDBUF 0x1001 # define ASIO_OS_DEF_SO_RCVBUF 0x1002 # define ASIO_OS_DEF_SO_SNDLOWAT 0x1003 @@ -177,6 +179,9 @@ typedef int signed_size_type; # define ASIO_OS_DEF_AI_V4MAPPED 0x800 # define ASIO_OS_DEF_AI_ALL 0x100 # define ASIO_OS_DEF_AI_ADDRCONFIG 0x400 +# define ASIO_OS_DEF_SA_RESTART 0x1 +# define ASIO_OS_DEF_SA_NOCLDSTOP 0x2 +# define ASIO_OS_DEF_SA_NOCLDWAIT 0x4 #elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) typedef SOCKET socket_type; const SOCKET invalid_socket = INVALID_SOCKET; @@ -205,6 +210,7 @@ typedef unsigned long ioctl_arg_type; typedef u_long u_long_type; typedef u_short u_short_type; typedef int signed_size_type; +struct sockaddr_un_type { u_short sun_family; char sun_path[108]; }; # define ASIO_OS_DEF(c) ASIO_OS_DEF_##c # define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC # define ASIO_OS_DEF_AF_INET AF_INET @@ -236,6 +242,7 @@ typedef int signed_size_type; # define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE # define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE # define ASIO_OS_DEF_SO_LINGER SO_LINGER +# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE # define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF # define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF # define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT @@ -282,6 +289,9 @@ const int max_iov_len = 64; # else const int max_iov_len = 16; # endif +# define ASIO_OS_DEF_SA_RESTART 0x1 +# define ASIO_OS_DEF_SA_NOCLDSTOP 0x2 +# define ASIO_OS_DEF_SA_NOCLDWAIT 0x4 #else typedef int socket_type; const int invalid_socket = -1; @@ -351,6 +361,7 @@ typedef int signed_size_type; # define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE # define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE # define ASIO_OS_DEF_SO_LINGER SO_LINGER +# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE # define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF # define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF # define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT @@ -400,6 +411,9 @@ const int max_iov_len = IOV_MAX; // POSIX platforms are not required to define IOV_MAX. const int max_iov_len = 16; # endif +# define ASIO_OS_DEF_SA_RESTART SA_RESTART +# define ASIO_OS_DEF_SA_NOCLDSTOP SA_NOCLDSTOP +# define ASIO_OS_DEF_SA_NOCLDWAIT SA_NOCLDWAIT #endif const int custom_socket_option_level = 0xA5100000; const int enable_connection_aborted_option = 1; diff --git a/3rdparty/asio/include/asio/detail/source_location.hpp b/3rdparty/asio/include/asio/detail/source_location.hpp new file mode 100644 index 00000000000..14b74f91435 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/source_location.hpp @@ -0,0 +1,45 @@ +// +// detail/source_location.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_SOURCE_LOCATION_HPP +#define ASIO_DETAIL_SOURCE_LOCATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SOURCE_LOCATION) + +#if defined(ASIO_HAS_STD_SOURCE_LOCATION) +# include <source_location> +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# include <experimental/source_location> +#else // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# error ASIO_HAS_SOURCE_LOCATION is set \ + but no source_location is available +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_SOURCE_LOCATION) +using std::source_location; +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +using std::experimental::source_location; +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +} // namespace detail +} // namespace asio + +#endif // defined(ASIO_HAS_SOURCE_LOCATION) + +#endif // ASIO_DETAIL_SOURCE_LOCATION_HPP diff --git a/3rdparty/asio/include/asio/detail/static_mutex.hpp b/3rdparty/asio/include/asio/detail/static_mutex.hpp index 1be0a85af90..b47d087bf4a 100644 --- a/3rdparty/asio/include/asio/detail/static_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/static_mutex.hpp @@ -2,7 +2,7 @@ // detail/static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,10 +23,8 @@ # include "asio/detail/win_static_mutex.hpp" #elif defined(ASIO_HAS_PTHREADS) # include "asio/detail/posix_static_mutex.hpp" -#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) -# include "asio/detail/std_static_mutex.hpp" #else -# error Only Windows and POSIX are supported! +# include "asio/detail/std_static_mutex.hpp" #endif namespace asio { @@ -41,7 +39,7 @@ typedef win_static_mutex static_mutex; #elif defined(ASIO_HAS_PTHREADS) typedef posix_static_mutex static_mutex; # define ASIO_STATIC_MUTEX_INIT ASIO_POSIX_STATIC_MUTEX_INIT -#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) +#else typedef std_static_mutex static_mutex; # define ASIO_STATIC_MUTEX_INIT ASIO_STD_STATIC_MUTEX_INIT #endif diff --git a/3rdparty/asio/include/asio/detail/std_event.hpp b/3rdparty/asio/include/asio/detail/std_event.hpp index e05fcca3316..97a347ed725 100644 --- a/3rdparty/asio/include/asio/detail/std_event.hpp +++ b/3rdparty/asio/include/asio/detail/std_event.hpp @@ -2,7 +2,7 @@ // detail/std_event.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) - #include <chrono> #include <condition_variable> #include "asio/detail/assert.hpp" @@ -73,6 +70,18 @@ public: cond_.notify_one(); } + // Unlock the mutex and signal one waiter who may destroy us. + template <typename Lock> + void unlock_and_signal_one_for_destruction(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + cond_.notify_one(); + lock.unlock(); + } + // If there's a waiter, unlock the mutex and signal it. template <typename Lock> bool maybe_unlock_and_signal_one(Lock& lock) @@ -171,6 +180,4 @@ private: #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) - #endif // ASIO_DETAIL_STD_EVENT_HPP diff --git a/3rdparty/asio/include/asio/detail/solaris_fenced_block.hpp b/3rdparty/asio/include/asio/detail/std_fenced_block.hpp index c1b599ecd8e..d1e0c603cbc 100644 --- a/3rdparty/asio/include/asio/detail/solaris_fenced_block.hpp +++ b/3rdparty/asio/include/asio/detail/std_fenced_block.hpp @@ -1,25 +1,22 @@ // -// detail/solaris_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/std_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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_DETAIL_SOLARIS_FENCED_BLOCK_HPP -#define ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP +#ifndef ASIO_DETAIL_STD_FENCED_BLOCK_HPP +#define ASIO_DETAIL_STD_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(__sun) - -#include <atomic.h> +#include <atomic> #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" @@ -27,7 +24,7 @@ namespace asio { namespace detail { -class solaris_fenced_block +class std_fenced_block : private noncopyable { public: @@ -35,20 +32,20 @@ public: enum full_t { full }; // Constructor for a half fenced block. - explicit solaris_fenced_block(half_t) + explicit std_fenced_block(half_t) { } // Constructor for a full fenced block. - explicit solaris_fenced_block(full_t) + explicit std_fenced_block(full_t) { - membar_consumer(); + std::atomic_thread_fence(std::memory_order_acquire); } // Destructor. - ~solaris_fenced_block() + ~std_fenced_block() { - membar_producer(); + std::atomic_thread_fence(std::memory_order_release); } }; @@ -57,6 +54,4 @@ public: #include "asio/detail/pop_options.hpp" -#endif // defined(__sun) - -#endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP +#endif // ASIO_DETAIL_STD_FENCED_BLOCK_HPP diff --git a/3rdparty/asio/include/asio/detail/std_global.hpp b/3rdparty/asio/include/asio/detail/std_global.hpp index 416f0d3b548..49ae055ea7d 100644 --- a/3rdparty/asio/include/asio/detail/std_global.hpp +++ b/3rdparty/asio/include/asio/detail/std_global.hpp @@ -2,7 +2,7 @@ // detail/std_global.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_CALL_ONCE) - #include <exception> #include <mutex> @@ -65,6 +62,4 @@ T& std_global() #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_STD_CALL_ONCE) - #endif // ASIO_DETAIL_STD_GLOBAL_HPP diff --git a/3rdparty/asio/include/asio/detail/std_mutex.hpp b/3rdparty/asio/include/asio/detail/std_mutex.hpp index 31af56a36d7..06839d69ca3 100644 --- a/3rdparty/asio/include/asio/detail/std_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/std_mutex.hpp @@ -2,7 +2,7 @@ // detail/std_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) - #include <mutex> #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" @@ -68,6 +65,4 @@ private: #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) - #endif // ASIO_DETAIL_STD_MUTEX_HPP diff --git a/3rdparty/asio/include/asio/detail/std_static_mutex.hpp b/3rdparty/asio/include/asio/detail/std_static_mutex.hpp index 166ede9aee9..302b729037d 100644 --- a/3rdparty/asio/include/asio/detail/std_static_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/std_static_mutex.hpp @@ -2,7 +2,7 @@ // detail/std_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) - #include <mutex> #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" @@ -76,6 +73,4 @@ private: #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) - #endif // ASIO_DETAIL_STD_STATIC_MUTEX_HPP diff --git a/3rdparty/asio/include/asio/detail/std_thread.hpp b/3rdparty/asio/include/asio/detail/std_thread.hpp index f6fcec1621f..78bbab9ea10 100644 --- a/3rdparty/asio/include/asio/detail/std_thread.hpp +++ b/3rdparty/asio/include/asio/detail/std_thread.hpp @@ -2,7 +2,7 @@ // detail/std_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_THREAD) - #include <thread> #include "asio/detail/noncopyable.hpp" @@ -66,6 +63,4 @@ private: #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_STD_THREAD) - #endif // ASIO_DETAIL_STD_THREAD_HPP diff --git a/3rdparty/asio/include/asio/detail/strand_executor_service.hpp b/3rdparty/asio/include/asio/detail/strand_executor_service.hpp index 5ca77a33196..45536ed5368 100644 --- a/3rdparty/asio/include/asio/detail/strand_executor_service.hpp +++ b/3rdparty/asio/include/asio/detail/strand_executor_service.hpp @@ -2,7 +2,7 @@ // detail/strand_executor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,6 +23,8 @@ #include "asio/detail/op_queue.hpp" #include "asio/detail/scheduler_operation.hpp" #include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution.hpp" #include "asio/execution_context.hpp" #include "asio/detail/push_options.hpp" @@ -52,6 +54,10 @@ public: // itself has been scheduled in order to invoke some pending handlers. bool locked_; + // Indicates that the strand has been shut down and will accept no further + // handlers. + bool shutdown_; + // The handlers that are waiting on the strand but should not be run until // after the next time the strand is scheduled. This queue must only be // modified while the mutex is locked. @@ -82,19 +88,35 @@ public: ASIO_DECL implementation_type create_implementation(); // Request invocation of the given function. + template <typename Executor, typename Function> + static void execute(const implementation_type& impl, Executor& ex, + Function&& function, + enable_if_t< + can_query<Executor, execution::allocator_t<void>>::value + >* = 0); + + // Request invocation of the given function. + template <typename Executor, typename Function> + static void execute(const implementation_type& impl, Executor& ex, + Function&& function, + enable_if_t< + !can_query<Executor, execution::allocator_t<void>>::value + >* = 0); + + // Request invocation of the given function. template <typename Executor, typename Function, typename Allocator> static void dispatch(const implementation_type& impl, Executor& ex, - ASIO_MOVE_ARG(Function) function, const Allocator& a); + Function&& function, const Allocator& a); // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> static void post(const implementation_type& impl, Executor& ex, - ASIO_MOVE_ARG(Function) function, const Allocator& a); + Function&& function, const Allocator& a); // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> static void defer(const implementation_type& impl, Executor& ex, - ASIO_MOVE_ARG(Function) function, const Allocator& a); + Function&& function, const Allocator& a); // Determine whether the strand is running in the current thread. ASIO_DECL static bool running_in_this_thread( @@ -102,12 +124,25 @@ public: private: friend class strand_impl; - template <typename Executor> class invoker; + template <typename F, typename Allocator> class allocator_binder; + template <typename Executor, typename = void> class invoker; // Adds a function to the strand. Returns true if it acquires the lock. ASIO_DECL static bool enqueue(const implementation_type& impl, scheduler_operation* op); + // Transfers waiting handlers to the ready queue. Returns true if one or more + // handlers were transferred. + ASIO_DECL static bool push_waiting_to_ready(implementation_type& impl); + + // Invokes all ready-to-run handlers. + ASIO_DECL static void run_ready_handlers(implementation_type& impl); + + // Helper function to request invocation of the given function. + template <typename Executor, typename Function, typename Allocator> + static void do_execute(const implementation_type& impl, Executor& ex, + Function&& function, const Allocator& a); + // Mutex to protect access to the service-wide state. mutex mutex_; diff --git a/3rdparty/asio/include/asio/detail/strand_service.hpp b/3rdparty/asio/include/asio/detail/strand_service.hpp index c5d95e7696f..084eb0b3066 100644 --- a/3rdparty/asio/include/asio/detail/strand_service.hpp +++ b/3rdparty/asio/include/asio/detail/strand_service.hpp @@ -2,7 +2,7 @@ // detail/strand_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -96,11 +96,10 @@ public: const implementation_type& impl) const; private: - // Helper function to dispatch a handler. Returns true if the handler should - // be dispatched immediately. - ASIO_DECL bool do_dispatch(implementation_type& impl, operation* op); + // Helper function to dispatch a handler. + ASIO_DECL void do_dispatch(implementation_type& impl, operation* op); - // Helper fiunction to post a handler. + // Helper function to post a handler. ASIO_DECL void do_post(implementation_type& impl, operation* op, bool is_continuation); @@ -108,8 +107,11 @@ private: operation* base, const asio::error_code& ec, std::size_t bytes_transferred); + // The io_context used to obtain an I/O executor. + io_context& io_context_; + // The io_context implementation used to post completions. - io_context_impl& io_context_; + io_context_impl& io_context_impl_; // Mutex to protect access to the array of implementations. asio::detail::mutex mutex_; diff --git a/3rdparty/asio/include/asio/detail/string_view.hpp b/3rdparty/asio/include/asio/detail/string_view.hpp index 6f4072d04fa..a4470f1e580 100644 --- a/3rdparty/asio/include/asio/detail/string_view.hpp +++ b/3rdparty/asio/include/asio/detail/string_view.hpp @@ -2,7 +2,7 @@ // detail/string_view.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,31 +15,33 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#if defined(ASIO_HAS_STD_STRING_VIEW) - #include "asio/detail/config.hpp" -#if defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) -# include <experimental/string_view> -#else // defined(ASIO_HAS_EXPERIMENTAL_STRING_VIEW) +#if defined(ASIO_HAS_STRING_VIEW) + +#if defined(ASIO_HAS_STD_STRING_VIEW) # include <string_view> -#endif // defined(ASIO_HAS_EXPERIMENTAL_STRING_VIEW) +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# include <experimental/string_view> +#else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# error ASIO_HAS_STRING_VIEW is set but no string_view is available +#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) namespace asio { -#if defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) -using std::experimental::basic_string_view; -using std::experimental::string_view; -#else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +#if defined(ASIO_HAS_STD_STRING_VIEW) using std::basic_string_view; using std::string_view; +#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +using std::experimental::basic_string_view; +using std::experimental::string_view; #endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) } // namespace asio # define ASIO_STRING_VIEW_PARAM asio::string_view -#else // defined(ASIO_HAS_STD_STRING_VIEW) +#else // defined(ASIO_HAS_STRING_VIEW) # define ASIO_STRING_VIEW_PARAM const std::string& -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) #endif // ASIO_DETAIL_STRING_VIEW_HPP diff --git a/3rdparty/asio/include/asio/detail/thread.hpp b/3rdparty/asio/include/asio/detail/thread.hpp index cfb5bad1455..faa7fad2438 100644 --- a/3rdparty/asio/include/asio/detail/thread.hpp +++ b/3rdparty/asio/include/asio/detail/thread.hpp @@ -2,7 +2,7 @@ // detail/thread.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,8 @@ #if !defined(ASIO_HAS_THREADS) # include "asio/detail/null_thread.hpp" +#elif defined(ASIO_HAS_PTHREADS) +# include "asio/detail/posix_thread.hpp" #elif defined(ASIO_WINDOWS) # if defined(UNDER_CE) # include "asio/detail/wince_thread.hpp" @@ -27,12 +29,8 @@ # else # include "asio/detail/win_thread.hpp" # endif -#elif defined(ASIO_HAS_PTHREADS) -# include "asio/detail/posix_thread.hpp" -#elif defined(ASIO_HAS_STD_THREAD) -# include "asio/detail/std_thread.hpp" #else -# error Only Windows, POSIX and std::thread are supported! +# include "asio/detail/std_thread.hpp" #endif namespace asio { @@ -40,6 +38,8 @@ namespace detail { #if !defined(ASIO_HAS_THREADS) typedef null_thread thread; +#elif defined(ASIO_HAS_PTHREADS) +typedef posix_thread thread; #elif defined(ASIO_WINDOWS) # if defined(UNDER_CE) typedef wince_thread thread; @@ -48,9 +48,7 @@ typedef winapp_thread thread; # else typedef win_thread thread; # endif -#elif defined(ASIO_HAS_PTHREADS) -typedef posix_thread thread; -#elif defined(ASIO_HAS_STD_THREAD) +#else typedef std_thread thread; #endif diff --git a/3rdparty/asio/include/asio/detail/thread_context.hpp b/3rdparty/asio/include/asio/detail/thread_context.hpp index 66d20d6f541..bebfc4a43a2 100644 --- a/3rdparty/asio/include/asio/detail/thread_context.hpp +++ b/3rdparty/asio/include/asio/detail/thread_context.hpp @@ -2,7 +2,7 @@ // detail/thread_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,6 +30,11 @@ class thread_info_base; class thread_context { public: + // Obtain a pointer to the top of the thread call stack. Returns null when + // not running inside a thread context. + ASIO_DECL static thread_info_base* top_of_thread_call_stack(); + +protected: // Per-thread call stack to track the state of each thread in the context. typedef call_stack<thread_context, thread_info_base> thread_call_stack; }; @@ -39,4 +44,8 @@ public: #include "asio/detail/pop_options.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/thread_context.ipp" +#endif // defined(ASIO_HEADER_ONLY) + #endif // ASIO_DETAIL_THREAD_CONTEXT_HPP diff --git a/3rdparty/asio/include/asio/detail/thread_group.hpp b/3rdparty/asio/include/asio/detail/thread_group.hpp index 312af44c729..5ebff5e185f 100644 --- a/3rdparty/asio/include/asio/detail/thread_group.hpp +++ b/3rdparty/asio/include/asio/detail/thread_group.hpp @@ -2,7 +2,7 @@ // detail/thread_group.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,8 @@ #include "asio/detail/scoped_ptr.hpp" #include "asio/detail/thread.hpp" +#include "asio/detail/push_options.hpp" + namespace asio { namespace detail { @@ -64,6 +66,12 @@ public: } } + // Test whether the group is empty. + bool empty() const + { + return first_ == 0; + } + private: // Structure used to track a single thread in the group. struct item @@ -86,4 +94,6 @@ private: } // namespace detail } // namespace asio +#include "asio/detail/pop_options.hpp" + #endif // ASIO_DETAIL_THREAD_GROUP_HPP diff --git a/3rdparty/asio/include/asio/detail/thread_info_base.hpp b/3rdparty/asio/include/asio/detail/thread_info_base.hpp index 5fc26c30970..5a74cef776a 100644 --- a/3rdparty/asio/include/asio/detail/thread_info_base.hpp +++ b/3rdparty/asio/include/asio/detail/thread_info_base.hpp @@ -2,7 +2,7 @@ // detail/thread_info_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,72 +15,231 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include "asio/detail/config.hpp" #include <climits> #include <cstddef> +#include "asio/detail/memory.hpp" #include "asio/detail/noncopyable.hpp" +#if !defined(ASIO_NO_EXCEPTIONS) +# include <exception> +# include "asio/multiple_exceptions.hpp" +#endif // !defined(ASIO_NO_EXCEPTIONS) + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +#ifndef ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE +# define ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE 2 +#endif // ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE + class thread_info_base : private noncopyable { public: + struct default_tag + { + enum + { + cache_size = ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE, + begin_mem_index = 0, + end_mem_index = cache_size + }; + }; + + struct awaitable_frame_tag + { + enum + { + cache_size = ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE, + begin_mem_index = default_tag::end_mem_index, + end_mem_index = begin_mem_index + cache_size + }; + }; + + struct executor_function_tag + { + enum + { + cache_size = ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE, + begin_mem_index = awaitable_frame_tag::end_mem_index, + end_mem_index = begin_mem_index + cache_size + }; + }; + + struct cancellation_signal_tag + { + enum + { + cache_size = ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE, + begin_mem_index = executor_function_tag::end_mem_index, + end_mem_index = begin_mem_index + cache_size + }; + }; + + struct parallel_group_tag + { + enum + { + cache_size = ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE, + begin_mem_index = cancellation_signal_tag::end_mem_index, + end_mem_index = begin_mem_index + cache_size + }; + }; + + enum { max_mem_index = parallel_group_tag::end_mem_index }; + thread_info_base() - : reusable_memory_(0) +#if !defined(ASIO_NO_EXCEPTIONS) + : has_pending_exception_(0) +#endif // !defined(ASIO_NO_EXCEPTIONS) { + for (int i = 0; i < max_mem_index; ++i) + reusable_memory_[i] = 0; } ~thread_info_base() { - if (reusable_memory_) - ::operator delete(reusable_memory_); + for (int i = 0; i < max_mem_index; ++i) + { + // The following test for non-null pointers is technically redundant, but + // it is significantly faster when using a tight io_context::poll() loop + // in latency sensitive applications. + if (reusable_memory_[i]) + aligned_delete(reusable_memory_[i]); + } } - static void* allocate(thread_info_base* this_thread, std::size_t size) + static void* allocate(thread_info_base* this_thread, + std::size_t size, std::size_t align = ASIO_DEFAULT_ALIGN) { - if (this_thread && this_thread->reusable_memory_) - { - void* const pointer = this_thread->reusable_memory_; - this_thread->reusable_memory_ = 0; + return allocate(default_tag(), this_thread, size, align); + } - unsigned char* const mem = static_cast<unsigned char*>(pointer); - if (static_cast<std::size_t>(mem[0]) >= size) + static void deallocate(thread_info_base* this_thread, + void* pointer, std::size_t size) + { + deallocate(default_tag(), this_thread, pointer, size); + } + + template <typename Purpose> + static void* allocate(Purpose, thread_info_base* this_thread, + std::size_t size, std::size_t align = ASIO_DEFAULT_ALIGN) + { + std::size_t chunks = (size + chunk_size - 1) / chunk_size; + + if (this_thread) + { + for (int mem_index = Purpose::begin_mem_index; + mem_index < Purpose::end_mem_index; ++mem_index) { - mem[size] = mem[0]; - return pointer; + if (this_thread->reusable_memory_[mem_index]) + { + void* const pointer = this_thread->reusable_memory_[mem_index]; + unsigned char* const mem = static_cast<unsigned char*>(pointer); + if (static_cast<std::size_t>(mem[0]) >= chunks + && reinterpret_cast<std::size_t>(pointer) % align == 0) + { + this_thread->reusable_memory_[mem_index] = 0; + mem[size] = mem[0]; + return pointer; + } + } } - ::operator delete(pointer); + for (int mem_index = Purpose::begin_mem_index; + mem_index < Purpose::end_mem_index; ++mem_index) + { + if (this_thread->reusable_memory_[mem_index]) + { + void* const pointer = this_thread->reusable_memory_[mem_index]; + this_thread->reusable_memory_[mem_index] = 0; + aligned_delete(pointer); + break; + } + } } - void* const pointer = ::operator new(size + 1); + void* const pointer = aligned_new(align, chunks * chunk_size + 1); unsigned char* const mem = static_cast<unsigned char*>(pointer); - mem[size] = (size <= UCHAR_MAX) ? static_cast<unsigned char>(size) : 0; + mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0; return pointer; } - static void deallocate(thread_info_base* this_thread, + template <typename Purpose> + static void deallocate(Purpose, thread_info_base* this_thread, void* pointer, std::size_t size) { - if (size <= UCHAR_MAX) + if (size <= chunk_size * UCHAR_MAX) { - if (this_thread && this_thread->reusable_memory_ == 0) + if (this_thread) { - unsigned char* const mem = static_cast<unsigned char*>(pointer); - mem[0] = mem[size]; - this_thread->reusable_memory_ = pointer; - return; + for (int mem_index = Purpose::begin_mem_index; + mem_index < Purpose::end_mem_index; ++mem_index) + { + if (this_thread->reusable_memory_[mem_index] == 0) + { + unsigned char* const mem = static_cast<unsigned char*>(pointer); + mem[0] = mem[size]; + this_thread->reusable_memory_[mem_index] = pointer; + return; + } + } } } - ::operator delete(pointer); + aligned_delete(pointer); + } + + void capture_current_exception() + { +#if !defined(ASIO_NO_EXCEPTIONS) + switch (has_pending_exception_) + { + case 0: + has_pending_exception_ = 1; + pending_exception_ = std::current_exception(); + break; + case 1: + has_pending_exception_ = 2; + pending_exception_ = + std::make_exception_ptr<multiple_exceptions>( + multiple_exceptions(pending_exception_)); + break; + default: + break; + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } + + void rethrow_pending_exception() + { +#if !defined(ASIO_NO_EXCEPTIONS) + if (has_pending_exception_ > 0) + { + has_pending_exception_ = 0; + std::exception_ptr ex( + static_cast<std::exception_ptr&&>( + pending_exception_)); + std::rethrow_exception(ex); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) } private: - void* reusable_memory_; +#if defined(ASIO_HAS_IO_URING) + enum { chunk_size = 8 }; +#else // defined(ASIO_HAS_IO_URING) + enum { chunk_size = 4 }; +#endif // defined(ASIO_HAS_IO_URING) + void* reusable_memory_[max_mem_index]; + +#if !defined(ASIO_NO_EXCEPTIONS) + int has_pending_exception_; + std::exception_ptr pending_exception_; +#endif // !defined(ASIO_NO_EXCEPTIONS) }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/throw_error.hpp b/3rdparty/asio/include/asio/detail/throw_error.hpp index 3c1d59cd36d..881c3128576 100644 --- a/3rdparty/asio/include/asio/detail/throw_error.hpp +++ b/3rdparty/asio/include/asio/detail/throw_error.hpp @@ -2,7 +2,7 @@ // detail/throw_error.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,6 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/throw_exception.hpp" #include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" @@ -23,22 +24,30 @@ namespace asio { namespace detail { -ASIO_DECL void do_throw_error(const asio::error_code& err); +ASIO_DECL void do_throw_error( + const asio::error_code& err + ASIO_SOURCE_LOCATION_PARAM); -ASIO_DECL void do_throw_error(const asio::error_code& err, - const char* location); +ASIO_DECL void do_throw_error( + const asio::error_code& err, + const char* location + ASIO_SOURCE_LOCATION_PARAM); -inline void throw_error(const asio::error_code& err) +inline void throw_error( + const asio::error_code& err + ASIO_SOURCE_LOCATION_DEFAULTED_PARAM) { if (err) - do_throw_error(err); + do_throw_error(err ASIO_SOURCE_LOCATION_ARG); } -inline void throw_error(const asio::error_code& err, - const char* location) +inline void throw_error( + const asio::error_code& err, + const char* location + ASIO_SOURCE_LOCATION_DEFAULTED_PARAM) { if (err) - do_throw_error(err, location); + do_throw_error(err, location ASIO_SOURCE_LOCATION_ARG); } } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/throw_exception.hpp b/3rdparty/asio/include/asio/detail/throw_exception.hpp index a0c3cf85eaa..e939c1093f6 100644 --- a/3rdparty/asio/include/asio/detail/throw_exception.hpp +++ b/3rdparty/asio/include/asio/detail/throw_exception.hpp @@ -2,7 +2,7 @@ // detail/throw_exception.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,14 +30,18 @@ using boost::throw_exception; // Declare the throw_exception function for all targets. template <typename Exception> -void throw_exception(const Exception& e); +void throw_exception( + const Exception& e + ASIO_SOURCE_LOCATION_DEFAULTED_PARAM); // Only define the throw_exception function when exceptions are enabled. // Otherwise, it is up to the application to provide a definition of this // function. # if !defined(ASIO_NO_EXCEPTIONS) template <typename Exception> -void throw_exception(const Exception& e) +void throw_exception( + const Exception& e + ASIO_SOURCE_LOCATION_PARAM) { throw e; } diff --git a/3rdparty/asio/include/asio/detail/timer_queue.hpp b/3rdparty/asio/include/asio/detail/timer_queue.hpp index 1575e03af7b..843f3614da0 100644 --- a/3rdparty/asio/include/asio/detail/timer_queue.hpp +++ b/3rdparty/asio/include/asio/detail/timer_queue.hpp @@ -2,7 +2,7 @@ // detail/timer_queue.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -150,7 +150,12 @@ public: while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_)) { per_timer_data* timer = heap_[0].timer_; - ops.push(timer->op_queue_); + while (wait_op* op = timer->op_queue_.front()) + { + timer->op_queue_.pop(); + op->ec_ = asio::error_code(); + ops.push(op); + } remove_timer(*timer); } } @@ -192,6 +197,30 @@ public: return num_cancelled; } + // Cancel and dequeue a specific operation for the given timer. + void cancel_timer_by_key(per_timer_data* timer, + op_queue<operation>& ops, void* cancellation_key) + { + if (timer->prev_ != 0 || timer == timers_) + { + op_queue<wait_op> other_ops; + while (wait_op* op = timer->op_queue_.front()) + { + timer->op_queue_.pop(); + if (op->cancellation_key_ == cancellation_key) + { + op->ec_ = asio::error::operation_aborted; + ops.push(op); + } + else + other_ops.push(op); + } + timer->op_queue_.push(other_ops); + if (timer->op_queue_.empty()) + remove_timer(*timer); + } + } + // Move operations from one timer to another, empty timer. void move_timer(per_timer_data& target, per_timer_data& source) { @@ -266,11 +295,13 @@ private: { if (index == heap_.size() - 1) { + timer.heap_index_ = (std::numeric_limits<std::size_t>::max)(); heap_.pop_back(); } else { swap_heap(index, heap_.size() - 1); + timer.heap_index_ = (std::numeric_limits<std::size_t>::max)(); heap_.pop_back(); if (index > 0 && Time_Traits::less_than( heap_[index].time_, heap_[(index - 1) / 2].time_)) diff --git a/3rdparty/asio/include/asio/detail/timer_queue_base.hpp b/3rdparty/asio/include/asio/detail/timer_queue_base.hpp index 326d05556d9..ddcf41c1371 100644 --- a/3rdparty/asio/include/asio/detail/timer_queue_base.hpp +++ b/3rdparty/asio/include/asio/detail/timer_queue_base.hpp @@ -2,7 +2,7 @@ // detail/timer_queue_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/timer_queue_ptime.hpp b/3rdparty/asio/include/asio/detail/timer_queue_ptime.hpp index 9d3cb7d0c93..937a4ad85fa 100644 --- a/3rdparty/asio/include/asio/detail/timer_queue_ptime.hpp +++ b/3rdparty/asio/include/asio/detail/timer_queue_ptime.hpp @@ -2,7 +2,7 @@ // detail/timer_queue_ptime.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -31,7 +31,7 @@ struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {}; // Template specialisation for the commonly used instantation. template <> -class timer_queue<time_traits<boost::posix_time::ptime> > +class timer_queue<time_traits<boost::posix_time::ptime>> : public timer_queue_base { public: @@ -77,6 +77,10 @@ public: per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Cancel and dequeue operations for the given timer and key. + ASIO_DECL void cancel_timer_by_key(per_timer_data* timer, + op_queue<operation>& ops, void* cancellation_key); + // Move operations from one timer to another, empty timer. ASIO_DECL void move_timer(per_timer_data& target, per_timer_data& source); diff --git a/3rdparty/asio/include/asio/detail/timer_queue_set.hpp b/3rdparty/asio/include/asio/detail/timer_queue_set.hpp index 38f46d1e0da..7bf50747be1 100644 --- a/3rdparty/asio/include/asio/detail/timer_queue_set.hpp +++ b/3rdparty/asio/include/asio/detail/timer_queue_set.hpp @@ -2,7 +2,7 @@ // detail/timer_queue_set.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/timer_scheduler.hpp b/3rdparty/asio/include/asio/detail/timer_scheduler.hpp index 190731675e7..dd34d328c84 100644 --- a/3rdparty/asio/include/asio/detail/timer_scheduler.hpp +++ b/3rdparty/asio/include/asio/detail/timer_scheduler.hpp @@ -2,7 +2,7 @@ // detail/timer_scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,6 +22,8 @@ # include "asio/detail/winrt_timer_scheduler.hpp" #elif defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_io_context.hpp" +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_service.hpp" #elif defined(ASIO_HAS_EPOLL) # include "asio/detail/epoll_reactor.hpp" #elif defined(ASIO_HAS_KQUEUE) diff --git a/3rdparty/asio/include/asio/detail/timer_scheduler_fwd.hpp b/3rdparty/asio/include/asio/detail/timer_scheduler_fwd.hpp index cf27b8c0c93..bbb8a4e8ded 100644 --- a/3rdparty/asio/include/asio/detail/timer_scheduler_fwd.hpp +++ b/3rdparty/asio/include/asio/detail/timer_scheduler_fwd.hpp @@ -2,7 +2,7 @@ // detail/timer_scheduler_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -24,6 +24,8 @@ namespace detail { typedef class winrt_timer_scheduler timer_scheduler; #elif defined(ASIO_HAS_IOCP) typedef class win_iocp_io_context timer_scheduler; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +typedef class io_uring_service timer_scheduler; #elif defined(ASIO_HAS_EPOLL) typedef class epoll_reactor timer_scheduler; #elif defined(ASIO_HAS_KQUEUE) diff --git a/3rdparty/asio/include/asio/detail/tss_ptr.hpp b/3rdparty/asio/include/asio/detail/tss_ptr.hpp index 2d0306153d6..f7aaa2ec29c 100644 --- a/3rdparty/asio/include/asio/detail/tss_ptr.hpp +++ b/3rdparty/asio/include/asio/detail/tss_ptr.hpp @@ -2,7 +2,7 @@ // detail/tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/type_traits.hpp b/3rdparty/asio/include/asio/detail/type_traits.hpp index 08665891520..a4706a5ff1c 100644 --- a/3rdparty/asio/include/asio/detail/type_traits.hpp +++ b/3rdparty/asio/include/asio/detail/type_traits.hpp @@ -2,7 +2,7 @@ // detail/type_traits.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,64 +16,162 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_TYPE_TRAITS) -# include <type_traits> -#else // defined(ASIO_HAS_TYPE_TRAITS) -# include <boost/type_traits/add_const.hpp> -# include <boost/type_traits/conditional.hpp> -# include <boost/type_traits/decay.hpp> -# include <boost/type_traits/integral_constant.hpp> -# include <boost/type_traits/is_base_of.hpp> -# include <boost/type_traits/is_class.hpp> -# include <boost/type_traits/is_const.hpp> -# include <boost/type_traits/is_convertible.hpp> -# include <boost/type_traits/is_function.hpp> -# include <boost/type_traits/is_same.hpp> -# include <boost/type_traits/remove_pointer.hpp> -# include <boost/type_traits/remove_reference.hpp> -# include <boost/utility/enable_if.hpp> -# include <boost/utility/result_of.hpp> -#endif // defined(ASIO_HAS_TYPE_TRAITS) +#include <type_traits> namespace asio { -#if defined(ASIO_HAS_STD_TYPE_TRAITS) using std::add_const; + +template <typename T> +using add_const_t = typename std::add_const<T>::type; + +using std::add_lvalue_reference; + +template <typename T> +using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type; + +template <std::size_t N, std::size_t A> +struct aligned_storage +{ + struct type + { + alignas(A) unsigned char data[N]; + }; +}; + +template <std::size_t N, std::size_t A> +using aligned_storage_t = typename aligned_storage<N, A>::type; + +using std::alignment_of; + using std::conditional; + +template <bool C, typename T, typename U> +using conditional_t = typename std::conditional<C, T, U>::type; + using std::decay; + +template <typename T> +using decay_t = typename std::decay<T>::type; + +using std::declval; + using std::enable_if; + +template <bool C, typename T = void> +using enable_if_t = typename std::enable_if<C, T>::type; + using std::false_type; + using std::integral_constant; + using std::is_base_of; + using std::is_class; + using std::is_const; + +using std::is_constructible; + using std::is_convertible; + +using std::is_copy_constructible; + +using std::is_destructible; + using std::is_function; + +using std::is_move_constructible; + +using std::is_nothrow_copy_constructible; + +using std::is_nothrow_destructible; + +using std::is_object; + +using std::is_pointer; + +using std::is_reference; + using std::is_same; + +using std::is_scalar; + +using std::remove_cv; + +template <typename T> +using remove_cv_t = typename std::remove_cv<T>::type; + +template <typename T> +struct remove_cvref : + std::remove_cv<typename std::remove_reference<T>::type> {}; + +template <typename T> +using remove_cvref_t = typename remove_cvref<T>::type; + using std::remove_pointer; + +template <typename T> +using remove_pointer_t = typename std::remove_pointer<T>::type; + using std::remove_reference; + +template <typename T> +using remove_reference_t = typename std::remove_reference<T>::type; + +#if defined(ASIO_HAS_STD_INVOKE_RESULT) + +template <typename> struct result_of; + +template <typename F, typename... Args> +struct result_of<F(Args...)> : std::invoke_result<F, Args...> {}; + +template <typename T> +using result_of_t = typename result_of<T>::type; + +#else // defined(ASIO_HAS_STD_INVOKE_RESULT) + using std::result_of; + +template <typename T> +using result_of_t = typename std::result_of<T>::type; + +#endif // defined(ASIO_HAS_STD_INVOKE_RESULT) + using std::true_type; -#else // defined(ASIO_HAS_STD_TYPE_TRAITS) -using boost::add_const; -template <bool Condition, typename Type = void> -struct enable_if : boost::enable_if_c<Condition, Type> {}; -using boost::conditional; -using boost::decay; -using boost::false_type; -using boost::integral_constant; -using boost::is_base_of; -using boost::is_class; -using boost::is_const; -using boost::is_convertible; -using boost::is_function; -using boost::is_same; -using boost::remove_pointer; -using boost::remove_reference; -using boost::result_of; -using boost::true_type; -#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) + +template <typename> struct void_type +{ + typedef void type; +}; + +template <typename T> +using void_t = typename void_type<T>::type; + +template <typename...> struct conjunction : true_type {}; + +template <typename T> struct conjunction<T> : T {}; + +template <typename Head, typename... Tail> +struct conjunction<Head, Tail...> : + conditional_t<Head::value, conjunction<Tail...>, Head> {}; + +struct defaulted_constraint +{ + constexpr defaulted_constraint() {} +}; + +template <bool Condition, typename Type = int> +struct constraint : std::enable_if<Condition, Type> {}; + +template <bool Condition, typename Type = int> +using constraint_t = typename constraint<Condition, Type>::type; + +template <typename T> +struct type_identity { typedef T type; }; + +template <typename T> +using type_identity_t = typename type_identity<T>::type; } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/utility.hpp b/3rdparty/asio/include/asio/detail/utility.hpp new file mode 100644 index 00000000000..72dd4d43190 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/utility.hpp @@ -0,0 +1,83 @@ +// +// detail/utility.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_UTILITY_HPP +#define ASIO_DETAIL_UTILITY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <utility> + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_STD_INDEX_SEQUENCE) + +using std::index_sequence; +using std::index_sequence_for; +using std::make_index_sequence; + +#else // defined(ASIO_HAS_STD_INDEX_SEQUENCE) + +template <std::size_t...> +struct index_sequence +{ +}; + +template <typename T, typename U> +struct join_index_sequences; + +template <std::size_t... I, std::size_t... J> +struct join_index_sequences<index_sequence<I...>, index_sequence<J...>> +{ + using type = index_sequence<I..., J...>; +}; + +template <std::size_t First, std::size_t Last> +struct index_pack : + join_index_sequences< + typename index_pack<First, First + (Last - First + 1) / 2 - 1>::type, + typename index_pack<First + (Last - First + 1) / 2, Last>::type + > +{ +}; + +template <std::size_t N> +struct index_pack<N, N> +{ + using type = index_sequence<N>; +}; + +template <std::size_t Begin, std::size_t End> +struct index_range : index_pack<Begin, End - 1> +{ +}; + +template <std::size_t N> +struct index_range<N, N> +{ + using type = index_sequence<>; +}; + +template <typename... T> +using index_sequence_for = typename index_range<0, sizeof...(T)>::type; + +template <std::size_t N> +using make_index_sequence = typename index_range<0, N>::type; + +#endif // defined(ASIO_HAS_STD_INDEX_SEQUENCE) + +} // namespace detail +} // namespace asio + +#endif // ASIO_DETAIL_UTILITY_HPP diff --git a/3rdparty/asio/include/asio/detail/variadic_templates.hpp b/3rdparty/asio/include/asio/detail/variadic_templates.hpp deleted file mode 100644 index 272ae28351e..00000000000 --- a/3rdparty/asio/include/asio/detail/variadic_templates.hpp +++ /dev/null @@ -1,119 +0,0 @@ -// -// detail/variadic_templates.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_VARIADIC_TEMPLATES_HPP -#define ASIO_DETAIL_VARIADIC_TEMPLATES_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) - -# define ASIO_VARIADIC_TPARAMS(n) ASIO_VARIADIC_TPARAMS_##n - -# define ASIO_VARIADIC_TPARAMS_1 \ - typename T1 -# define ASIO_VARIADIC_TPARAMS_2 \ - typename T1, typename T2 -# define ASIO_VARIADIC_TPARAMS_3 \ - typename T1, typename T2, typename T3 -# define ASIO_VARIADIC_TPARAMS_4 \ - typename T1, typename T2, typename T3, typename T4 -# define ASIO_VARIADIC_TPARAMS_5 \ - typename T1, typename T2, typename T3, typename T4, typename T5 - -# define ASIO_VARIADIC_TARGS(n) ASIO_VARIADIC_TARGS_##n - -# define ASIO_VARIADIC_TARGS_1 T1 -# define ASIO_VARIADIC_TARGS_2 T1, T2 -# define ASIO_VARIADIC_TARGS_3 T1, T2, T3 -# define ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4 -# define ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5 - -# define ASIO_VARIADIC_BYVAL_PARAMS(n) \ - ASIO_VARIADIC_BYVAL_PARAMS_##n - -# define ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1 -# define ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2 -# define ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3 -# define ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4 -# define ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5 - -# define ASIO_VARIADIC_BYVAL_ARGS(n) \ - ASIO_VARIADIC_BYVAL_ARGS_##n - -# define ASIO_VARIADIC_BYVAL_ARGS_1 x1 -# define ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2 -# define ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3 -# define ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4 -# define ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5 - -# define ASIO_VARIADIC_MOVE_PARAMS(n) \ - ASIO_VARIADIC_MOVE_PARAMS_##n - -# define ASIO_VARIADIC_MOVE_PARAMS_1 \ - ASIO_MOVE_ARG(T1) x1 -# define ASIO_VARIADIC_MOVE_PARAMS_2 \ - ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2 -# define ASIO_VARIADIC_MOVE_PARAMS_3 \ - ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ - ASIO_MOVE_ARG(T3) x3 -# define ASIO_VARIADIC_MOVE_PARAMS_4 \ - ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ - ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4 -# define ASIO_VARIADIC_MOVE_PARAMS_5 \ - ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \ - ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \ - ASIO_MOVE_ARG(T5) x5 - -# define ASIO_VARIADIC_MOVE_ARGS(n) \ - ASIO_VARIADIC_MOVE_ARGS_##n - -# define ASIO_VARIADIC_MOVE_ARGS_1 \ - ASIO_MOVE_CAST(T1)(x1) -# define ASIO_VARIADIC_MOVE_ARGS_2 \ - ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2) -# define ASIO_VARIADIC_MOVE_ARGS_3 \ - ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ - ASIO_MOVE_CAST(T3)(x3) -# define ASIO_VARIADIC_MOVE_ARGS_4 \ - ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ - ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4) -# define ASIO_VARIADIC_MOVE_ARGS_5 \ - ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \ - ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \ - ASIO_MOVE_CAST(T5)(x5) - -# define ASIO_VARIADIC_DECAY(n) \ - ASIO_VARIADIC_DECAY_##n - -# define ASIO_VARIADIC_DECAY_1 \ - typename decay<T1>::type -# define ASIO_VARIADIC_DECAY_2 \ - typename decay<T1>::type, typename decay<T2>::type -# define ASIO_VARIADIC_DECAY_3 \ - typename decay<T1>::type, typename decay<T2>::type, \ - typename decay<T3>::type -# define ASIO_VARIADIC_DECAY_4 \ - typename decay<T1>::type, typename decay<T2>::type, \ - typename decay<T3>::type, typename decay<T4>::type -# define ASIO_VARIADIC_DECAY_5 \ - typename decay<T1>::type, typename decay<T2>::type, \ - typename decay<T3>::type, typename decay<T4>::type, \ - typename decay<T5>::type - -# define ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) - -#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) - -#endif // ASIO_DETAIL_VARIADIC_TEMPLATES_HPP diff --git a/3rdparty/asio/include/asio/detail/wait_handler.hpp b/3rdparty/asio/include/asio/detail/wait_handler.hpp index 29bcfd75f1c..489a968cd77 100644 --- a/3rdparty/asio/include/asio/detail/wait_handler.hpp +++ b/3rdparty/asio/include/asio/detail/wait_handler.hpp @@ -2,7 +2,7 @@ // detail/wait_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,29 +16,29 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/wait_op.hpp" -#include "asio/io_context.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class wait_handler : public wait_op { public: ASIO_DEFINE_HANDLER_PTR(wait_handler); - wait_handler(Handler& h) + wait_handler(Handler& h, const IoExecutor& io_ex) : wait_op(&wait_handler::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(h)) + handler_(static_cast<Handler&&>(h)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -48,10 +48,14 @@ public: // Take ownership of the handler object. wait_handler* h(static_cast<wait_handler*>(base)); ptr p = { asio::detail::addressof(h->handler_), h, h }; - handler_work<Handler> w(h->handler_); ASIO_HANDLER_COMPLETION((*h)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + h->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -75,6 +79,7 @@ public: private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/wait_op.hpp b/3rdparty/asio/include/asio/detail/wait_op.hpp index 68bb86fd80c..548232c1c55 100644 --- a/3rdparty/asio/include/asio/detail/wait_op.hpp +++ b/3rdparty/asio/include/asio/detail/wait_op.hpp @@ -2,7 +2,7 @@ // detail/wait_op.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,9 +30,13 @@ public: // The error code to be passed to the completion handler. asio::error_code ec_; + // The operation key used for targeted cancellation. + void* cancellation_key_; + protected: wait_op(func_type func) - : operation(func) + : operation(func), + cancellation_key_(0) { } }; diff --git a/3rdparty/asio/include/asio/detail/win_event.hpp b/3rdparty/asio/include/asio/detail/win_event.hpp index aa04fd5edd3..e61843e5b9d 100644 --- a/3rdparty/asio/include/asio/detail/win_event.hpp +++ b/3rdparty/asio/include/asio/detail/win_event.hpp @@ -2,7 +2,7 @@ // detail/win_event.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,7 @@ #if defined(ASIO_WINDOWS) +#include <cstddef> #include "asio/detail/assert.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -67,6 +68,18 @@ public: ::SetEvent(events_[1]); } + // Unlock the mutex and signal one waiter who may destroy us. + template <typename Lock> + void unlock_and_signal_one_for_destruction(Lock& lock) + { + ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + ::SetEvent(events_[1]); + lock.unlock(); + } + // If there's a waiter, unlock the mutex and signal it. template <typename Lock> bool maybe_unlock_and_signal_one(Lock& lock) diff --git a/3rdparty/asio/include/asio/detail/win_fd_set_adapter.hpp b/3rdparty/asio/include/asio/detail/win_fd_set_adapter.hpp index 7d288f6244a..0e3e63f0c25 100644 --- a/3rdparty/asio/include/asio/detail/win_fd_set_adapter.hpp +++ b/3rdparty/asio/include/asio/detail/win_fd_set_adapter.hpp @@ -2,7 +2,7 @@ // detail/win_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/win_fenced_block.hpp b/3rdparty/asio/include/asio/detail/win_fenced_block.hpp deleted file mode 100644 index 42846ca7e96..00000000000 --- a/3rdparty/asio/include/asio/detail/win_fenced_block.hpp +++ /dev/null @@ -1,90 +0,0 @@ -// -// detail/win_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_DETAIL_WIN_FENCED_BLOCK_HPP -#define ASIO_DETAIL_WIN_FENCED_BLOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_WINDOWS) && !defined(UNDER_CE) - -#include "asio/detail/socket_types.hpp" -#include "asio/detail/noncopyable.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace detail { - -class win_fenced_block - : private noncopyable -{ -public: - enum half_t { half }; - enum full_t { full }; - - // Constructor for a half fenced block. - explicit win_fenced_block(half_t) - { - } - - // Constructor for a full fenced block. - explicit win_fenced_block(full_t) - { -#if defined(__BORLANDC__) - LONG barrier = 0; - ::InterlockedExchange(&barrier, 1); -#elif defined(ASIO_MSVC) \ - && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier)) -# if defined(_M_IX86) -# pragma warning(push) -# pragma warning(disable:4793) - LONG barrier; - __asm { xchg barrier, eax } -# pragma warning(pop) -# endif // defined(_M_IX86) -#else - MemoryBarrier(); -#endif - } - - // Destructor. - ~win_fenced_block() - { -#if defined(__BORLANDC__) - LONG barrier = 0; - ::InterlockedExchange(&barrier, 1); -#elif defined(ASIO_MSVC) \ - && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier)) -# if defined(_M_IX86) -# pragma warning(push) -# pragma warning(disable:4793) - LONG barrier; - __asm { xchg barrier, eax } -# pragma warning(pop) -# endif // defined(_M_IX86) -#else - MemoryBarrier(); -#endif - } -}; - -} // namespace detail -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_WINDOWS) && !defined(UNDER_CE) - -#endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/3rdparty/asio/include/asio/detail/win_global.hpp b/3rdparty/asio/include/asio/detail/win_global.hpp index 92ebdadfa8b..771f3fcba4b 100644 --- a/3rdparty/asio/include/asio/detail/win_global.hpp +++ b/3rdparty/asio/include/asio/detail/win_global.hpp @@ -2,7 +2,7 @@ // detail/win_global.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -35,7 +35,7 @@ struct win_global_impl static win_global_impl instance_; static static_mutex mutex_; - static T* ptr_; + T* ptr_; static tss_ptr<T> tss_ptr_; }; @@ -46,9 +46,6 @@ template <typename T> static_mutex win_global_impl<T>::mutex_ = ASIO_STATIC_MUTEX_INIT; template <typename T> -T* win_global_impl<T>::ptr_ = 0; - -template <typename T> tss_ptr<T> win_global_impl<T>::tss_ptr_; template <typename T> @@ -58,8 +55,9 @@ T& win_global() { win_global_impl<T>::mutex_.init(); static_mutex::scoped_lock lock(win_global_impl<T>::mutex_); - win_global_impl<T>::ptr_ = new T; - win_global_impl<T>::tss_ptr_ = win_global_impl<T>::ptr_; + if (win_global_impl<T>::instance_.ptr_ == 0) + win_global_impl<T>::instance_.ptr_ = new T; + win_global_impl<T>::tss_ptr_ = win_global_impl<T>::instance_.ptr_; } return *win_global_impl<T>::tss_ptr_; diff --git a/3rdparty/asio/include/asio/detail/win_iocp_file_service.hpp b/3rdparty/asio/include/asio/detail/win_iocp_file_service.hpp new file mode 100644 index 00000000000..f10a8d3cdf4 --- /dev/null +++ b/3rdparty/asio/include/asio/detail/win_iocp_file_service.hpp @@ -0,0 +1,287 @@ +// +// detail/win_iocp_file_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_WIN_IOCP_FILE_SERVICE_HPP +#define ASIO_DETAIL_WIN_IOCP_FILE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_FILE) + +#include <string> +#include "asio/detail/cstdint.hpp" +#include "asio/detail/win_iocp_handle_service.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" +#include "asio/file_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Extend win_iocp_handle_service to provide file support. +class win_iocp_file_service : + public execution_context_service_base<win_iocp_file_service> +{ +public: + // The native type of a file. + typedef win_iocp_handle_service::native_handle_type native_handle_type; + + // The implementation type of the file. + class implementation_type : win_iocp_handle_service::implementation_type + { + private: + // Only this service will have access to the internal values. + friend class win_iocp_file_service; + + uint64_t offset_; + bool is_stream_; + }; + + // Constructor. + ASIO_DECL win_iocp_file_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + ASIO_DECL void shutdown(); + + // Construct a new file implementation. + void construct(implementation_type& impl) + { + handle_service_.construct(impl); + impl.offset_ = 0; + impl.is_stream_ = false; + } + + // Move-construct a new file implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + handle_service_.move_construct(impl, other_impl); + impl.offset_ = other_impl.offset_; + impl.is_stream_ = other_impl.is_stream_; + other_impl.offset_ = 0; + } + + // Move-assign from another file implementation. + void move_assign(implementation_type& impl, + win_iocp_file_service& other_service, + implementation_type& other_impl) + { + handle_service_.move_assign(impl, + other_service.handle_service_, other_impl); + impl.offset_ = other_impl.offset_; + impl.is_stream_ = other_impl.is_stream_; + other_impl.offset_ = 0; + } + + // Destroy a file implementation. + void destroy(implementation_type& impl) + { + handle_service_.destroy(impl); + } + + // Set whether the implementation is stream-oriented. + void set_is_stream(implementation_type& impl, bool is_stream) + { + impl.is_stream_ = is_stream; + } + + // Open the file using the specified path name. + ASIO_DECL asio::error_code open(implementation_type& impl, + const char* path, file_base::flags open_flags, + asio::error_code& ec); + + // Assign a native handle to a file implementation. + asio::error_code assign(implementation_type& impl, + const native_handle_type& native_handle, + asio::error_code& ec) + { + return handle_service_.assign(impl, native_handle, ec); + } + + // Determine whether the file is open. + bool is_open(const implementation_type& impl) const + { + return handle_service_.is_open(impl); + } + + // Destroy a file implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + return handle_service_.close(impl, ec); + } + + // Get the native file representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return handle_service_.native_handle(impl); + } + + // Release ownership of a file. + native_handle_type release(implementation_type& impl, + asio::error_code& ec) + { + return handle_service_.release(impl, ec); + } + + // Cancel all operations associated with the file. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + return handle_service_.cancel(impl, ec); + } + + // Get the size of the file. + ASIO_DECL uint64_t size(const implementation_type& impl, + asio::error_code& ec) const; + + // Alter the size of the file. + ASIO_DECL asio::error_code resize(implementation_type& impl, + uint64_t n, asio::error_code& ec); + + // Synchronise the file to disk. + ASIO_DECL asio::error_code sync_all(implementation_type& impl, + asio::error_code& ec); + + // Synchronise the file data to disk. + ASIO_DECL asio::error_code sync_data(implementation_type& impl, + asio::error_code& ec); + + // Seek to a position in the file. + ASIO_DECL uint64_t seek(implementation_type& impl, int64_t offset, + file_base::seek_basis whence, asio::error_code& ec); + + // Write the given data. Returns the number of bytes written. + template <typename ConstBufferSequence> + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + uint64_t offset = impl.offset_; + impl.offset_ += asio::buffer_size(buffers); + return handle_service_.write_some_at(impl, offset, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + uint64_t offset = impl.offset_; + impl.offset_ += asio::buffer_size(buffers); + handle_service_.async_write_some_at(impl, offset, buffers, handler, io_ex); + } + + // Write the given data at the specified location. Returns the number of + // bytes written. + template <typename ConstBufferSequence> + size_t write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return handle_service_.write_some_at(impl, offset, buffers, ec); + } + + // Start an asynchronous write at the specified location. The data being + // written must be valid for the lifetime of the asynchronous operation. + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_write_some_at(implementation_type& impl, + uint64_t offset, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + handle_service_.async_write_some_at(impl, offset, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes read. + template <typename MutableBufferSequence> + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + uint64_t offset = impl.offset_; + impl.offset_ += asio::buffer_size(buffers); + return handle_service_.read_some_at(impl, offset, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + uint64_t offset = impl.offset_; + impl.offset_ += asio::buffer_size(buffers); + handle_service_.async_read_some_at(impl, offset, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes read. + template <typename MutableBufferSequence> + size_t read_some_at(implementation_type& impl, uint64_t offset, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return handle_service_.read_some_at(impl, offset, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_read_some_at(implementation_type& impl, + uint64_t offset, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + handle_service_.async_read_some_at(impl, offset, buffers, handler, io_ex); + } + +private: + // The implementation used for initiating asynchronous operations. + win_iocp_handle_service handle_service_; + + // Emulation of Windows IO_STATUS_BLOCK structure. + struct io_status_block + { + union u + { + LONG Status; + void* Pointer; + }; + ULONG_PTR Information; + }; + + // Emulation of flag passed to NtFlushBuffersFileEx. + enum { flush_flags_file_data_sync_only = 4 }; + + // The type of a NtFlushBuffersFileEx function pointer. + typedef LONG (NTAPI *nt_flush_buffers_file_ex_fn)( + HANDLE, ULONG, void*, ULONG, io_status_block*); + + // The NTFlushBuffersFileEx function pointer. + nt_flush_buffers_file_ex_fn nt_flush_buffers_file_ex_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/detail/impl/win_iocp_file_service.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_FILE) + +#endif // ASIO_DETAIL_WIN_IOCP_FILE_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/detail/win_iocp_handle_read_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_handle_read_op.hpp index c3ff79b0959..9721bda1c21 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_handle_read_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_handle_read_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_handle_read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -20,33 +20,33 @@ #if defined(ASIO_HAS_IOCP) -#include "asio/error.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" +#include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename MutableBufferSequence, typename Handler> +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class win_iocp_handle_read_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); - win_iocp_handle_read_op( - const MutableBufferSequence& buffers, Handler& handler) + win_iocp_handle_read_op(const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) : operation(&win_iocp_handle_read_op::do_complete), buffers_(buffers), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -56,12 +56,17 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { @@ -75,6 +80,8 @@ public: if (ec.value() == ERROR_HANDLE_EOF) ec = asio::error::eof; + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -99,6 +106,7 @@ public: private: MutableBufferSequence buffers_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_handle_service.hpp b/3rdparty/asio/include/asio/detail/win_iocp_handle_service.hpp index a1d07bd0531..9e2486b4b79 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_handle_service.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_handle_service.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_handle_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -20,8 +20,9 @@ #if defined(ASIO_HAS_IOCP) +#include "asio/associated_cancellation_slot.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/cstdint.hpp" #include "asio/detail/handler_alloc_helpers.hpp" @@ -38,7 +39,7 @@ namespace asio { namespace detail { class win_iocp_handle_service : - public service_base<win_iocp_handle_service> + public execution_context_service_base<win_iocp_handle_service> { public: // The native type of a stream handle. @@ -75,7 +76,7 @@ public: implementation_type* prev_; }; - ASIO_DECL win_iocp_handle_service(asio::io_context& io_context); + ASIO_DECL win_iocp_handle_service(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown(); @@ -109,6 +110,10 @@ public: ASIO_DECL asio::error_code close(implementation_type& impl, asio::error_code& ec); + // Release ownership of a handle. + ASIO_DECL native_handle_type release(implementation_type& impl, + asio::error_code& ec); + // Get the native handle representation. native_handle_type native_handle(const implementation_type& impl) const { @@ -142,43 +147,61 @@ public: // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, Handler& handler) + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op; + typedef win_iocp_handle_write_op< + ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(buffers, handler); + operation* o = p.p = new (p.v) op(buffers, handler, io_ex); ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o); + start_write_op(impl, 0, buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::first(buffers), p.p); + ConstBufferSequence>::first(buffers), o); p.v = p.p = 0; } // Start an asynchronous write at a specified offset. The data being written // must be valid for the lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> - void async_write_some_at(implementation_type& impl, uint64_t offset, - const ConstBufferSequence& buffers, Handler& handler) + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> + void async_write_some_at(implementation_type& impl, + uint64_t offset, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op; + typedef win_iocp_handle_write_op< + ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(buffers, handler); + operation* o = p.p = new (p.v) op(buffers, handler, io_ex); ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o); + start_write_op(impl, offset, buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::first(buffers), p.p); + ConstBufferSequence>::first(buffers), o); p.v = p.p = 0; } @@ -204,44 +227,64 @@ public: // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, Handler& handler) + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op; + typedef win_iocp_handle_read_op< + MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(buffers, handler); + operation* o = p.p = new (p.v) op(buffers, handler, io_ex); ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o); + start_read_op(impl, 0, buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::first(buffers), p.p); + MutableBufferSequence>::first(buffers), o); p.v = p.p = 0; } // Start an asynchronous read at a specified offset. The buffer for the data // being received must be valid for the lifetime of the asynchronous // operation. - template <typename MutableBufferSequence, typename Handler> - void async_read_some_at(implementation_type& impl, uint64_t offset, - const MutableBufferSequence& buffers, Handler& handler) + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> + void async_read_some_at(implementation_type& impl, + uint64_t offset, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op; + typedef win_iocp_handle_read_op< + MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(buffers, handler); + operation* o = p.p = new (p.v) op(buffers, handler, io_ex); ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o); + start_read_op(impl, offset, buffer_sequence_adapter<asio::mutable_buffer, - MutableBufferSequence>::first(buffers), p.p); + MutableBufferSequence>::first(buffers), o); p.v = p.p = 0; } @@ -251,22 +294,24 @@ private: const null_buffers& buffers, asio::error_code& ec); size_t write_some_at(implementation_type& impl, uint64_t offset, const null_buffers& buffers, asio::error_code& ec); - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_write_some(implementation_type& impl, - const null_buffers& buffers, Handler& handler); - template <typename Handler> + const null_buffers& buffers, Handler& handler, + const IoExecutor& io_ex); + template <typename Handler, typename IoExecutor> void async_write_some_at(implementation_type& impl, uint64_t offset, - const null_buffers& buffers, Handler& handler); + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); size_t read_some(implementation_type& impl, const null_buffers& buffers, asio::error_code& ec); size_t read_some_at(implementation_type& impl, uint64_t offset, const null_buffers& buffers, asio::error_code& ec); - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_read_some(implementation_type& impl, - const null_buffers& buffers, Handler& handler); - template <typename Handler> + const null_buffers& buffers, Handler& handler, + const IoExecutor& io_ex); + template <typename Handler, typename IoExecutor> void async_read_some_at(implementation_type& impl, uint64_t offset, - const null_buffers& buffers, Handler& handler); + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); // Helper class for waiting for synchronous operations to complete. class overlapped_wrapper; @@ -298,10 +343,73 @@ private: // destroyed. ASIO_DECL void close_for_destruction(implementation_type& impl); + // The type of a NtSetInformationFile function pointer. + typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG); + + // Helper function to get the NtSetInformationFile function pointer. If no + // NtSetInformationFile pointer has been obtained yet, one is obtained using + // GetProcAddress and the pointer is cached. Returns a null pointer if + // NtSetInformationFile is not available. + ASIO_DECL nt_set_info_fn get_nt_set_info(); + + // Helper function to emulate InterlockedCompareExchangePointer functionality + // for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp); + + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); + + // Helper class used to implement per operation cancellation. + class iocp_op_cancellation : public operation + { + public: + iocp_op_cancellation(HANDLE h, operation* target) + : operation(&iocp_op_cancellation::do_complete), + handle_(h), + target_(target) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + iocp_op_cancellation* o = static_cast<iocp_op_cancellation*>(base); + o->target_->complete(owner, result_ec, bytes_transferred); + } + + void operator()(cancellation_type_t type) + { +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + ::CancelIoEx(handle_, this); + } +#else // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + (void)type; +#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + } + + private: + HANDLE handle_; + operation* target_; + }; + // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_context& iocp_service_; + // Pointer to NtSetInformationFile implementation. + void* nt_set_info_; + // Mutex to protect access to the linked list of implementations. mutex mutex_; diff --git a/3rdparty/asio/include/asio/detail/win_iocp_handle_write_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_handle_write_op.hpp index 36019c88aa4..6a5b7e78338 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_handle_write_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_handle_write_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_handle_write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -20,44 +20,52 @@ #if defined(ASIO_HAS_IOCP) -#include "asio/error.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" +#include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename ConstBufferSequence, typename Handler> +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> class win_iocp_handle_write_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); - win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler& handler) + win_iocp_handle_write_op(const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) : operation(&win_iocp_handle_write_op::do_complete), buffers_(buffers), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, - const asio::error_code& ec, std::size_t bytes_transferred) + const asio::error_code& result_ec, std::size_t bytes_transferred) { + asio::error_code ec(result_ec); + // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { @@ -67,6 +75,8 @@ public: } #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -91,6 +101,7 @@ public: private: ConstBufferSequence buffers_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_io_context.hpp b/3rdparty/asio/include/asio/detail/win_iocp_io_context.hpp index 8b6803db792..1de94df7854 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_io_context.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_io_context.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_io_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -48,7 +48,10 @@ public: // Constructor. Specifies a concurrency hint that is passed through to the // underlying I/O completion port. ASIO_DECL win_iocp_io_context(asio::execution_context& ctx, - int concurrency_hint = -1); + int concurrency_hint = -1, bool own_thread = true); + + // Destructor. + ASIO_DECL ~win_iocp_io_context(); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown(); @@ -106,10 +109,10 @@ public: } // Return whether a handler can be dispatched immediately. - bool can_dispatch() - { - return thread_call_stack::contains(this) != 0; - } + ASIO_DECL bool can_dispatch(); + + /// Capture the current exception so it can be rethrown from a run function. + ASIO_DECL void capture_current_exception(); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. @@ -194,6 +197,12 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Cancel the timer operations associated with the given key. + template <typename Time_Traits> + void cancel_timer_by_key(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data* timer, + void* cancellation_key); + // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, @@ -218,7 +227,8 @@ private: // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). - ASIO_DECL size_t do_one(DWORD msec, asio::error_code& ec); + ASIO_DECL size_t do_one(DWORD msec, + win_iocp_thread_info& this_thread, asio::error_code& ec); // Helper to calculate the GetQueuedCompletionStatus timeout. ASIO_DECL static DWORD get_gqcs_timeout(); @@ -262,11 +272,13 @@ private: enum { +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) // Timeout to use with GetQueuedCompletionStatus on older versions of // Windows. Some versions of windows have a "bug" where a call to // GetQueuedCompletionStatus can appear stuck even though there are events // waiting on the queue. Using a timeout helps to work around the issue. default_gqcs_timeout = 500, +#endif // !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) // Maximum waitable timer timeout, in milliseconds. max_timeout_msec = 5 * 60 * 1000, @@ -287,6 +299,10 @@ private: // Timeout to use with GetQueuedCompletionStatus. const DWORD gqcs_timeout_; + // Helper class to run the scheduler in its own thread. + struct thread_function; + friend struct thread_function; + // Function object for processing timeouts in a background thread. struct timer_thread_function; friend struct timer_thread_function; @@ -311,6 +327,9 @@ private: // The concurrency hint used to initialise the io_context. const int concurrency_hint_; + + // The thread that is running the io_context. + scoped_ptr<thread> thread_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_null_buffers_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_null_buffers_op.hpp index f9e296debc1..07751b9234b 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_null_buffers_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_null_buffers_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_null_buffers_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,10 +20,9 @@ #if defined(ASIO_HAS_IOCP) #include "asio/detail/bind_handler.hpp" -#include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -34,20 +33,21 @@ namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class win_iocp_null_buffers_op : public reactor_op { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, - Handler& handler) - : reactor_op(&win_iocp_null_buffers_op::do_perform, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(asio::error_code(), + &win_iocp_null_buffers_op::do_perform, &win_iocp_null_buffers_op::do_complete), cancel_token_(cancel_token), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static status do_perform(reactor_op*) @@ -62,12 +62,17 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + // The reactor may have stored a result in the operation object. if (o->ec_) ec = o->ec_; @@ -85,6 +90,8 @@ public: ec = asio::error::connection_refused; } + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -109,6 +116,7 @@ public: private: socket_ops::weak_cancel_token_type cancel_token_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_operation.hpp b/3rdparty/asio/include/asio/detail/win_iocp_operation.hpp index 9f888b19498..a935f87b882 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_operation.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_operation.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -51,6 +51,16 @@ public: func_(0, this, asio::error_code(), 0); } + void reset() + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + hEvent = 0; + ready_ = 0; + } + protected: typedef void (*func_type)( void*, win_iocp_operation*, @@ -68,16 +78,6 @@ protected: { } - void reset() - { - Internal = 0; - InternalHigh = 0; - Offset = 0; - OffsetHigh = 0; - hEvent = 0; - ready_ = 0; - } - private: friend class op_queue_access; friend class win_iocp_io_context; diff --git a/3rdparty/asio/include/asio/detail/win_iocp_overlapped_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_overlapped_op.hpp index fde9a92c70a..dc65ad08311 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_overlapped_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_overlapped_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_overlapped_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,42 +19,51 @@ #if defined(ASIO_HAS_IOCP) -#include "asio/error.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" +#include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class win_iocp_overlapped_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); - win_iocp_overlapped_op(Handler& handler) + win_iocp_overlapped_op(Handler& handler, const IoExecutor& io_ex) : operation(&win_iocp_overlapped_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, - const asio::error_code& ec, std::size_t bytes_transferred) + const asio::error_code& result_ec, std::size_t bytes_transferred) { + asio::error_code ec(result_ec); + // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -78,6 +87,7 @@ public: private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp b/3rdparty/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp index 22025fd5fad..596705a38c6 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_overlapped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,6 +20,7 @@ #if defined(ASIO_HAS_IOCP) #include "asio/io_context.hpp" +#include "asio/query.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/noncopyable.hpp" @@ -44,13 +45,13 @@ public: } // Construct an win_iocp_overlapped_ptr to contain the specified handler. - template <typename Handler> - explicit win_iocp_overlapped_ptr( - asio::io_context& io_context, ASIO_MOVE_ARG(Handler) handler) + template <typename Executor, typename Handler> + explicit win_iocp_overlapped_ptr(const Executor& ex, + Handler&& handler) : ptr_(0), iocp_service_(0) { - this->reset(io_context, ASIO_MOVE_CAST(Handler)(handler)); + this->reset(ex, static_cast<Handler&&>(handler)); } // Destructor automatically frees the OVERLAPPED object unless released. @@ -73,22 +74,24 @@ public: // Reset to contain the specified handler, freeing any current OVERLAPPED // object. - template <typename Handler> - void reset(asio::io_context& io_context, Handler handler) + template <typename Executor, typename Handler> + void reset(const Executor& ex, Handler handler) { - typedef win_iocp_overlapped_op<Handler> op; + win_iocp_io_context* iocp_service = this->get_iocp_service(ex); + + typedef win_iocp_overlapped_op<Handler, Executor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, ex); - ASIO_HANDLER_CREATION((io_context, *p.p, - "io_context", &io_context.impl_, 0, "overlapped")); + ASIO_HANDLER_CREATION((ex.context(), *p.p, + "iocp_service", iocp_service, 0, "overlapped")); - io_context.impl_.work_started(); + iocp_service->work_started(); reset(); ptr_ = p.p; p.v = p.p = 0; - iocp_service_ = &io_context.impl_; + iocp_service_ = iocp_service; } // Get the contained OVERLAPPED object. @@ -129,6 +132,31 @@ public: } private: + template <typename Executor> + static win_iocp_io_context* get_iocp_service(const Executor& ex, + enable_if_t< + can_query<const Executor&, execution::context_t>::value + >* = 0) + { + return &use_service<win_iocp_io_context>( + asio::query(ex, execution::context)); + } + + template <typename Executor> + static win_iocp_io_context* get_iocp_service(const Executor& ex, + enable_if_t< + !can_query<const Executor&, execution::context_t>::value + >* = 0) + { + return &use_service<win_iocp_io_context>(ex.context()); + } + + static win_iocp_io_context* get_iocp_service( + const io_context::executor_type& ex) + { + return &asio::query(ex, execution::context).impl_; + } + win_iocp_operation* ptr_; win_iocp_io_context* iocp_service_; }; diff --git a/3rdparty/asio/include/asio/detail/win_iocp_serial_port_service.hpp b/3rdparty/asio/include/asio/detail/win_iocp_serial_port_service.hpp index 53856460c72..e0e12e91d5f 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_serial_port_service.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_serial_port_service.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_serial_port_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -22,7 +22,7 @@ #include <string> #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/detail/win_iocp_handle_service.hpp" #include "asio/detail/push_options.hpp" @@ -32,7 +32,7 @@ namespace detail { // Extend win_iocp_handle_service to provide serial port support. class win_iocp_serial_port_service : - public service_base<win_iocp_serial_port_service> + public execution_context_service_base<win_iocp_serial_port_service> { public: // The native type of a serial port. @@ -42,8 +42,7 @@ public: typedef win_iocp_handle_service::implementation_type implementation_type; // Constructor. - ASIO_DECL win_iocp_serial_port_service( - asio::io_context& io_context); + ASIO_DECL win_iocp_serial_port_service(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown(); @@ -138,6 +137,7 @@ public: asio::error_code& ec) { ec = asio::error::operation_not_supported; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -151,11 +151,12 @@ public: // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, Handler& handler) + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { - handle_service_.async_write_some(impl, buffers, handler); + handle_service_.async_write_some(impl, buffers, handler, io_ex); } // Read some data. Returns the number of bytes received. @@ -168,11 +169,13 @@ public: // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, Handler& handler) + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) { - handle_service_.async_read_some(impl, buffers, handler); + handle_service_.async_read_some(impl, buffers, handler, io_ex); } private: diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_accept_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_accept_op.hpp index 937f4c0f6f3..f4aa850be80 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_accept_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_accept_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_accept_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,10 +20,9 @@ #if defined(ASIO_HAS_IOCP) #include "asio/detail/bind_handler.hpp" -#include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" @@ -35,7 +34,8 @@ namespace asio { namespace detail { -template <typename Socket, typename Protocol, typename Handler> +template <typename Socket, typename Protocol, + typename Handler, typename IoExecutor> class win_iocp_socket_accept_op : public operation { public: @@ -44,7 +44,7 @@ public: win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, socket_type socket, Socket& peer, const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, - bool enable_connection_aborted, Handler& handler) + bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) : operation(&win_iocp_socket_accept_op::do_complete), socket_service_(socket_service), socket_(socket), @@ -52,9 +52,11 @@ public: protocol_(protocol), peer_endpoint_(peer_endpoint), enable_connection_aborted_(enable_connection_aborted), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + proxy_op_(0), + cancel_requested_(0), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } socket_holder& new_socket() @@ -72,6 +74,12 @@ public: return sizeof(sockaddr_storage_type) + 16; } + void enable_cancellation(long* cancel_requested, operation* proxy_op) + { + cancel_requested_ = cancel_requested; + proxy_op_ = proxy_op; + } + static void do_complete(void* owner, operation* base, const asio::error_code& result_ec, std::size_t /*bytes_transferred*/) @@ -79,9 +87,9 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); if (owner) { @@ -98,10 +106,13 @@ public: && !o->enable_connection_aborted_) { o->reset(); + if (o->proxy_op_) + o->proxy_op_->reset(); o->socket_service_.restart_accept_op(o->socket_, o->new_socket_, o->protocol_.family(), o->protocol_.type(), o->protocol_.protocol(), - o->output_buffer(), o->address_length(), o); + o->output_buffer(), o->address_length(), + o->cancel_requested_, o->proxy_op_ ? o->proxy_op_ : o); p.v = p.p = 0; return; } @@ -124,6 +135,13 @@ public: ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -154,12 +172,14 @@ private: typename Protocol::endpoint* peer_endpoint_; unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; + operation* proxy_op_; + long* cancel_requested_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; -#if defined(ASIO_HAS_MOVE) - -template <typename Protocol, typename Handler> +template <typename Protocol, typename PeerIoExecutor, + typename Handler, typename IoExecutor> class win_iocp_socket_move_accept_op : public operation { public: @@ -167,19 +187,21 @@ public: win_iocp_socket_move_accept_op( win_iocp_socket_service_base& socket_service, socket_type socket, - const Protocol& protocol, asio::io_context& peer_io_context, + const Protocol& protocol, const PeerIoExecutor& peer_io_ex, typename Protocol::endpoint* peer_endpoint, - bool enable_connection_aborted, Handler& handler) + bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) : operation(&win_iocp_socket_move_accept_op::do_complete), socket_service_(socket_service), socket_(socket), - peer_(peer_io_context), + peer_(peer_io_ex), protocol_(protocol), peer_endpoint_(peer_endpoint), enable_connection_aborted_(enable_connection_aborted), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + cancel_requested_(0), + proxy_op_(0), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } socket_holder& new_socket() @@ -197,6 +219,12 @@ public: return sizeof(sockaddr_storage_type) + 16; } + void enable_cancellation(long* cancel_requested, operation* proxy_op) + { + cancel_requested_ = cancel_requested; + proxy_op_ = proxy_op; + } + static void do_complete(void* owner, operation* base, const asio::error_code& result_ec, std::size_t /*bytes_transferred*/) @@ -204,10 +232,10 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_socket_move_accept_op* o( static_cast<win_iocp_socket_move_accept_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); if (owner) { @@ -224,10 +252,13 @@ public: && !o->enable_connection_aborted_) { o->reset(); + if (o->proxy_op_) + o->proxy_op_->reset(); o->socket_service_.restart_accept_op(o->socket_, o->new_socket_, o->protocol_.family(), o->protocol_.type(), o->protocol_.protocol(), - o->output_buffer(), o->address_length(), o); + o->output_buffer(), o->address_length(), + o->cancel_requested_, o->proxy_op_ ? o->proxy_op_ : o); p.v = p.p = 0; return; } @@ -250,6 +281,13 @@ public: ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -257,9 +295,9 @@ public: // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::move_binder2<Handler, - asio::error_code, typename Protocol::socket> - handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), ec, - ASIO_MOVE_CAST(typename Protocol::socket)(o->peer_)); + asio::error_code, peer_socket_type> + handler(0, static_cast<Handler&&>(o->handler_), ec, + static_cast<peer_socket_type&&>(o->peer_)); p.h = asio::detail::addressof(handler.handler_); p.reset(); @@ -274,19 +312,23 @@ public: } private: + typedef typename Protocol::socket::template + rebind_executor<PeerIoExecutor>::other peer_socket_type; + win_iocp_socket_service_base& socket_service_; socket_type socket_; socket_holder new_socket_; - typename Protocol::socket peer_; + peer_socket_type peer_; Protocol protocol_; typename Protocol::endpoint* peer_endpoint_; unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; + long* cancel_requested_; + operation* proxy_op_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; -#endif // defined(ASIO_HAS_MOVE) - } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_connect_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_connect_op.hpp index 4edd869c479..104ee87bb24 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_connect_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_connect_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_connect_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,7 +22,7 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -37,7 +37,8 @@ class win_iocp_socket_connect_op_base : public reactor_op { public: win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&win_iocp_socket_connect_op_base::do_perform, complete_func), + : reactor_op(asio::error_code(), + &win_iocp_socket_connect_op_base::do_perform, complete_func), socket_(socket), connect_ex_(false) { @@ -45,6 +46,7 @@ public: static status do_perform(reactor_op* base) { + ASIO_ASSUME(base != 0); win_iocp_socket_connect_op_base* o( static_cast<win_iocp_socket_connect_op_base*>(base)); @@ -56,18 +58,19 @@ public: bool connect_ex_; }; -template <typename Handler> +template <typename Handler, typename IoExecutor> class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op); - win_iocp_socket_connect_op(socket_type socket, Handler& handler) + win_iocp_socket_connect_op(socket_type socket, + Handler& handler, const IoExecutor& io_ex) : win_iocp_socket_connect_op_base(socket, &win_iocp_socket_connect_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -77,10 +80,10 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_socket_connect_op* o( static_cast<win_iocp_socket_connect_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); if (owner) { @@ -92,6 +95,13 @@ public: ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -115,6 +125,7 @@ public: private: Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_recv_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_recv_op.hpp index 98b000548d9..874a12aa7d0 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_recv_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_recv_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" @@ -34,7 +34,7 @@ namespace asio { namespace detail { -template <typename MutableBufferSequence, typename Handler> +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class win_iocp_socket_recv_op : public operation { public: @@ -42,14 +42,15 @@ public: win_iocp_socket_recv_op(socket_ops::state_type state, socket_ops::weak_cancel_token_type cancel_token, - const MutableBufferSequence& buffers, Handler& handler) + const MutableBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) : operation(&win_iocp_socket_recv_op::do_complete), state_(state), cancel_token_(cancel_token), buffers_(buffers), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -59,12 +60,17 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -79,6 +85,8 @@ public: MutableBufferSequence>::all_empty(o->buffers_), ec, bytes_transferred); + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -105,6 +113,7 @@ private: socket_ops::weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp index a7af87846d7..b4b98aa0148 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_recvfrom_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" @@ -34,7 +34,8 @@ namespace asio { namespace detail { -template <typename MutableBufferSequence, typename Endpoint, typename Handler> +template <typename MutableBufferSequence, typename Endpoint, + typename Handler, typename IoExecutor> class win_iocp_socket_recvfrom_op : public operation { public: @@ -42,15 +43,16 @@ public: win_iocp_socket_recvfrom_op(Endpoint& endpoint, socket_ops::weak_cancel_token_type cancel_token, - const MutableBufferSequence& buffers, Handler& handler) + const MutableBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) : operation(&win_iocp_socket_recvfrom_op::do_complete), endpoint_(endpoint), endpoint_size_(static_cast<int>(endpoint.capacity())), cancel_token_(cancel_token), buffers_(buffers), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } int& endpoint_size() @@ -65,13 +67,18 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_socket_recvfrom_op* o( static_cast<win_iocp_socket_recvfrom_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -86,6 +93,8 @@ public: // Record the size of the endpoint returned by the operation. o->endpoint_.resize(o->endpoint_size_); + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -113,6 +122,7 @@ private: socket_ops::weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp index 9e5952f6ce6..85e4b78dc20 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp @@ -1,8 +1,8 @@ // // detail/win_iocp_socket_recvmsg_op.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" @@ -35,7 +35,7 @@ namespace asio { namespace detail { -template <typename MutableBufferSequence, typename Handler> +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class win_iocp_socket_recvmsg_op : public operation { public: @@ -44,14 +44,15 @@ public: win_iocp_socket_recvmsg_op( socket_ops::weak_cancel_token_type cancel_token, const MutableBufferSequence& buffers, - socket_base::message_flags& out_flags, Handler& handler) + socket_base::message_flags& out_flags, + Handler& handler, const IoExecutor& io_ex) : operation(&win_iocp_socket_recvmsg_op::do_complete), cancel_token_(cancel_token), buffers_(buffers), out_flags_(out_flags), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -61,13 +62,18 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_socket_recvmsg_op* o( static_cast<win_iocp_socket_recvmsg_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -80,6 +86,8 @@ public: socket_ops::complete_iocp_recvmsg(o->cancel_token_, ec); o->out_flags_ = 0; + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -106,6 +114,7 @@ private: MutableBufferSequence buffers_; socket_base::message_flags& out_flags_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_send_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_send_op.hpp index 15c88a55014..c7043c4875e 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_send_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_send_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" @@ -34,20 +34,21 @@ namespace asio { namespace detail { -template <typename ConstBufferSequence, typename Handler> +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> class win_iocp_socket_send_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, - const ConstBufferSequence& buffers, Handler& handler) + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) : operation(&win_iocp_socket_send_op::do_complete), cancel_token_(cancel_token), buffers_(buffers), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, @@ -57,12 +58,17 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -74,6 +80,8 @@ public: socket_ops::complete_iocp_send(o->cancel_token_, ec); + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -99,6 +107,7 @@ private: socket_ops::weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp index 9040f7c9b96..faeaffa4c36 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_service.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -21,13 +21,12 @@ #include <cstring> #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/operation.hpp" @@ -51,7 +50,7 @@ namespace detail { template <typename Protocol> class win_iocp_socket_service : - public service_base<win_iocp_socket_service<Protocol> >, + public execution_context_service_base<win_iocp_socket_service<Protocol>>, public win_iocp_socket_service_base { public: @@ -129,9 +128,10 @@ public: }; // Constructor. - win_iocp_socket_service(asio::io_context& io_context) - : service_base<win_iocp_socket_service<Protocol> >(io_context), - win_iocp_socket_service_base(io_context) + win_iocp_socket_service(execution_context& context) + : execution_context_service_base< + win_iocp_socket_service<Protocol>>(context), + win_iocp_socket_service_base(context) { } @@ -143,7 +143,7 @@ public: // Move-construct a new socket implementation. void move_construct(implementation_type& impl, - implementation_type& other_impl) + implementation_type& other_impl) noexcept { this->base_move_construct(impl, other_impl); @@ -177,6 +177,7 @@ public: // Move-construct a new socket implementation from another protocol type. template <typename Protocol1> void converting_move_construct(implementation_type& impl, + win_iocp_socket_service<Protocol1>&, typename win_iocp_socket_service< Protocol1>::implementation_type& other_impl) { @@ -203,6 +204,8 @@ public: impl.have_remote_endpoint_ = false; impl.remote_endpoint_ = endpoint_type(); } + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -217,6 +220,8 @@ public: impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); impl.remote_endpoint_ = native_socket.remote_endpoint(); } + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -233,6 +238,8 @@ public: const endpoint_type& endpoint, asio::error_code& ec) { socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -244,6 +251,8 @@ public: socket_ops::setsockopt(impl.socket_, impl.state_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -258,6 +267,8 @@ public: option.data(impl.protocol_), &size, ec); if (!ec) option.resize(impl.protocol_, size); + + ASIO_ERROR_LOCATION(ec); return ec; } @@ -268,7 +279,10 @@ public: endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + { + ASIO_ERROR_LOCATION(ec); return endpoint_type(); + } endpoint.resize(addr_len); return endpoint; } @@ -281,7 +295,10 @@ public: std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, impl.have_remote_endpoint_, ec)) + { + ASIO_ERROR_LOCATION(ec); return endpoint_type(); + } endpoint.resize(addr_len); return endpoint; } @@ -304,9 +321,12 @@ public: buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); - return socket_ops::sync_sendto(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, + size_t n = socket_ops::sync_sendto(impl.socket_, + impl.state_, bufs.buffers(), bufs.count(), flags, destination.data(), destination.size(), ec); + + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be sent without blocking. @@ -316,50 +336,61 @@ public: { // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); - + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, - socket_base::message_flags flags, Handler& handler) + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; + typedef win_iocp_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + operation* o = p.p = new (p.v) op( + impl.cancel_token_, buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_send_to")); buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.socket_, o); + start_send_to_op(impl, bufs.buffers(), bufs.count(), destination.data(), static_cast<int>(destination.size()), - flags, p.p); + flags, o); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send_to(implementation_type& impl, const null_buffers&, - const endpoint_type&, socket_base::message_flags, Handler& handler) + const endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. - typedef win_iocp_null_buffers_op<Handler> op; + typedef win_iocp_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + reactor_op* o = p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_send_to(null_buffers)")); - start_reactor_op(impl, select_reactor::write_op, p.p); + start_reactor_op(impl, select_reactor::write_op, o); p.v = p.p = 0; } @@ -375,14 +406,15 @@ public: MutableBufferSequence> bufs(buffers); std::size_t addr_len = sender_endpoint.capacity(); - std::size_t bytes_recvd = socket_ops::sync_recvfrom( - impl.socket_, impl.state_, bufs.buffers(), bufs.count(), - flags, sender_endpoint.data(), &addr_len, ec); + std::size_t n = socket_ops::sync_recvfrom(impl.socket_, + impl.state_, bufs.buffers(), bufs.count(), flags, + sender_endpoint.data(), &addr_len, ec); if (!ec) sender_endpoint.resize(addr_len); - return bytes_recvd; + ASIO_ERROR_LOCATION(ec); + return n; } // Wait until data can be received without blocking. @@ -396,55 +428,85 @@ public: // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); + ASIO_ERROR_LOCATION(ec); return 0; } // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endp, - socket_base::message_flags flags, Handler& handler) + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_recvfrom_op< - MutableBufferSequence, endpoint_type, Handler> op; + typedef win_iocp_socket_recvfrom_op<MutableBufferSequence, + endpoint_type, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); + operation* o = p.p = new (p.v) op(sender_endp, + impl.cancel_token_, buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive_from")); buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.socket_, o); + start_receive_from_op(impl, bufs.buffers(), bufs.count(), - sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + sender_endp.data(), flags, &p.p->endpoint_size(), o); p.v = p.p = 0; } // Wait until data can be received without blocking. - template <typename Handler> - void async_receive_from(implementation_type& impl, - const null_buffers&, endpoint_type& sender_endpoint, - socket_base::message_flags flags, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_null_buffers_op<Handler> op; + typedef win_iocp_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive_from(null_buffers)")); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); - start_null_buffers_receive_op(impl, flags, p.p); + // Optionally register for per-operation cancellation. + operation* iocp_op = p.p; + if (slot.is_connected()) + { + p.p->cancellation_key_ = iocp_op = + &slot.template emplace<reactor_op_cancellation>( + impl.socket_, iocp_op); + } + + int op_type = start_null_buffers_receive_op(impl, flags, p.p, iocp_op); p.v = p.p = 0; + + // Update cancellation method if the reactor was used. + if (slot.is_connected() && op_type != -1) + { + static_cast<reactor_op_cancellation*>(iocp_op)->use_reactor( + &get_reactor(), &impl.reactor_data_, op_type); + } } // Accept a new connection. @@ -456,6 +518,7 @@ public: if (peer.is_open()) { ec = asio::error::already_open; + ASIO_ERROR_LOCATION(ec); return ec; } @@ -474,90 +537,87 @@ public: new_socket.release(); } + ASIO_ERROR_LOCATION(ec); return ec; } -#if defined(ASIO_HAS_MOVE) - // Accept a new connection. - typename Protocol::socket accept(implementation_type& impl, - io_context* peer_io_context, endpoint_type* peer_endpoint, - asio::error_code& ec) - { - typename Protocol::socket peer( - peer_io_context ? *peer_io_context : io_context_); - - std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; - socket_holder new_socket(socket_ops::sync_accept(impl.socket_, - impl.state_, peer_endpoint ? peer_endpoint->data() : 0, - peer_endpoint ? &addr_len : 0, ec)); - - // On success, assign new connection to peer socket object. - if (new_socket.get() != invalid_socket) - { - if (peer_endpoint) - peer_endpoint->resize(addr_len); - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - } - - return peer; - } -#endif // defined(ASIO_HAS_MOVE) - // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. - template <typename Socket, typename Handler> + template <typename Socket, typename Handler, typename IoExecutor> void async_accept(implementation_type& impl, Socket& peer, - endpoint_type* peer_endpoint, Handler& handler) + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op; + typedef win_iocp_socket_accept_op<Socket, + protocol_type, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; bool enable_connection_aborted = (impl.state_ & socket_ops::enable_connection_aborted) != 0; - p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, - peer_endpoint, enable_connection_aborted, handler); + operation* o = p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, + peer_endpoint, enable_connection_aborted, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_accept")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + accept_op_cancellation* c = + &slot.template emplace<accept_op_cancellation>(impl.socket_, o); + p.p->enable_cancellation(c->get_cancel_requested(), c); + o = c; + } + start_accept_op(impl, peer.is_open(), p.p->new_socket(), impl.protocol_.family(), impl.protocol_.type(), impl.protocol_.protocol(), p.p->output_buffer(), - p.p->address_length(), p.p); + p.p->address_length(), o); p.v = p.p = 0; } -#if defined(ASIO_HAS_MOVE) // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. - template <typename Handler> - void async_accept(implementation_type& impl, - asio::io_context* peer_io_context, - endpoint_type* peer_endpoint, Handler& handler) + template <typename PeerIoExecutor, typename Handler, typename IoExecutor> + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_move_accept_op<protocol_type, Handler> op; + typedef win_iocp_socket_move_accept_op< + protocol_type, PeerIoExecutor, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; bool enable_connection_aborted = (impl.state_ & socket_ops::enable_connection_aborted) != 0; - p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, - peer_io_context ? *peer_io_context : io_context_, - peer_endpoint, enable_connection_aborted, handler); + operation* o = p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, + peer_io_ex, peer_endpoint, enable_connection_aborted, + handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_accept")); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + accept_op_cancellation* c = + &slot.template emplace<accept_op_cancellation>(impl.socket_, o); + p.p->enable_cancellation(c->get_cancel_requested(), c); + o = c; + } + start_accept_op(impl, false, p.p->new_socket(), impl.protocol_.family(), impl.protocol_.type(), impl.protocol_.protocol(), p.p->output_buffer(), - p.p->address_length(), p.p); + p.p->address_length(), o); p.v = p.p = 0; } -#endif // defined(ASIO_HAS_MOVE) // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, @@ -565,26 +625,48 @@ public: { socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); + ASIO_ERROR_LOCATION(ec); return ec; } // Start an asynchronous connect. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, Handler& handler) + const endpoint_type& peer_endpoint, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_connect_op<Handler> op; + typedef win_iocp_socket_connect_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, handler); + p.p = new (p.v) op(impl.socket_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_connect")); - start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(), - peer_endpoint.data(), static_cast<int>(peer_endpoint.size()), p.p); + // Optionally register for per-operation cancellation. + operation* iocp_op = p.p; + if (slot.is_connected()) + { + p.p->cancellation_key_ = iocp_op = + &slot.template emplace<reactor_op_cancellation>( + impl.socket_, iocp_op); + } + + int op_type = start_connect_op(impl, impl.protocol_.family(), + impl.protocol_.type(), peer_endpoint.data(), + static_cast<int>(peer_endpoint.size()), p.p, iocp_op); p.v = p.p = 0; + + // Update cancellation method if the reactor was used. + if (slot.is_connected() && op_type != -1) + { + static_cast<reactor_op_cancellation*>(iocp_op)->use_reactor( + &get_reactor(), &impl.reactor_data_, op_type); + } } }; diff --git a/3rdparty/asio/include/asio/detail/win_iocp_socket_service_base.hpp b/3rdparty/asio/include/asio/detail/win_iocp_socket_service_base.hpp index 9f22adc9808..a157143e35b 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_socket_service_base.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_socket_service_base.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_socket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,14 +19,14 @@ #if defined(ASIO_HAS_IOCP) +#include "asio/associated_cancellation_slot.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/operation.hpp" @@ -85,8 +85,7 @@ public: }; // Constructor. - ASIO_DECL win_iocp_socket_service_base( - asio::io_context& io_context); + ASIO_DECL win_iocp_socket_service_base(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void base_shutdown(); @@ -96,7 +95,7 @@ public: // Move-construct a new socket implementation. ASIO_DECL void base_move_construct(base_implementation_type& impl, - base_implementation_type& other_impl); + base_implementation_type& other_impl) noexcept; // Move-assign from another socket implementation. ASIO_DECL void base_move_assign(base_implementation_type& impl, @@ -116,6 +115,10 @@ public: ASIO_DECL asio::error_code close( base_implementation_type& impl, asio::error_code& ec); + // Release ownership of the socket. + ASIO_DECL socket_type release( + base_implementation_type& impl, asio::error_code& ec); + // Cancel all operations associated with the socket. ASIO_DECL asio::error_code cancel( base_implementation_type& impl, asio::error_code& ec); @@ -206,31 +209,46 @@ public: // Asynchronously wait for the socket to become ready to read, ready to // write, or to have pending error conditions. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_wait(base_implementation_type& impl, - socket_base::wait_type w, Handler& handler) + socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef win_iocp_wait_op<Handler> op; + typedef win_iocp_wait_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_wait")); + // Optionally register for per-operation cancellation. + operation* iocp_op = p.p; + if (slot.is_connected()) + { + p.p->cancellation_key_ = iocp_op = + &slot.template emplace<reactor_op_cancellation>( + impl.socket_, iocp_op); + } + + int op_type = -1; switch (w) { case socket_base::wait_read: - start_null_buffers_receive_op(impl, 0, p.p); + op_type = start_null_buffers_receive_op(impl, 0, p.p, iocp_op); break; case socket_base::wait_write: + op_type = select_reactor::write_op; start_reactor_op(impl, select_reactor::write_op, p.p); break; case socket_base::wait_error: + op_type = select_reactor::read_op; start_reactor_op(impl, select_reactor::except_op, p.p); break; default: @@ -240,6 +258,13 @@ public: } p.v = p.p = 0; + + // Update cancellation method if the reactor was used. + if (slot.is_connected() && op_type != -1) + { + static_cast<reactor_op_cancellation*>(iocp_op)->use_reactor( + &get_reactor(), &impl.reactor_data_, op_type); + } } // Send the given data to the peer. Returns the number of bytes sent. @@ -267,41 +292,50 @@ public: // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send(base_implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; + typedef win_iocp_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + operation* o = p.p = new (p.v) op( + impl.cancel_token_, buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_send")); buffer_sequence_adapter<asio::const_buffer, ConstBufferSequence> bufs(buffers); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.socket_, o); + start_send_op(impl, bufs.buffers(), bufs.count(), flags, (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), - p.p); + o); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send(base_implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. - typedef win_iocp_null_buffers_op<Handler> op; + typedef win_iocp_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_send(null_buffers)")); start_reactor_op(impl, select_reactor::write_op, p.p); @@ -333,45 +367,75 @@ public: // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive(base_implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op; + typedef win_iocp_socket_recv_op< + MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler); + operation* o = p.p = new (p.v) op(impl.state_, + impl.cancel_token_, buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive")); buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.socket_, o); + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), - p.p); + o); p.v = p.p = 0; } // Wait until data can be received without blocking. - template <typename Handler> - void async_receive(base_implementation_type& impl, const null_buffers&, - socket_base::message_flags flags, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_receive(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_null_buffers_op<Handler> op; + typedef win_iocp_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive(null_buffers)")); - start_null_buffers_receive_op(impl, flags, p.p); + // Optionally register for per-operation cancellation. + operation* iocp_op = p.p; + if (slot.is_connected()) + { + p.p->cancellation_key_ = iocp_op = + &slot.template emplace<reactor_op_cancellation>( + impl.socket_, iocp_op); + } + + int op_type = start_null_buffers_receive_op(impl, flags, p.p, iocp_op); p.v = p.p = 0; + + // Update cancellation method if the reactor was used. + if (slot.is_connected() && op_type != -1) + { + static_cast<reactor_op_cancellation*>(iocp_op)->use_reactor( + &get_reactor(), &impl.reactor_data_, op_type); + } } // Receive some data with associated flags. Returns the number of bytes @@ -406,53 +470,85 @@ public: // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive_with_flags(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags in_flags, - socket_base::message_flags& out_flags, Handler& handler) + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_socket_recvmsg_op<MutableBufferSequence, Handler> op; + typedef win_iocp_socket_recvmsg_op< + MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, buffers, out_flags, handler); + operation* o = p.p = new (p.v) op(impl.cancel_token_, + buffers, out_flags, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags")); buffer_sequence_adapter<asio::mutable_buffer, MutableBufferSequence> bufs(buffers); - start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, p.p); + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + o = &slot.template emplace<iocp_op_cancellation>(impl.socket_, o); + + start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, o); p.v = p.p = 0; } // Wait until data can be received without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_receive_with_flags(base_implementation_type& impl, const null_buffers&, socket_base::message_flags in_flags, - socket_base::message_flags& out_flags, Handler& handler) + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + // Allocate and construct an operation to wrap the handler. - typedef win_iocp_null_buffers_op<Handler> op; + typedef win_iocp_null_buffers_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.cancel_token_, handler); + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + ASIO_HANDLER_CREATION((context_, *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); // Reset out_flags since it can be given no sensible value at this time. out_flags = 0; - start_null_buffers_receive_op(impl, in_flags, p.p); + // Optionally register for per-operation cancellation. + operation* iocp_op = p.p; + if (slot.is_connected()) + { + p.p->cancellation_key_ = iocp_op = + &slot.template emplace<reactor_op_cancellation>( + impl.socket_, iocp_op); + } + + int op_type = start_null_buffers_receive_op(impl, in_flags, p.p, iocp_op); p.v = p.p = 0; + + // Update cancellation method if the reactor was used. + if (slot.is_connected() && op_type != -1) + { + static_cast<reactor_op_cancellation*>(iocp_op)->use_reactor( + &get_reactor(), &impl.reactor_data_, op_type); + } } // Helper function to restart an asynchronous accept operation. ASIO_DECL void restart_accept_op(socket_type s, - socket_holder& new_socket, int family, int type, int protocol, - void* output_buffer, DWORD address_length, operation* op); + socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, + long* cancel_requested, operation* op); protected: // Open a new socket implementation. @@ -472,9 +568,8 @@ protected: // Helper function to start an asynchronous send_to operation. ASIO_DECL void start_send_to_op(base_implementation_type& impl, - WSABUF* buffers, std::size_t buffer_count, - const socket_addr_type* addr, int addrlen, - socket_base::message_flags flags, operation* op); + WSABUF* buffers, std::size_t buffer_count, const void* addr, + int addrlen, socket_base::message_flags flags, operation* op); // Helper function to start an asynchronous receive operation. ASIO_DECL void start_receive_op(base_implementation_type& impl, @@ -482,13 +577,13 @@ protected: socket_base::message_flags flags, bool noop, operation* op); // Helper function to start an asynchronous null_buffers receive operation. - ASIO_DECL void start_null_buffers_receive_op( - base_implementation_type& impl, - socket_base::message_flags flags, reactor_op* op); + ASIO_DECL int start_null_buffers_receive_op( + base_implementation_type& impl, socket_base::message_flags flags, + reactor_op* op, operation* iocp_op); // Helper function to start an asynchronous receive_from operation. ASIO_DECL void start_receive_from_op(base_implementation_type& impl, - WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + WSABUF* buffers, std::size_t buffer_count, void* addr, socket_base::message_flags flags, int* addrlen, operation* op); // Helper function to start an asynchronous accept operation. @@ -501,9 +596,9 @@ protected: int op_type, reactor_op* op); // Start the asynchronous connect operation using the reactor. - ASIO_DECL void start_connect_op(base_implementation_type& impl, - int family, int type, const socket_addr_type* remote_addr, - std::size_t remote_addrlen, win_iocp_socket_connect_op_base* op); + ASIO_DECL int start_connect_op(base_implementation_type& impl, + int family, int type, const void* remote_addr, std::size_t remote_addrlen, + win_iocp_socket_connect_op_base* op, operation* iocp_op); // Helper function to close a socket when the associated object is being // destroyed. @@ -514,8 +609,8 @@ protected: base_implementation_type& impl); // Helper function to get the reactor. If no reactor has been created yet, a - // new one is obtained from the io_context and a pointer to it is cached in - // this service. + // new one is obtained from the execution context and a pointer to it is + // cached in this service. ASIO_DECL select_reactor& get_reactor(); // The type of a ConnectEx function pointer, as old SDKs may not provide it. @@ -528,6 +623,15 @@ protected: ASIO_DECL connect_ex_fn get_connect_ex( base_implementation_type& impl, int type); + // The type of a NtSetInformationFile function pointer. + typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG); + + // Helper function to get the NtSetInformationFile function pointer. If no + // NtSetInformationFile pointer has been obtained yet, one is obtained using + // GetProcAddress and the pointer is cached. Returns a null pointer if + // NtSetInformationFile is not available. + ASIO_DECL nt_set_info_fn get_nt_set_info(); + // Helper function to emulate InterlockedCompareExchangePointer functionality // for: // - very old Platform SDKs; and @@ -540,8 +644,155 @@ protected: // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); - // The io_context used to obtain the reactor, if required. - asio::io_context& io_context_; + // Helper class used to implement per operation cancellation. + class iocp_op_cancellation : public operation + { + public: + iocp_op_cancellation(SOCKET s, operation* target) + : operation(&iocp_op_cancellation::do_complete), + socket_(s), + target_(target) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + iocp_op_cancellation* o = static_cast<iocp_op_cancellation*>(base); + o->target_->complete(owner, result_ec, bytes_transferred); + } + + void operator()(cancellation_type_t type) + { +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(socket_); + ::CancelIoEx(sock_as_handle, this); + } +#else // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + (void)type; +#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + } + + private: + SOCKET socket_; + operation* target_; + }; + + // Helper class used to implement per operation cancellation. + class accept_op_cancellation : public operation + { + public: + accept_op_cancellation(SOCKET s, operation* target) + : operation(&iocp_op_cancellation::do_complete), + socket_(s), + target_(target), + cancel_requested_(0) + { + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + accept_op_cancellation* o = static_cast<accept_op_cancellation*>(base); + o->target_->complete(owner, result_ec, bytes_transferred); + } + + long* get_cancel_requested() + { + return &cancel_requested_; + } + + void operator()(cancellation_type_t type) + { +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(socket_); + ::CancelIoEx(sock_as_handle, this); + } +#else // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + (void)type; +#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + } + + private: + SOCKET socket_; + operation* target_; + long cancel_requested_; + }; + + // Helper class used to implement per operation cancellation. + class reactor_op_cancellation : public operation + { + public: + reactor_op_cancellation(SOCKET s, operation* base) + : operation(&reactor_op_cancellation::do_complete), + socket_(s), + target_(base), + reactor_(0), + reactor_data_(0), + op_type_(-1) + { + } + + void use_reactor(select_reactor* r, + select_reactor::per_descriptor_data* p, int o) + { + reactor_ = r; + reactor_data_ = p; + op_type_ = o; + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& result_ec, + std::size_t bytes_transferred) + { + reactor_op_cancellation* o = static_cast<reactor_op_cancellation*>(base); + o->target_->complete(owner, result_ec, bytes_transferred); + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + if (reactor_) + { + reactor_->cancel_ops_by_key(socket_, + *reactor_data_, op_type_, this); + } + else + { +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(socket_); + ::CancelIoEx(sock_as_handle, this); +#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + } + } + } + + private: + SOCKET socket_; + operation* target_; + select_reactor* reactor_; + select_reactor::per_descriptor_data* reactor_data_; + int op_type_; + }; + + // The execution context used to obtain the reactor, if required. + execution_context& context_; // The IOCP service used for running asynchronous operations and dispatching // handlers. @@ -554,6 +805,9 @@ protected: // Pointer to ConnectEx implementation. void* connect_ex_; + // Pointer to NtSetInformationFile implementation. + void* nt_set_info_; + // Mutex to protect access to the linked list of implementations. asio::detail::mutex mutex_; diff --git a/3rdparty/asio/include/asio/detail/win_iocp_thread_info.hpp b/3rdparty/asio/include/asio/detail/win_iocp_thread_info.hpp index ae13dd47100..3f1e0126779 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_thread_info.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_thread_info.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_thread_info.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/win_iocp_wait_op.hpp b/3rdparty/asio/include/asio/detail/win_iocp_wait_op.hpp index d5178d04734..882f16e73cf 100644 --- a/3rdparty/asio/include/asio/detail/win_iocp_wait_op.hpp +++ b/3rdparty/asio/include/asio/detail/win_iocp_wait_op.hpp @@ -2,7 +2,7 @@ // detail/win_iocp_wait_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" @@ -34,20 +34,21 @@ namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class win_iocp_wait_op : public reactor_op { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op); win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token, - Handler& handler) - : reactor_op(&win_iocp_wait_op::do_perform, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(asio::error_code(), + &win_iocp_wait_op::do_perform, &win_iocp_wait_op::do_complete), cancel_token_(cancel_token), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static status do_perform(reactor_op*) @@ -62,12 +63,17 @@ public: asio::error_code ec(result_ec); // Take ownership of the operation object. + ASIO_ASSUME(base != 0); win_iocp_wait_op* o(static_cast<win_iocp_wait_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + // The reactor may have stored a result in the operation object. if (o->ec_) ec = o->ec_; @@ -85,6 +91,8 @@ public: ec = asio::error::connection_refused; } + ASIO_ERROR_LOCATION(ec); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -109,6 +117,7 @@ public: private: socket_ops::weak_cancel_token_type cancel_token_; Handler handler_; + handler_work<Handler, IoExecutor> work_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/win_mutex.hpp b/3rdparty/asio/include/asio/detail/win_mutex.hpp index 350a02dce2a..77603ec9750 100644 --- a/3rdparty/asio/include/asio/detail/win_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/win_mutex.hpp @@ -2,7 +2,7 @@ // detail/win_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/win_object_handle_service.hpp b/3rdparty/asio/include/asio/detail/win_object_handle_service.hpp index 59605549f42..8e01b72f4f6 100644 --- a/3rdparty/asio/include/asio/detail/win_object_handle_service.hpp +++ b/3rdparty/asio/include/asio/detail/win_object_handle_service.hpp @@ -2,7 +2,7 @@ // detail/win_object_handle_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2011 Boris Schaeling (boris@highscore.de) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -20,11 +20,16 @@ #if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/wait_handler.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) #include "asio/detail/push_options.hpp" @@ -32,7 +37,7 @@ namespace asio { namespace detail { class win_object_handle_service : - public service_base<win_object_handle_service> + public execution_context_service_base<win_object_handle_service> { public: // The native type of an object handle. @@ -79,8 +84,7 @@ public: }; // Constructor. - ASIO_DECL win_object_handle_service( - asio::io_context& io_context); + ASIO_DECL win_object_handle_service(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown(); @@ -129,16 +133,17 @@ public: asio::error_code& ec); /// Start an asynchronous wait. - template <typename Handler> - void async_wait(implementation_type& impl, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. - typedef wait_handler<Handler> op; + typedef wait_handler<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_ex); - ASIO_HANDLER_CREATION((io_context_.context(), *p.p, "object_handle", + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "object_handle", &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "async_wait")); start_wait_op(impl, p.p); @@ -157,8 +162,13 @@ private: static ASIO_DECL VOID CALLBACK wait_callback( PVOID param, BOOLEAN timeout); - // The io_context implementation used to post completions. - io_context_impl& io_context_; + // The scheduler used to post completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; // Mutex to protect access to internal state. mutex mutex_; diff --git a/3rdparty/asio/include/asio/detail/win_static_mutex.hpp b/3rdparty/asio/include/asio/detail/win_static_mutex.hpp index 6f0e75b4109..736ef0e3f2c 100644 --- a/3rdparty/asio/include/asio/detail/win_static_mutex.hpp +++ b/3rdparty/asio/include/asio/detail/win_static_mutex.hpp @@ -2,7 +2,7 @@ // detail/win_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/win_thread.hpp b/3rdparty/asio/include/asio/detail/win_thread.hpp index ab2ba8d95bc..c1e7b8e618a 100644 --- a/3rdparty/asio/include/asio/detail/win_thread.hpp +++ b/3rdparty/asio/include/asio/detail/win_thread.hpp @@ -2,7 +2,7 @@ // detail/win_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/win_tss_ptr.hpp b/3rdparty/asio/include/asio/detail/win_tss_ptr.hpp index 490c705783d..95a87717bad 100644 --- a/3rdparty/asio/include/asio/detail/win_tss_ptr.hpp +++ b/3rdparty/asio/include/asio/detail/win_tss_ptr.hpp @@ -2,7 +2,7 @@ // detail/win_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/winapp_thread.hpp b/3rdparty/asio/include/asio/detail/winapp_thread.hpp index 4d13109bdf0..efa662dfe6f 100644 --- a/3rdparty/asio/include/asio/detail/winapp_thread.hpp +++ b/3rdparty/asio/include/asio/detail/winapp_thread.hpp @@ -2,7 +2,7 @@ // detail/winapp_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,8 +19,8 @@ #if defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP) -#include "asio/detail/memory.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_ptr.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" @@ -40,7 +40,7 @@ public: template <typename Function> winapp_thread(Function f, unsigned int = 0) { - std::auto_ptr<func_base> arg(new func<Function>(f)); + scoped_ptr<func_base> arg(new func<Function>(f)); DWORD thread_id = 0; thread_ = ::CreateThread(0, 0, winapp_thread_function, arg.get(), 0, &thread_id); @@ -108,7 +108,7 @@ private: inline DWORD WINAPI winapp_thread_function(LPVOID arg) { - std::auto_ptr<winapp_thread::func_base> func( + scoped_ptr<winapp_thread::func_base> func( static_cast<winapp_thread::func_base*>(arg)); func->run(); return 0; diff --git a/3rdparty/asio/include/asio/detail/wince_thread.hpp b/3rdparty/asio/include/asio/detail/wince_thread.hpp index 5e0d4ec0250..3c6b8543c21 100644 --- a/3rdparty/asio/include/asio/detail/wince_thread.hpp +++ b/3rdparty/asio/include/asio/detail/wince_thread.hpp @@ -2,7 +2,7 @@ // detail/wince_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,8 +19,8 @@ #if defined(ASIO_WINDOWS) && defined(UNDER_CE) -#include "asio/detail/memory.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/scoped_ptr.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" @@ -40,7 +40,7 @@ public: template <typename Function> wince_thread(Function f, unsigned int = 0) { - std::auto_ptr<func_base> arg(new func<Function>(f)); + scoped_ptr<func_base> arg(new func<Function>(f)); DWORD thread_id = 0; thread_ = ::CreateThread(0, 0, wince_thread_function, arg.get(), 0, &thread_id); @@ -108,7 +108,7 @@ private: inline DWORD WINAPI wince_thread_function(LPVOID arg) { - std::auto_ptr<wince_thread::func_base> func( + scoped_ptr<wince_thread::func_base> func( static_cast<wince_thread::func_base*>(arg)); func->run(); return 0; diff --git a/3rdparty/asio/include/asio/detail/winrt_async_manager.hpp b/3rdparty/asio/include/asio/detail/winrt_async_manager.hpp index 921dfdd6274..9d0f9023c8c 100644 --- a/3rdparty/asio/include/asio/detail/winrt_async_manager.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_async_manager.hpp @@ -2,7 +2,7 @@ // detail/winrt_async_manager.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,13 @@ #include "asio/detail/atomic_count.hpp" #include "asio/detail/winrt_async_op.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) #include "asio/detail/push_options.hpp" @@ -31,13 +37,13 @@ namespace asio { namespace detail { class winrt_async_manager - : public asio::detail::service_base<winrt_async_manager> + : public execution_context_service_base<winrt_async_manager> { public: // Constructor. - winrt_async_manager(asio::io_context& io_context) - : asio::detail::service_base<winrt_async_manager>(io_context), - io_context_(use_service<io_context_impl>(io_context)), + winrt_async_manager(execution_context& context) + : execution_context_service_base<winrt_async_manager>(context), + scheduler_(use_service<scheduler_impl>(context)), outstanding_ops_(1) { } @@ -185,12 +191,12 @@ public: asio::system_category()); break; } - io_context_.post_deferred_completion(handler); + scheduler_.post_deferred_completion(handler); if (--outstanding_ops_ == 0) promise_.set_value(); }); - io_context_.work_started(); + scheduler_.work_started(); ++outstanding_ops_; action->Completed = on_completed; } @@ -222,12 +228,12 @@ public: asio::system_category()); break; } - io_context_.post_deferred_completion(handler); + scheduler_.post_deferred_completion(handler); if (--outstanding_ops_ == 0) promise_.set_value(); }); - io_context_.work_started(); + scheduler_.work_started(); ++outstanding_ops_; operation->Completed = on_completed; } @@ -263,19 +269,24 @@ public: asio::system_category()); break; } - io_context_.post_deferred_completion(handler); + scheduler_.post_deferred_completion(handler); if (--outstanding_ops_ == 0) promise_.set_value(); }); - io_context_.work_started(); + scheduler_.work_started(); ++outstanding_ops_; operation->Completed = on_completed; } private: - // The io_context implementation used to post completed handlers. - io_context_impl& io_context_; + // The scheduler implementation used to post completed handlers. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; // Count of outstanding operations. atomic_count outstanding_ops_; diff --git a/3rdparty/asio/include/asio/detail/winrt_async_op.hpp b/3rdparty/asio/include/asio/detail/winrt_async_op.hpp index 2b18b431f56..a34989841bc 100644 --- a/3rdparty/asio/include/asio/detail/winrt_async_op.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_async_op.hpp @@ -2,7 +2,7 @@ // detail/winrt_async_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/detail/winrt_resolve_op.hpp b/3rdparty/asio/include/asio/detail/winrt_resolve_op.hpp index a197c3d3757..3cbd00e61f2 100644 --- a/3rdparty/asio/include/asio/detail/winrt_resolve_op.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_resolve_op.hpp @@ -2,7 +2,7 @@ // detail/winrt_resolve_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -22,7 +22,7 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/winrt_async_op.hpp" #include "asio/ip/basic_resolver_results.hpp" @@ -33,7 +33,7 @@ namespace asio { namespace detail { -template <typename Protocol, typename Handler> +template <typename Protocol, typename Handler, typename IoExecutor> class winrt_resolve_op : public winrt_async_op< Windows::Foundation::Collections::IVectorView< @@ -46,27 +46,33 @@ public: typedef asio::ip::basic_resolver_query<Protocol> query_type; typedef asio::ip::basic_resolver_results<Protocol> results_type; - winrt_resolve_op(const query_type& query, Handler& handler) + winrt_resolve_op(const query_type& query, + Handler& handler, const IoExecutor& io_ex) : winrt_async_op< Windows::Foundation::Collections::IVectorView< Windows::Networking::EndpointPair^>^>( &winrt_resolve_op::do_complete), query_(query), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, const asio::error_code&, std::size_t) { // Take ownership of the operation object. + ASIO_ASSUME(base != 0); winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + results_type results = results_type(); if (!o->ec_) { @@ -106,6 +112,7 @@ public: private: query_type query_; Handler handler_; + handler_work<Handler, IoExecutor> executor_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/winrt_resolver_service.hpp b/3rdparty/asio/include/asio/detail/winrt_resolver_service.hpp index 8e38331c234..02dddf08226 100644 --- a/3rdparty/asio/include/asio/detail/winrt_resolver_service.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_resolver_service.hpp @@ -2,7 +2,7 @@ // detail/winrt_resolver_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -21,6 +21,7 @@ #include "asio/ip/basic_resolver_query.hpp" #include "asio/ip/basic_resolver_results.hpp" +#include "asio/post.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/socket_ops.hpp" @@ -28,6 +29,12 @@ #include "asio/detail/winrt_resolve_op.hpp" #include "asio/detail/winrt_utils.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + #include "asio/detail/push_options.hpp" namespace asio { @@ -35,7 +42,7 @@ namespace detail { template <typename Protocol> class winrt_resolver_service : - public service_base<winrt_resolver_service<Protocol> > + public execution_context_service_base<winrt_resolver_service<Protocol>> { public: // The implementation type of the resolver. A cancellation token is used to @@ -53,10 +60,11 @@ public: typedef asio::ip::basic_resolver_results<Protocol> results_type; // Constructor. - winrt_resolver_service(asio::io_context& io_context) - : service_base<winrt_resolver_service<Protocol> >(io_context), - io_context_(use_service<io_context_impl>(io_context)), - async_manager_(use_service<winrt_async_manager>(io_context)) + winrt_resolver_service(execution_context& context) + : execution_context_service_base< + winrt_resolver_service<Protocol>>(context), + scheduler_(use_service<scheduler_impl>(context)), + async_manager_(use_service<winrt_async_manager>(context)) { } @@ -71,7 +79,7 @@ public: } // Perform any fork-related housekeeping. - void notify_fork(asio::io_context::fork_event) + void notify_fork(execution_context::fork_event) { } @@ -130,20 +138,20 @@ public: } // Asynchronously resolve a query to a list of entries. - template <typename Handler> - void async_resolve(implementation_type& impl, - const query_type& query, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_resolve(implementation_type& impl, const query_type& query, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef winrt_resolve_op<Protocol, Handler> op; + typedef winrt_resolve_op<Protocol, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(query, handler); + p.p = new (p.v) op(query, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_.context(), + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "resolver", &impl, 0, "async_resolve")); (void)impl; @@ -159,7 +167,7 @@ public: { p.p->ec_ = asio::error_code( e->HResult, asio::system_category()); - io_context_.post_immediate_completion(p.p, is_continuation); + scheduler_.post_immediate_completion(p.p, is_continuation); p.v = p.p = 0; } } @@ -173,18 +181,24 @@ public: } // Asynchronously resolve an endpoint to a list of entries. - template <typename Handler> - void async_resolve(implementation_type&, - const endpoint_type&, Handler& handler) + template <typename Handler, typename IoExecutor> + void async_resolve(implementation_type&, const endpoint_type&, + Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const results_type results; - io_context_.get_io_context().post( - detail::bind_handler(handler, ec, results)); + asio::post(io_ex, detail::bind_handler(handler, ec, results)); } private: - io_context_impl& io_context_; + // The scheduler implementation used for delivering completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + winrt_async_manager& async_manager_; }; diff --git a/3rdparty/asio/include/asio/detail/winrt_socket_connect_op.hpp b/3rdparty/asio/include/asio/detail/winrt_socket_connect_op.hpp index 94b4048250d..008062e1b6e 100644 --- a/3rdparty/asio/include/asio/detail/winrt_socket_connect_op.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_socket_connect_op.hpp @@ -2,7 +2,7 @@ // detail/winrt_socket_connect_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/winrt_async_op.hpp" #include "asio/error.hpp" @@ -33,30 +33,35 @@ namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename IoExecutor> class winrt_socket_connect_op : public winrt_async_op<void> { public: ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op); - winrt_socket_connect_op(Handler& handler) + winrt_socket_connect_op(Handler& handler, const IoExecutor& io_ex) : winrt_async_op<void>(&winrt_socket_connect_op::do_complete), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, const asio::error_code&, std::size_t) { // Take ownership of the operation object. + ASIO_ASSUME(base != 0); winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -80,6 +85,7 @@ public: private: Handler handler_; + handler_work<Handler, IoExecutor> executor_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/winrt_socket_recv_op.hpp b/3rdparty/asio/include/asio/detail/winrt_socket_recv_op.hpp index d19f1f734f3..4b1d9f895f3 100644 --- a/3rdparty/asio/include/asio/detail/winrt_socket_recv_op.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_socket_recv_op.hpp @@ -2,7 +2,7 @@ // detail/winrt_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/winrt_async_op.hpp" #include "asio/error.hpp" @@ -33,32 +33,38 @@ namespace asio { namespace detail { -template <typename MutableBufferSequence, typename Handler> +template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class winrt_socket_recv_op : public winrt_async_op<Windows::Storage::Streams::IBuffer^> { public: ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op); - winrt_socket_recv_op(const MutableBufferSequence& buffers, Handler& handler) + winrt_socket_recv_op(const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) : winrt_async_op<Windows::Storage::Streams::IBuffer^>( &winrt_socket_recv_op::do_complete), buffers_(buffers), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, const asio::error_code&, std::size_t) { // Take ownership of the operation object. + ASIO_ASSUME(base != 0); winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -100,6 +106,7 @@ public: private: MutableBufferSequence buffers_; Handler handler_; + handler_work<Handler, IoExecutor> executor_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/winrt_socket_send_op.hpp b/3rdparty/asio/include/asio/detail/winrt_socket_send_op.hpp index 6d16ef3f5cd..eb21ef7e902 100644 --- a/3rdparty/asio/include/asio/detail/winrt_socket_send_op.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_socket_send_op.hpp @@ -2,7 +2,7 @@ // detail/winrt_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,7 +23,7 @@ #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_work.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/winrt_async_op.hpp" #include "asio/error.hpp" @@ -33,31 +33,37 @@ namespace asio { namespace detail { -template <typename ConstBufferSequence, typename Handler> +template <typename ConstBufferSequence, typename Handler, typename IoExecutor> class winrt_socket_send_op : public winrt_async_op<unsigned int> { public: ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op); - winrt_socket_send_op(const ConstBufferSequence& buffers, Handler& handler) + winrt_socket_send_op(const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) : winrt_async_op<unsigned int>(&winrt_socket_send_op::do_complete), buffers_(buffers), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) { - handler_work<Handler>::start(handler_); } static void do_complete(void* owner, operation* base, const asio::error_code&, std::size_t) { // Take ownership of the operation object. + ASIO_ASSUME(base != 0); winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base)); ptr p = { asio::detail::addressof(o->handler_), o, o }; - handler_work<Handler> w(o->handler_); ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work<Handler, IoExecutor> w( + static_cast<handler_work<Handler, IoExecutor>&&>( + o->work_)); + #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -91,6 +97,7 @@ public: private: ConstBufferSequence buffers_; Handler handler_; + handler_work<Handler, IoExecutor> executor_; }; } // namespace detail diff --git a/3rdparty/asio/include/asio/detail/winrt_ssocket_service.hpp b/3rdparty/asio/include/asio/detail/winrt_ssocket_service.hpp index 6f72bbec4d6..6b45ed4fb0c 100644 --- a/3rdparty/asio/include/asio/detail/winrt_ssocket_service.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_ssocket_service.hpp @@ -2,7 +2,7 @@ // detail/winrt_ssocket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,7 +20,7 @@ #if defined(ASIO_WINDOWS_RUNTIME) #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/winrt_socket_connect_op.hpp" #include "asio/detail/winrt_ssocket_service_base.hpp" @@ -33,7 +33,7 @@ namespace detail { template <typename Protocol> class winrt_ssocket_service : - public service_base<winrt_ssocket_service<Protocol> >, + public execution_context_service_base<winrt_ssocket_service<Protocol>>, public winrt_ssocket_service_base { public: @@ -61,9 +61,9 @@ public: }; // Constructor. - winrt_ssocket_service(asio::io_context& io_context) - : service_base<winrt_ssocket_service<Protocol> >(io_context), - winrt_ssocket_service_base(io_context) + winrt_ssocket_service(execution_context& context) + : execution_context_service_base<winrt_ssocket_service<Protocol>>(context), + winrt_ssocket_service_base(context) { } @@ -75,7 +75,7 @@ public: // Move-construct a new socket implementation. void move_construct(implementation_type& impl, - implementation_type& other_impl) + implementation_type& other_impl) noexcept { this->base_move_construct(impl, other_impl); @@ -97,6 +97,7 @@ public: // Move-construct a new socket implementation from another protocol type. template <typename Protocol1> void converting_move_construct(implementation_type& impl, + winrt_ssocket_service<Protocol1>&, typename winrt_ssocket_service< Protocol1>::implementation_type& other_impl) { @@ -177,6 +178,14 @@ public: return endpoint; } + // Disable sends or receives on the socket. + asio::error_code shutdown(implementation_type&, + socket_base::shutdown_type, asio::error_code& ec) + { + ec = asio::error::operation_not_supported; + return ec; + } + // Set a socket option. template <typename Option> asio::error_code set_option(implementation_type& impl, @@ -209,20 +218,21 @@ public: } // Start an asynchronous connect. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, Handler& handler) + const endpoint_type& peer_endpoint, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef winrt_socket_connect_op<Handler> op; + typedef winrt_socket_connect_op<Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_ex); - ASIO_HANDLER_CREATION((io_context_.context(), + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "socket", &impl, 0, "async_connect")); start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation); diff --git a/3rdparty/asio/include/asio/detail/winrt_ssocket_service_base.hpp b/3rdparty/asio/include/asio/detail/winrt_ssocket_service_base.hpp index 9192ffbc138..c752da80e2a 100644 --- a/3rdparty/asio/include/asio/detail/winrt_ssocket_service_base.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_ssocket_service_base.hpp @@ -2,7 +2,7 @@ // detail/winrt_ssocket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -21,7 +21,7 @@ #include "asio/buffer.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/socket_base.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/memory.hpp" @@ -30,6 +30,12 @@ #include "asio/detail/winrt_socket_recv_op.hpp" #include "asio/detail/winrt_socket_send_op.hpp" +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) + #include "asio/detail/push_options.hpp" namespace asio { @@ -61,8 +67,7 @@ public: }; // Constructor. - ASIO_DECL winrt_ssocket_service_base( - asio::io_context& io_context); + ASIO_DECL winrt_ssocket_service_base(execution_context& context); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void base_shutdown(); @@ -72,7 +77,7 @@ public: // Move-construct a new socket implementation. ASIO_DECL void base_move_construct(base_implementation_type& impl, - base_implementation_type& other_impl); + base_implementation_type& other_impl) noexcept; // Move-assign from another socket implementation. ASIO_DECL void base_move_assign(base_implementation_type& impl, @@ -92,6 +97,10 @@ public: ASIO_DECL asio::error_code close( base_implementation_type& impl, asio::error_code& ec); + // Release ownership of the socket. + ASIO_DECL native_handle_type release( + base_implementation_type& impl, asio::error_code& ec); + // Get the native socket representation. native_handle_type native_handle(base_implementation_type& impl) { @@ -159,14 +168,6 @@ public: return ec; } - // Disable sends or receives on the socket. - asio::error_code shutdown(base_implementation_type&, - socket_base::shutdown_type, asio::error_code& ec) - { - ec = asio::error::operation_not_supported; - return ec; - } - // Send the given data to the peer. template <typename ConstBufferSequence> std::size_t send(base_implementation_type& impl, @@ -188,21 +189,21 @@ public: // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template <typename ConstBufferSequence, typename Handler> + template <typename ConstBufferSequence, typename Handler, typename IoExecutor> void async_send(base_implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef winrt_socket_send_op<ConstBufferSequence, Handler> op; + typedef winrt_socket_send_op<ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(buffers, handler); + p.p = new (p.v) op(buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_.context(), + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "socket", &impl, 0, "async_send")); start_send_op(impl, @@ -213,13 +214,13 @@ public: } // Start an asynchronous wait until data can be sent without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_send(base_implementation_type&, const null_buffers&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.get_io_context().post( + asio::post(io_ex, detail::bind_handler(handler, ec, bytes_transferred)); } @@ -244,21 +245,22 @@ public: // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template <typename MutableBufferSequence, typename Handler> + template <typename MutableBufferSequence, + typename Handler, typename IoExecutor> void async_receive(base_implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler& handler) + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) { bool is_continuation = asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef winrt_socket_recv_op<MutableBufferSequence, Handler> op; + typedef winrt_socket_recv_op<MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(buffers, handler); + p.p = new (p.v) op(buffers, handler, io_ex); - ASIO_HANDLER_CREATION((io_context_.context(), + ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "socket", &impl, 0, "async_receive")); start_receive_op(impl, @@ -269,13 +271,13 @@ public: } // Wait until data can be received without blocking. - template <typename Handler> + template <typename Handler, typename IoExecutor> void async_receive(base_implementation_type&, const null_buffers&, - socket_base::message_flags, Handler& handler) + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) { asio::error_code ec = asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_context_.get_io_context().post( + asio::post(io_ex, detail::bind_handler(handler, ec, bytes_transferred)); } @@ -328,8 +330,13 @@ protected: winrt_async_op<Windows::Storage::Streams::IBuffer^>* op, bool is_continuation); - // The io_context implementation used for delivering completions. - io_context_impl& io_context_; + // The scheduler implementation used for delivering completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; // The manager that keeps track of outstanding operations. winrt_async_manager& async_manager_; diff --git a/3rdparty/asio/include/asio/detail/winrt_timer_scheduler.hpp b/3rdparty/asio/include/asio/detail/winrt_timer_scheduler.hpp index f3ffe6113e8..aadd581f75d 100644 --- a/3rdparty/asio/include/asio/detail/winrt_timer_scheduler.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_timer_scheduler.hpp @@ -2,7 +2,7 @@ // detail/winrt_timer_scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -28,7 +28,13 @@ #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_set.hpp" #include "asio/detail/wait_op.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/scheduler.hpp" +#endif // defined(ASIO_HAS_IOCP) #if defined(ASIO_HAS_IOCP) # include "asio/detail/thread.hpp" @@ -40,11 +46,11 @@ namespace asio { namespace detail { class winrt_timer_scheduler - : public asio::detail::service_base<winrt_timer_scheduler> + : public execution_context_service_base<winrt_timer_scheduler> { public: // Constructor. - ASIO_DECL winrt_timer_scheduler(asio::io_context& io_context); + ASIO_DECL winrt_timer_scheduler(execution_context& context); // Destructor. ASIO_DECL ~winrt_timer_scheduler(); @@ -53,8 +59,7 @@ public: ASIO_DECL void shutdown(); // Recreate internal descriptors following a fork. - ASIO_DECL void notify_fork( - asio::io_context::fork_event fork_ev); + ASIO_DECL void notify_fork(execution_context::fork_event fork_ev); // Initialise the task. No effect as this class uses its own thread. ASIO_DECL void init_task(); @@ -100,8 +105,13 @@ private: // Helper function to remove a timer queue. ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); - // The io_context implementation used to post completions. - io_context_impl& io_context_; + // The scheduler implementation used to post completions. +#if defined(ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; // Mutex used to protect internal variables. asio::detail::mutex mutex_; diff --git a/3rdparty/asio/include/asio/detail/winrt_utils.hpp b/3rdparty/asio/include/asio/detail/winrt_utils.hpp index 52f714300ac..f33786ccf8b 100644 --- a/3rdparty/asio/include/asio/detail/winrt_utils.hpp +++ b/3rdparty/asio/include/asio/detail/winrt_utils.hpp @@ -2,7 +2,7 @@ // detail/winrt_utils.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -82,7 +82,8 @@ inline Windows::Storage::Streams::IBuffer^ buffer_dup( const ConstBufferSequence& buffers) { using Microsoft::WRL::ComPtr; - std::size_t size = asio::buffer_size(buffers); + using asio::buffer_size; + std::size_t size = buffer_size(buffers); auto b = ref new Windows::Storage::Streams::Buffer(size); ComPtr<IInspectable> insp = reinterpret_cast<IInspectable*>(b); ComPtr<Windows::Storage::Streams::IBufferByteAccess> bacc; diff --git a/3rdparty/asio/include/asio/detail/winsock_init.hpp b/3rdparty/asio/include/asio/detail/winsock_init.hpp index b88cd518c98..7914560ab64 100644 --- a/3rdparty/asio/include/asio/detail/winsock_init.hpp +++ b/3rdparty/asio/include/asio/detail/winsock_init.hpp @@ -2,7 +2,7 @@ // detail/winsock_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -47,7 +47,7 @@ protected: ASIO_DECL static void throw_on_error(data& d); }; -template <int Major = 2, int Minor = 0> +template <int Major = 2, int Minor = 2> class winsock_init : private winsock_init_base { public: diff --git a/3rdparty/asio/include/asio/detail/work_dispatcher.hpp b/3rdparty/asio/include/asio/detail/work_dispatcher.hpp index 460fbd6c03e..2a473e45af6 100644 --- a/3rdparty/asio/include/asio/detail/work_dispatcher.hpp +++ b/3rdparty/asio/include/asio/detail/work_dispatcher.hpp @@ -2,7 +2,7 @@ // detail/work_dispatcher.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,26 +16,97 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/type_traits.hpp" #include "asio/associated_executor.hpp" #include "asio/associated_allocator.hpp" #include "asio/executor_work_guard.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/prefer.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { -template <typename Handler> +template <typename Handler, typename Executor, typename = void> +struct is_work_dispatcher_required : true_type +{ +}; + +template <typename Handler, typename Executor> +struct is_work_dispatcher_required<Handler, Executor, + enable_if_t< + is_same< + typename associated_executor<Handler, + Executor>::asio_associated_executor_is_unspecialised, + void + >::value + >> : false_type +{ +}; + +template <typename Handler, typename Executor, typename = void> class work_dispatcher { public: - work_dispatcher(Handler& handler) - : work_((get_associated_executor)(handler)), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + template <typename CompletionHandler> + work_dispatcher(CompletionHandler&& handler, + const Executor& handler_ex) + : handler_(static_cast<CompletionHandler&&>(handler)), + executor_(asio::prefer(handler_ex, + execution::outstanding_work.tracked)) + { + } + + work_dispatcher(const work_dispatcher& other) + : handler_(other.handler_), + executor_(other.executor_) + { + } + + work_dispatcher(work_dispatcher&& other) + : handler_(static_cast<Handler&&>(other.handler_)), + executor_(static_cast<work_executor_type&&>(other.executor_)) + { + } + + void operator()() + { + associated_allocator_t<Handler> alloc((get_associated_allocator)(handler_)); + asio::prefer(executor_, execution::allocator(alloc)).execute( + asio::detail::bind_handler( + static_cast<Handler&&>(handler_))); + } + +private: + typedef decay_t< + prefer_result_t<const Executor&, + execution::outstanding_work_t::tracked_t + > + > work_executor_type; + + Handler handler_; + work_executor_type executor_; +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Handler, typename Executor> +class work_dispatcher<Handler, Executor, + enable_if_t<!execution::is_executor<Executor>::value>> +{ +public: + template <typename CompletionHandler> + work_dispatcher(CompletionHandler&& handler, const Executor& handler_ex) + : work_(handler_ex), + handler_(static_cast<CompletionHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) work_dispatcher(const work_dispatcher& other) : work_(other.work_), handler_(other.handler_) @@ -43,27 +114,27 @@ public: } work_dispatcher(work_dispatcher&& other) - : work_(ASIO_MOVE_CAST(executor_work_guard< - typename associated_executor<Handler>::type>)(other.work_)), - handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + : work_(static_cast<executor_work_guard<Executor>&&>(other.work_)), + handler_(static_cast<Handler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()() { - typename associated_executor<Handler>::type ex(work_.get_executor()); - typename associated_allocator<Handler>::type alloc( - (get_associated_allocator)(handler_)); - ex.dispatch(ASIO_MOVE_CAST(Handler)(handler_), alloc); + associated_allocator_t<Handler> alloc((get_associated_allocator)(handler_)); + work_.get_executor().dispatch( + asio::detail::bind_handler( + static_cast<Handler&&>(handler_)), alloc); work_.reset(); } private: - executor_work_guard<typename associated_executor<Handler>::type> work_; + executor_work_guard<Executor> work_; Handler handler_; }; +#endif // !defined(ASIO_NO_TS_EXECUTORS) + } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/detail/wrapped_handler.hpp b/3rdparty/asio/include/asio/detail/wrapped_handler.hpp index aff903ed38f..fce9abfab43 100644 --- a/3rdparty/asio/include/asio/detail/wrapped_handler.hpp +++ b/3rdparty/asio/include/asio/detail/wrapped_handler.hpp @@ -2,7 +2,7 @@ // detail/wrapped_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/bind_handler.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/push_options.hpp" @@ -52,11 +50,10 @@ public: wrapped_handler(Dispatcher dispatcher, Handler& handler) : dispatcher_(dispatcher), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) wrapped_handler(const wrapped_handler& other) : dispatcher_(other.dispatcher_), handler_(other.handler_) @@ -65,14 +62,13 @@ public: wrapped_handler(wrapped_handler&& other) : dispatcher_(other.dispatcher_), - handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + handler_(static_cast<Handler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()() { - dispatcher_.dispatch(ASIO_MOVE_CAST(Handler)(handler_)); + dispatcher_.dispatch(static_cast<Handler&&>(handler_)); } void operator()() const @@ -161,7 +157,7 @@ class rewrapped_handler public: explicit rewrapped_handler(Handler& handler, const Context& context) : context_(context), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)) { } @@ -171,7 +167,6 @@ public: { } -#if defined(ASIO_HAS_MOVE) rewrapped_handler(const rewrapped_handler& other) : context_(other.context_), handler_(other.handler_) @@ -179,11 +174,10 @@ public: } rewrapped_handler(rewrapped_handler&& other) - : context_(ASIO_MOVE_CAST(Context)(other.context_)), - handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + : context_(static_cast<Context&&>(other.context_)), + handler_(static_cast<Handler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()() { @@ -201,64 +195,12 @@ public: }; template <typename Dispatcher, typename Handler, typename IsContinuation> -inline void* asio_handler_allocate(std::size_t size, - wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) -{ - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); -} - -template <typename Dispatcher, typename Handler, typename IsContinuation> -inline void asio_handler_deallocate(void* pointer, std::size_t size, - wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) -{ - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); -} - -template <typename Dispatcher, typename Handler, typename IsContinuation> inline bool asio_handler_is_continuation( wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) { return IsContinuation()(this_handler->dispatcher_, this_handler->handler_); } -template <typename Function, typename Dispatcher, - typename Handler, typename IsContinuation> -inline void asio_handler_invoke(Function& function, - wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) -{ - this_handler->dispatcher_.dispatch( - rewrapped_handler<Function, Handler>( - function, this_handler->handler_)); -} - -template <typename Function, typename Dispatcher, - typename Handler, typename IsContinuation> -inline void asio_handler_invoke(const Function& function, - wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) -{ - this_handler->dispatcher_.dispatch( - rewrapped_handler<Function, Handler>( - function, this_handler->handler_)); -} - -template <typename Handler, typename Context> -inline void* asio_handler_allocate(std::size_t size, - rewrapped_handler<Handler, Context>* this_handler) -{ - return asio_handler_alloc_helpers::allocate( - size, this_handler->context_); -} - -template <typename Handler, typename Context> -inline void asio_handler_deallocate(void* pointer, std::size_t size, - rewrapped_handler<Handler, Context>* this_handler) -{ - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->context_); -} - template <typename Dispatcher, typename Context> inline bool asio_handler_is_continuation( rewrapped_handler<Dispatcher, Context>* this_handler) @@ -267,22 +209,6 @@ inline bool asio_handler_is_continuation( this_handler->context_); } -template <typename Function, typename Handler, typename Context> -inline void asio_handler_invoke(Function& function, - rewrapped_handler<Handler, Context>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - function, this_handler->context_); -} - -template <typename Function, typename Handler, typename Context> -inline void asio_handler_invoke(const Function& function, - rewrapped_handler<Handler, Context>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - function, this_handler->context_); -} - } // namespace detail } // namespace asio diff --git a/3rdparty/asio/include/asio/dispatch.hpp b/3rdparty/asio/include/asio/dispatch.hpp index 2addadcb806..9eb60a4103d 100644 --- a/3rdparty/asio/include/asio/dispatch.hpp +++ b/3rdparty/asio/include/asio/dispatch.hpp @@ -2,7 +2,7 @@ // dispatch.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,8 +17,10 @@ #include "asio/detail/config.hpp" #include "asio/async_result.hpp" +#include "asio/detail/initiate_dispatch.hpp" #include "asio/detail/type_traits.hpp" #include "asio/execution_context.hpp" +#include "asio/execution/executor.hpp" #include "asio/is_executor.hpp" #include "asio/detail/push_options.hpp" @@ -28,81 +30,168 @@ namespace asio { /// Submits a completion token or function object for execution. /** * This function submits an object for execution using the object's associated - * executor. The function object is queued for execution, and is never called - * from the current thread prior to returning from <tt>dispatch()</tt>. + * executor. The function object may be called from the current thread prior to + * returning from <tt>dispatch()</tt>. Otherwise, it is queued for execution. * - * This function has the following effects: + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode * - * @li Constructs a function object handler of type @c Handler, initialized - * with <tt>handler(forward<CompletionToken>(token))</tt>. + * @returns This function returns <tt>async_initiate<NullaryToken, + * void()>(Init{}, token)</tt>, where @c Init is a function object type defined + * as: * - * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, - * initializing the object as <tt>result(handler)</tt>. + * @code class Init + * { + * public: + * template <typename CompletionHandler> + * void operator()(CompletionHandler&& completion_handler) const; + * }; @endcode * - * @li Obtains the handler's associated executor object @c ex by performing - * <tt>get_associated_executor(handler)</tt>. + * The function call operator of @c Init: + * + * @li Obtains the handler's associated executor object @c ex of type @c Ex by + * performing @code auto ex = get_associated_executor(handler); @endcode * * @li Obtains the handler's associated allocator object @c alloc by performing - * <tt>get_associated_allocator(handler)</tt>. + * @code auto alloc = get_associated_allocator(handler); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs + * @code prefer(ex, execution::allocator(alloc)).execute( + * std::forward<CompletionHandler>(completion_handler)); @endcode * - * @li Performs <tt>ex.dispatch(std::move(handler), alloc)</tt>. + * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs + * @code ex.dispatch( + * std::forward<CompletionHandler>(completion_handler), + * alloc); @endcode * - * @li Returns <tt>result.get()</tt>. + * @par Completion Signature + * @code void() @endcode */ -template <typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - ASIO_MOVE_ARG(CompletionToken) token); +template <ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken> +inline auto dispatch(NullaryToken&& token) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_dispatch>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_dispatch(), token); +} /// Submits a completion token or function object for execution. /** * This function submits an object for execution using the specified executor. - * The function object is queued for execution, and is never called from the - * current thread prior to returning from <tt>dispatch()</tt>. - * - * This function has the following effects: + * The function object may be called from the current thread prior to returning + * from <tt>dispatch()</tt>. Otherwise, it is queued for execution. * - * @li Constructs a function object handler of type @c Handler, initialized - * with <tt>handler(forward<CompletionToken>(token))</tt>. + * @param ex The target executor. * - * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, - * initializing the object as <tt>result(handler)</tt>. + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode * - * @li Obtains the handler's associated executor object @c ex1 by performing - * <tt>get_associated_executor(handler)</tt>. + * @returns This function returns <tt>async_initiate<NullaryToken, + * void()>(Init{ex}, token)</tt>, where @c Init is a function object type + * defined as: * - * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. - * - * @li Obtains the handler's associated allocator object @c alloc by performing - * <tt>get_associated_allocator(handler)</tt>. + * @code class Init + * { + * public: + * using executor_type = Executor; + * explicit Init(const Executor& ex) : ex_(ex) {} + * executor_type get_executor() const noexcept { return ex_; } + * template <typename CompletionHandler> + * void operator()(CompletionHandler&& completion_handler) const; + * private: + * Executor ex_; // exposition only + * }; @endcode * - * @li Constructs a function object @c f with a function call operator that - * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by - * <tt>w.reset()</tt>. + * The function call operator of @c Init: * - * @li Performs <tt>Executor(ex).dispatch(std::move(f), alloc)</tt>. + * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by + * performing @code auto ex1 = get_associated_executor(handler, ex); @endcode * - * @li Returns <tt>result.get()</tt>. + * @li Obtains the handler's associated allocator object @c alloc by performing + * @code auto alloc = get_associated_allocator(handler); @endcode + * + * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a + * function object @c f with a member @c executor_ that is initialised with + * <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c + * handler_ that is a decay-copy of @c completion_handler, and a function call + * operator that performs: + * @code auto a = get_associated_allocator(handler_); + * prefer(executor_, execution::allocator(a)).execute(std::move(handler_)); + * @endcode + * + * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a + * function object @c f with a member @c work_ that is initialised with + * <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of + * @c completion_handler, and a function call operator that performs: + * @code auto a = get_associated_allocator(handler_); + * work_.get_executor().dispatch(std::move(handler_), a); + * work_.reset(); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs + * @code prefer(ex, execution::allocator(alloc)).execute(std::move(f)); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs + * @code ex.dispatch(std::move(f), alloc); @endcode + * + * @par Completion Signature + * @code void() @endcode */ -template <typename Executor, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_executor<Executor>::value>::type* = 0); +template <typename Executor, + ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken + = default_completion_token_t<Executor>> +inline auto dispatch(const Executor& ex, + NullaryToken&& token = default_completion_token_t<Executor>(), + constraint_t< + execution::is_executor<Executor>::value || is_executor<Executor>::value + > = 0) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_dispatch_with_executor<Executor>>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_dispatch_with_executor<Executor>(ex), token); +} /// Submits a completion token or function object for execution. /** + * @param ctx An execution context, from which the target executor is obtained. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode + * * @returns <tt>dispatch(ctx.get_executor(), - * forward<CompletionToken>(token))</tt>. + * forward<NullaryToken>(token))</tt>. + * + * @par Completion Signature + * @code void() @endcode */ -template <typename ExecutionContext, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type* = 0); +template <typename ExecutionContext, + ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken + = default_completion_token_t<typename ExecutionContext::executor_type>> +inline auto dispatch(ExecutionContext& ctx, + NullaryToken&& token = default_completion_token_t< + typename ExecutionContext::executor_type>(), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_dispatch_with_executor< + typename ExecutionContext::executor_type>>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_dispatch_with_executor< + typename ExecutionContext::executor_type>( + ctx.get_executor()), token); +} } // namespace asio #include "asio/detail/pop_options.hpp" -#include "asio/impl/dispatch.hpp" - #endif // ASIO_DISPATCH_HPP diff --git a/3rdparty/asio/include/asio/error.hpp b/3rdparty/asio/include/asio/error.hpp index 5d5767a4e55..d676ee8aa7d 100644 --- a/3rdparty/asio/include/asio/error.hpp +++ b/3rdparty/asio/include/asio/error.hpp @@ -2,7 +2,7 @@ // error.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -223,6 +223,41 @@ enum misc_errors fd_set_failure }; +// boostify: non-boost code starts here +#if !defined(ASIO_ERROR_LOCATION) +# define ASIO_ERROR_LOCATION(e) (void)0 +#endif // !defined(ASIO_ERROR_LOCATION) + +// boostify: non-boost code ends here +#if !defined(ASIO_ERROR_LOCATION) \ + && !defined(ASIO_DISABLE_ERROR_LOCATION) \ + && defined(ASIO_HAS_BOOST_CONFIG) \ + && (BOOST_VERSION >= 107900) + +# define ASIO_ERROR_LOCATION(e) \ + do { \ + BOOST_STATIC_CONSTEXPR boost::source_location loc \ + = BOOST_CURRENT_LOCATION; \ + (e).assign((e), &loc); \ + } while (false) + +#else // !defined(ASIO_ERROR_LOCATION) + // && !defined(ASIO_DISABLE_ERROR_LOCATION) + // && defined(ASIO_HAS_BOOST_CONFIG) + // && (BOOST_VERSION >= 107900) + +# define ASIO_ERROR_LOCATION(e) (void)0 + +#endif // !defined(ASIO_ERROR_LOCATION) + // && !defined(ASIO_DISABLE_ERROR_LOCATION) + // && defined(ASIO_HAS_BOOST_CONFIG) + // && (BOOST_VERSION >= 107900) + +inline void clear(asio::error_code& ec) +{ + ec.assign(0, ec.category()); +} + inline const asio::error_category& get_system_category() { return asio::system_category(); @@ -253,19 +288,22 @@ inline const asio::error_category& get_addrinfo_category() extern ASIO_DECL const asio::error_category& get_misc_category(); -static const asio::error_category& system_category +static const asio::error_category& + system_category ASIO_UNUSED_VARIABLE = asio::error::get_system_category(); -static const asio::error_category& netdb_category +static const asio::error_category& + netdb_category ASIO_UNUSED_VARIABLE = asio::error::get_netdb_category(); -static const asio::error_category& addrinfo_category +static const asio::error_category& + addrinfo_category ASIO_UNUSED_VARIABLE = asio::error::get_addrinfo_category(); -static const asio::error_category& misc_category +static const asio::error_category& + misc_category ASIO_UNUSED_VARIABLE = asio::error::get_misc_category(); } // namespace error } // namespace asio -#if defined(ASIO_HAS_STD_SYSTEM_ERROR) namespace std { template<> struct is_error_code_enum<asio::error::basic_errors> @@ -289,7 +327,6 @@ template<> struct is_error_code_enum<asio::error::misc_errors> }; } // namespace std -#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) namespace asio { namespace error { @@ -332,7 +369,7 @@ namespace socket_errc { namespace resolver_errc { // Simulates the proposed resolver_errc scoped enum. using error::host_not_found; - using error::host_not_found_try_again; + const error::netdb_errors try_again = error::host_not_found_try_again; using error::service_not_found; } // namespace resolver_errc } // namespace asio diff --git a/3rdparty/asio/include/asio/error_code.hpp b/3rdparty/asio/include/asio/error_code.hpp index 09a2acb2f6b..5cb07f48c42 100644 --- a/3rdparty/asio/include/asio/error_code.hpp +++ b/3rdparty/asio/include/asio/error_code.hpp @@ -2,7 +2,7 @@ // error_code.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,167 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_SYSTEM_ERROR) -# include <system_error> -#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) -# include <string> -# include "asio/detail/noncopyable.hpp" -# if !defined(ASIO_NO_IOSTREAM) -# include <iosfwd> -# endif // !defined(ASIO_NO_IOSTREAM) -#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) +#include <system_error> #include "asio/detail/push_options.hpp" namespace asio { -#if defined(ASIO_HAS_STD_SYSTEM_ERROR) - typedef std::error_category error_category; - -#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) - -/// Base class for all error categories. -class error_category : private noncopyable -{ -public: - /// Destructor. - virtual ~error_category() - { - } - - /// Returns a string naming the error gategory. - virtual const char* name() const = 0; - - /// Returns a string describing the error denoted by @c value. - virtual std::string message(int value) const = 0; - - /// Equality operator to compare two error categories. - bool operator==(const error_category& rhs) const - { - return this == &rhs; - } - - /// Inequality operator to compare two error categories. - bool operator!=(const error_category& rhs) const - { - return !(*this == rhs); - } -}; - -#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) +typedef std::error_code error_code; /// Returns the error category used for the system errors produced by asio. extern ASIO_DECL const error_category& system_category(); -#if defined(ASIO_HAS_STD_SYSTEM_ERROR) - -typedef std::error_code error_code; - -#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) - -/// Class to represent an error code value. -class error_code -{ -public: - /// Default constructor. - error_code() - : value_(0), - category_(&system_category()) - { - } - - /// Construct with specific error code and category. - error_code(int v, const error_category& c) - : value_(v), - category_(&c) - { - } - - /// Construct from an error code enum. - template <typename ErrorEnum> - error_code(ErrorEnum e) - { - *this = make_error_code(e); - } - - /// Get the error value. - int value() const - { - return value_; - } - - /// Get the error category. - const error_category& category() const - { - return *category_; - } - - /// Get the message associated with the error. - std::string message() const - { - return category_->message(value_); - } - - struct unspecified_bool_type_t - { - }; - - typedef void (*unspecified_bool_type)(unspecified_bool_type_t); - - static void unspecified_bool_true(unspecified_bool_type_t) {} - - /// Operator returns non-null if there is a non-success error code. - operator unspecified_bool_type() const - { - if (value_ == 0) - return 0; - else - return &error_code::unspecified_bool_true; - } - - /// Operator to test if the error represents success. - bool operator!() const - { - return value_ == 0; - } - - /// Equality operator to compare two error objects. - friend bool operator==(const error_code& e1, const error_code& e2) - { - return e1.value_ == e2.value_ && e1.category_ == e2.category_; - } - - /// Inequality operator to compare two error objects. - friend bool operator!=(const error_code& e1, const error_code& e2) - { - return e1.value_ != e2.value_ || e1.category_ != e2.category_; - } - -private: - // The value associated with the error code. - int value_; - - // The category associated with the error code. - const error_category* category_; -}; - -# if !defined(ASIO_NO_IOSTREAM) - -/// Output an error code. -template <typename Elem, typename Traits> -std::basic_ostream<Elem, Traits>& operator<<( - std::basic_ostream<Elem, Traits>& os, const error_code& ec) -{ - os << ec.category().name() << ':' << ec.value(); - return os; -} - -# endif // !defined(ASIO_NO_IOSTREAM) - -#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) - } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/execution.hpp b/3rdparty/asio/include/asio/execution.hpp new file mode 100644 index 00000000000..fa773259fad --- /dev/null +++ b/3rdparty/asio/include/asio/execution.hpp @@ -0,0 +1,33 @@ +// +// execution.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_HPP +#define ASIO_EXECUTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/execution/allocator.hpp" +#include "asio/execution/any_executor.hpp" +#include "asio/execution/bad_executor.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/blocking_adaptation.hpp" +#include "asio/execution/context.hpp" +#include "asio/execution/context_as.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/invocable_archetype.hpp" +#include "asio/execution/mapping.hpp" +#include "asio/execution/occupancy.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/execution/prefer_only.hpp" +#include "asio/execution/relationship.hpp" + +#endif // ASIO_EXECUTION_HPP diff --git a/3rdparty/asio/include/asio/execution/allocator.hpp b/3rdparty/asio/include/asio/execution/allocator.hpp new file mode 100644 index 00000000000..cdb6a4a9203 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/allocator.hpp @@ -0,0 +1,278 @@ +// +// execution/allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_ALLOCATOR_HPP +#define ASIO_EXECUTION_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe which allocator an executor will use to allocate the +/// memory required to store a submitted function object. +template <typename ProtoAllocator> +struct allocator_t +{ + /// The allocator_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The allocator_t property can be required. + static constexpr bool is_requirable = true; + + /// The allocator_t property can be preferred. + static constexpr bool is_preferable = true; + + /// Default constructor. + constexpr allocator_t(); + + /// Obtain the allocator stored in the allocator_t property object. + /** + * Present only if @c ProtoAllocator is non-void. + */ + constexpr ProtoAllocator value() const; + + /// Create an allocator_t object with a different allocator. + /** + * Present only if @c ProtoAllocator is void. + */ + template <typename OtherAllocator> + allocator_t<OtherAllocator operator()(const OtherAllocator& a); +}; + +/// A special value used for accessing the allocator_t property. +constexpr allocator_t<void> allocator; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +template <typename ProtoAllocator> +struct allocator_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, allocator_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(allocator_t::static_query<E>())> + static constexpr const T static_query_v = allocator_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + constexpr ProtoAllocator value() const + { + return a_; + } + +private: + friend struct allocator_t<void>; + + explicit constexpr allocator_t(const ProtoAllocator& a) + : a_(a) + { + } + + ProtoAllocator a_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <typename ProtoAllocator> template <typename E, typename T> +const T allocator_t<ProtoAllocator>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <> +struct allocator_t<void> +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + + constexpr allocator_t() + { + } + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, allocator_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(allocator_t::static_query<E>())> + static constexpr const T static_query_v = allocator_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template <typename OtherProtoAllocator> + constexpr allocator_t<OtherProtoAllocator> operator()( + const OtherProtoAllocator& a) const + { + return allocator_t<OtherProtoAllocator>(a); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <typename E, typename T> +const T allocator_t<void>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +constexpr allocator_t<void> allocator; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename ProtoAllocator> +struct is_applicable_property<T, execution::allocator_t<ProtoAllocator>> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T, typename ProtoAllocator> +struct static_query<T, execution::allocator_t<ProtoAllocator>, + enable_if_t< + execution::allocator_t<ProtoAllocator>::template + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::allocator_t<ProtoAllocator>::template + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::allocator_t<ProtoAllocator>::template + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_ALLOCATOR_HPP diff --git a/3rdparty/asio/include/asio/execution/any_executor.hpp b/3rdparty/asio/include/asio/execution/any_executor.hpp new file mode 100644 index 00000000000..a057543b139 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/any_executor.hpp @@ -0,0 +1,1933 @@ +// +// execution/any_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_ANY_EXECUTOR_HPP +#define ASIO_EXECUTION_ANY_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <new> +#include <typeinfo> +#include "asio/detail/assert.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/cstddef.hpp" +#include "asio/detail/executor_function.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/throw_exception.hpp" +#include "asio/execution/bad_executor.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// Polymorphic executor wrapper. +template <typename... SupportableProperties> +class any_executor +{ +public: + /// Default constructor. + any_executor() noexcept; + + /// Construct in an empty state. Equivalent effects to default constructor. + any_executor(nullptr_t) noexcept; + + /// Copy constructor. + any_executor(const any_executor& e) noexcept; + + /// Move constructor. + any_executor(any_executor&& e) noexcept; + + /// Construct to point to the same target as another any_executor. + template <class... OtherSupportableProperties> + any_executor(any_executor<OtherSupportableProperties...> e); + + /// Construct to point to the same target as another any_executor. + template <class... OtherSupportableProperties> + any_executor(std::nothrow_t, + any_executor<OtherSupportableProperties...> e) noexcept; + + /// Construct to point to the same target as another any_executor. + any_executor(std::nothrow_t, const any_executor& e) noexcept; + + /// Construct to point to the same target as another any_executor. + any_executor(std::nothrow_t, any_executor&& e) noexcept; + + /// Construct a polymorphic wrapper for the specified executor. + template <typename Executor> + any_executor(Executor e); + + /// Construct a polymorphic wrapper for the specified executor. + template <typename Executor> + any_executor(std::nothrow_t, Executor e) noexcept; + + /// Assignment operator. + any_executor& operator=(const any_executor& e) noexcept; + + /// Move assignment operator. + any_executor& operator=(any_executor&& e) noexcept; + + /// Assignment operator that sets the polymorphic wrapper to the empty state. + any_executor& operator=(nullptr_t); + + /// Assignment operator to create a polymorphic wrapper for the specified + /// executor. + template <typename Executor> + any_executor& operator=(Executor e); + + /// Destructor. + ~any_executor(); + + /// Swap targets with another polymorphic wrapper. + void swap(any_executor& other) noexcept; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require and asio::prefer customisation points. + * + * For example: + * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...; + * auto ex2 = asio::requre(ex, execution::blocking.possibly); @endcode + */ + template <typename Property> + any_executor require(Property) const; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...; + * auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode + */ + template <typename Property> + any_executor prefer(Property) const; + + /// Obtain the value associated with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code execution::any_executor<execution::occupancy_t> ex = ...; + * size_t n = asio::query(ex, execution::occupancy); @endcode + */ + template <typename Property> + typename Property::polymorphic_query_result_type query(Property) const; + + /// Execute the function on the target executor. + /** + * Throws asio::bad_executor if the polymorphic wrapper has no target. + */ + template <typename Function> + void execute(Function&& f) const; + + /// Obtain the underlying execution context. + /** + * This function is provided for backward compatibility. It is automatically + * defined when the @c SupportableProperties... list includes a property of + * type <tt>execution::context_as<U></tt>, for some type <tt>U</tt>. + */ + automatically_determined context() const; + + /// Determine whether the wrapper has a target executor. + /** + * @returns @c true if the polymorphic wrapper has a target executor, + * otherwise false. + */ + explicit operator bool() const noexcept; + + /// Get the type of the target executor. + const type_info& target_type() const noexcept; + + /// Get a pointer to the target executor. + template <typename Executor> Executor* target() noexcept; + + /// Get a pointer to the target executor. + template <typename Executor> const Executor* target() const noexcept; +}; + +/// Equality operator. +/** + * @relates any_executor + */ +template <typename... SupportableProperties> +bool operator==(const any_executor<SupportableProperties...>& a, + const any_executor<SupportableProperties...>& b) noexcept; + +/// Equality operator. +/** + * @relates any_executor + */ +template <typename... SupportableProperties> +bool operator==(const any_executor<SupportableProperties...>& a, + nullptr_t) noexcept; + +/// Equality operator. +/** + * @relates any_executor + */ +template <typename... SupportableProperties> +bool operator==(nullptr_t, + const any_executor<SupportableProperties...>& b) noexcept; + +/// Inequality operator. +/** + * @relates any_executor + */ +template <typename... SupportableProperties> +bool operator!=(const any_executor<SupportableProperties...>& a, + const any_executor<SupportableProperties...>& b) noexcept; + +/// Inequality operator. +/** + * @relates any_executor + */ +template <typename... SupportableProperties> +bool operator!=(const any_executor<SupportableProperties...>& a, + nullptr_t) noexcept; + +/// Inequality operator. +/** + * @relates any_executor + */ +template <typename... SupportableProperties> +bool operator!=(nullptr_t, + const any_executor<SupportableProperties...>& b) noexcept; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +#if !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) +#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL + +template <typename... SupportableProperties> +class any_executor; + +#endif // !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) + +template <typename U> +struct context_as_t; + +namespace detail { + +// Traits used to detect whether a property is requirable or preferable, taking +// into account that T::is_requirable or T::is_preferable may not not be well +// formed. + +template <typename T, typename = void> +struct is_requirable : false_type {}; + +template <typename T> +struct is_requirable<T, enable_if_t<T::is_requirable>> : true_type {}; + +template <typename T, typename = void> +struct is_preferable : false_type {}; + +template <typename T> +struct is_preferable<T, enable_if_t<T::is_preferable>> : true_type {}; + +// Trait used to detect context_as property, for backward compatibility. + +template <typename T> +struct is_context_as : false_type {}; + +template <typename U> +struct is_context_as<context_as_t<U>> : true_type {}; + +// Helper template to: +// - Check if a target can supply the supportable properties. +// - Find the first convertible-from-T property in the list. + +template <std::size_t I, typename Props> +struct supportable_properties; + +template <std::size_t I, typename Prop> +struct supportable_properties<I, void(Prop)> +{ + template <typename T> + struct is_valid_target : integral_constant<bool, + ( + is_requirable<Prop>::value + ? can_require<T, Prop>::value + : true + ) + && + ( + is_preferable<Prop>::value + ? can_prefer<T, Prop>::value + : true + ) + && + ( + !is_requirable<Prop>::value && !is_preferable<Prop>::value + ? can_query<T, Prop>::value + : true + ) + > + { + }; + + struct found + { + static constexpr bool value = true; + typedef Prop type; + typedef typename Prop::polymorphic_query_result_type query_result_type; + static constexpr std::size_t index = I; + }; + + struct not_found + { + static constexpr bool value = false; + }; + + template <typename T> + struct find_convertible_property : + conditional_t< + is_same<T, Prop>::value || is_convertible<T, Prop>::value, + found, + not_found + > {}; + + template <typename T> + struct find_convertible_requirable_property : + conditional_t< + is_requirable<Prop>::value + && (is_same<T, Prop>::value || is_convertible<T, Prop>::value), + found, + not_found + > {}; + + template <typename T> + struct find_convertible_preferable_property : + conditional_t< + is_preferable<Prop>::value + && (is_same<T, Prop>::value || is_convertible<T, Prop>::value), + found, + not_found + > {}; + + struct find_context_as_property : + conditional_t< + is_context_as<Prop>::value, + found, + not_found + > {}; +}; + +template <std::size_t I, typename Head, typename... Tail> +struct supportable_properties<I, void(Head, Tail...)> +{ + template <typename T> + struct is_valid_target : integral_constant<bool, + ( + supportable_properties<I, + void(Head)>::template is_valid_target<T>::value + && + supportable_properties<I + 1, + void(Tail...)>::template is_valid_target<T>::value + ) + > + { + }; + + template <typename T> + struct find_convertible_property : + conditional_t< + is_convertible<T, Head>::value, + typename supportable_properties<I, void(Head)>::found, + typename supportable_properties<I + 1, + void(Tail...)>::template find_convertible_property<T> + > {}; + + template <typename T> + struct find_convertible_requirable_property : + conditional_t< + is_requirable<Head>::value + && is_convertible<T, Head>::value, + typename supportable_properties<I, void(Head)>::found, + typename supportable_properties<I + 1, + void(Tail...)>::template find_convertible_requirable_property<T> + > {}; + + template <typename T> + struct find_convertible_preferable_property : + conditional_t< + is_preferable<Head>::value + && is_convertible<T, Head>::value, + typename supportable_properties<I, void(Head)>::found, + typename supportable_properties<I + 1, + void(Tail...)>::template find_convertible_preferable_property<T> + > {}; + + struct find_context_as_property : + conditional_t< + is_context_as<Head>::value, + typename supportable_properties<I, void(Head)>::found, + typename supportable_properties<I + 1, + void(Tail...)>::find_context_as_property + > {}; +}; + +template <typename T, typename Props> +struct is_valid_target_executor : + conditional_t< + is_executor<T>::value, + typename supportable_properties<0, Props>::template is_valid_target<T>, + false_type + > +{ +}; + +template <typename Props> +struct is_valid_target_executor<int, Props> : false_type +{ +}; + +class shared_target_executor +{ +public: + template <typename E> + shared_target_executor(E&& e, decay_t<E>*& target) + { + impl<decay_t<E>>* i = + new impl<decay_t<E>>(static_cast<E&&>(e)); + target = &i->ex_; + impl_ = i; + } + + template <typename E> + shared_target_executor(std::nothrow_t, E&& e, decay_t<E>*& target) noexcept + { + impl<decay_t<E>>* i = + new (std::nothrow) impl<decay_t<E>>(static_cast<E&&>(e)); + target = i ? &i->ex_ : 0; + impl_ = i; + } + + shared_target_executor(const shared_target_executor& other) noexcept + : impl_(other.impl_) + { + if (impl_) + asio::detail::ref_count_up(impl_->ref_count_); + } + + shared_target_executor(shared_target_executor&& other) noexcept + : impl_(other.impl_) + { + other.impl_ = 0; + } + + ~shared_target_executor() + { + if (impl_) + if (asio::detail::ref_count_down(impl_->ref_count_)) + delete impl_; + } + + void* get() const noexcept + { + return impl_ ? impl_->get() : 0; + } + +private: + shared_target_executor& operator=( + const shared_target_executor& other) = delete; + + shared_target_executor& operator=( + shared_target_executor&& other) = delete; + + struct impl_base + { + impl_base() : ref_count_(1) {} + virtual ~impl_base() {} + virtual void* get() = 0; + asio::detail::atomic_count ref_count_; + }; + + template <typename Executor> + struct impl : impl_base + { + impl(Executor ex) : ex_(static_cast<Executor&&>(ex)) {} + virtual void* get() { return &ex_; } + Executor ex_; + }; + + impl_base* impl_; +}; + +class any_executor_base +{ +public: + any_executor_base() noexcept + : object_fns_(0), + target_(0), + target_fns_(0) + { + } + + template <ASIO_EXECUTION_EXECUTOR Executor> + any_executor_base(Executor ex, false_type) + : target_fns_(target_fns_table<Executor>( + any_executor_base::query_blocking(ex, + can_query<const Executor&, const execution::blocking_t&>()) + == execution::blocking.always)) + { + any_executor_base::construct_object(ex, + integral_constant<bool, + sizeof(Executor) <= sizeof(object_type) + && alignment_of<Executor>::value <= alignment_of<object_type>::value + >()); + } + + template <ASIO_EXECUTION_EXECUTOR Executor> + any_executor_base(std::nothrow_t, Executor ex, false_type) noexcept + : target_fns_(target_fns_table<Executor>( + any_executor_base::query_blocking(ex, + can_query<const Executor&, const execution::blocking_t&>()) + == execution::blocking.always)) + { + any_executor_base::construct_object(std::nothrow, ex, + integral_constant<bool, + sizeof(Executor) <= sizeof(object_type) + && alignment_of<Executor>::value <= alignment_of<object_type>::value + >()); + if (target_ == 0) + { + object_fns_ = 0; + target_fns_ = 0; + } + } + + template <ASIO_EXECUTION_EXECUTOR Executor> + any_executor_base(Executor other, true_type) + : object_fns_(object_fns_table<shared_target_executor>()), + target_fns_(other.target_fns_) + { + Executor* p = 0; + new (&object_) shared_target_executor( + static_cast<Executor&&>(other), p); + target_ = p->template target<void>(); + } + + template <ASIO_EXECUTION_EXECUTOR Executor> + any_executor_base(std::nothrow_t, + Executor other, true_type) noexcept + : object_fns_(object_fns_table<shared_target_executor>()), + target_fns_(other.target_fns_) + { + Executor* p = 0; + new (&object_) shared_target_executor( + std::nothrow, static_cast<Executor&&>(other), p); + if (p) + target_ = p->template target<void>(); + else + { + target_ = 0; + object_fns_ = 0; + target_fns_ = 0; + } + } + + any_executor_base(const any_executor_base& other) noexcept + { + if (!!other) + { + object_fns_ = other.object_fns_; + target_fns_ = other.target_fns_; + object_fns_->copy(*this, other); + } + else + { + object_fns_ = 0; + target_ = 0; + target_fns_ = 0; + } + } + + ~any_executor_base() noexcept + { + if (!!*this) + object_fns_->destroy(*this); + } + + any_executor_base& operator=( + const any_executor_base& other) noexcept + { + if (this != &other) + { + if (!!*this) + object_fns_->destroy(*this); + if (!!other) + { + object_fns_ = other.object_fns_; + target_fns_ = other.target_fns_; + object_fns_->copy(*this, other); + } + else + { + object_fns_ = 0; + target_ = 0; + target_fns_ = 0; + } + } + return *this; + } + + any_executor_base& operator=(nullptr_t) noexcept + { + if (target_) + object_fns_->destroy(*this); + target_ = 0; + object_fns_ = 0; + target_fns_ = 0; + return *this; + } + + any_executor_base(any_executor_base&& other) noexcept + { + if (other.target_) + { + object_fns_ = other.object_fns_; + target_fns_ = other.target_fns_; + other.object_fns_ = 0; + other.target_fns_ = 0; + object_fns_->move(*this, other); + other.target_ = 0; + } + else + { + object_fns_ = 0; + target_ = 0; + target_fns_ = 0; + } + } + + any_executor_base& operator=( + any_executor_base&& other) noexcept + { + if (this != &other) + { + if (!!*this) + object_fns_->destroy(*this); + if (!!other) + { + object_fns_ = other.object_fns_; + target_fns_ = other.target_fns_; + other.object_fns_ = 0; + other.target_fns_ = 0; + object_fns_->move(*this, other); + other.target_ = 0; + } + else + { + object_fns_ = 0; + target_ = 0; + target_fns_ = 0; + } + } + return *this; + } + + void swap(any_executor_base& other) noexcept + { + if (this != &other) + { + any_executor_base tmp(static_cast<any_executor_base&&>(other)); + other = static_cast<any_executor_base&&>(*this); + *this = static_cast<any_executor_base&&>(tmp); + } + } + + template <typename F> + void execute(F&& f) const + { + if (target_) + { + if (target_fns_->blocking_execute != 0) + { + asio::detail::non_const_lvalue<F> f2(f); + target_fns_->blocking_execute(*this, function_view(f2.value)); + } + else + { + target_fns_->execute(*this, + function(static_cast<F&&>(f), std::allocator<void>())); + } + } + else + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + } + + template <typename Executor> + Executor* target() + { + return target_ && (is_same<Executor, void>::value + || target_fns_->target_type() == target_type_ex<Executor>()) + ? static_cast<Executor*>(target_) : 0; + } + + template <typename Executor> + const Executor* target() const + { + return target_ && (is_same<Executor, void>::value + || target_fns_->target_type() == target_type_ex<Executor>()) + ? static_cast<const Executor*>(target_) : 0; + } + +#if !defined(ASIO_NO_TYPEID) + const std::type_info& target_type() const + { + return target_ ? target_fns_->target_type() : typeid(void); + } +#else // !defined(ASIO_NO_TYPEID) + const void* target_type() const + { + return target_ ? target_fns_->target_type() : 0; + } +#endif // !defined(ASIO_NO_TYPEID) + + struct unspecified_bool_type_t {}; + typedef void (*unspecified_bool_type)(unspecified_bool_type_t); + static void unspecified_bool_true(unspecified_bool_type_t) {} + + operator unspecified_bool_type() const noexcept + { + return target_ ? &any_executor_base::unspecified_bool_true : 0; + } + + bool operator!() const noexcept + { + return target_ == 0; + } + +protected: + bool equality_helper(const any_executor_base& other) const noexcept + { + if (target_ == other.target_) + return true; + if (target_ && !other.target_) + return false; + if (!target_ && other.target_) + return false; + if (target_fns_ != other.target_fns_) + return false; + return target_fns_->equal(*this, other); + } + + template <typename Ex> + Ex& object() + { + return *static_cast<Ex*>(static_cast<void*>(&object_)); + } + + template <typename Ex> + const Ex& object() const + { + return *static_cast<const Ex*>(static_cast<const void*>(&object_)); + } + + struct object_fns + { + void (*destroy)(any_executor_base&); + void (*copy)(any_executor_base&, const any_executor_base&); + void (*move)(any_executor_base&, any_executor_base&); + const void* (*target)(const any_executor_base&); + }; + + static void destroy_shared(any_executor_base& ex) + { + typedef shared_target_executor type; + ex.object<type>().~type(); + } + + static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2) + { + typedef shared_target_executor type; + new (&ex1.object_) type(ex2.object<type>()); + ex1.target_ = ex2.target_; + } + + static void move_shared(any_executor_base& ex1, any_executor_base& ex2) + { + typedef shared_target_executor type; + new (&ex1.object_) type(static_cast<type&&>(ex2.object<type>())); + ex1.target_ = ex2.target_; + ex2.object<type>().~type(); + } + + static const void* target_shared(const any_executor_base& ex) + { + typedef shared_target_executor type; + return ex.object<type>().get(); + } + + template <typename Obj> + static const object_fns* object_fns_table( + enable_if_t< + is_same<Obj, shared_target_executor>::value + >* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_shared, + &any_executor_base::copy_shared, + &any_executor_base::move_shared, + &any_executor_base::target_shared + }; + return &fns; + } + + template <typename Obj> + static void destroy_object(any_executor_base& ex) + { + ex.object<Obj>().~Obj(); + } + + template <typename Obj> + static void copy_object(any_executor_base& ex1, const any_executor_base& ex2) + { + new (&ex1.object_) Obj(ex2.object<Obj>()); + ex1.target_ = &ex1.object<Obj>(); + } + + template <typename Obj> + static void move_object(any_executor_base& ex1, any_executor_base& ex2) + { + new (&ex1.object_) Obj(static_cast<Obj&&>(ex2.object<Obj>())); + ex1.target_ = &ex1.object<Obj>(); + ex2.object<Obj>().~Obj(); + } + + template <typename Obj> + static const void* target_object(const any_executor_base& ex) + { + return &ex.object<Obj>(); + } + + template <typename Obj> + static const object_fns* object_fns_table( + enable_if_t< + !is_same<Obj, void>::value + && !is_same<Obj, shared_target_executor>::value + >* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_object<Obj>, + &any_executor_base::copy_object<Obj>, + &any_executor_base::move_object<Obj>, + &any_executor_base::target_object<Obj> + }; + return &fns; + } + + typedef asio::detail::executor_function function; + typedef asio::detail::executor_function_view function_view; + + struct target_fns + { +#if !defined(ASIO_NO_TYPEID) + const std::type_info& (*target_type)(); +#else // !defined(ASIO_NO_TYPEID) + const void* (*target_type)(); +#endif // !defined(ASIO_NO_TYPEID) + bool (*equal)(const any_executor_base&, const any_executor_base&); + void (*execute)(const any_executor_base&, function&&); + void (*blocking_execute)(const any_executor_base&, function_view); + }; + +#if !defined(ASIO_NO_TYPEID) + template <typename Ex> + static const std::type_info& target_type_ex() + { + return typeid(Ex); + } +#else // !defined(ASIO_NO_TYPEID) + template <typename Ex> + static const void* target_type_ex() + { + static int unique_id; + return &unique_id; + } +#endif // !defined(ASIO_NO_TYPEID) + + template <typename Ex> + static bool equal_ex(const any_executor_base& ex1, + const any_executor_base& ex2) + { + const Ex* p1 = ex1.target<Ex>(); + const Ex* p2 = ex2.target<Ex>(); + ASIO_ASSUME(p1 != 0 && p2 != 0); + return *p1 == *p2; + } + + template <typename Ex> + static void execute_ex(const any_executor_base& ex, function&& f) + { + const Ex* p = ex.target<Ex>(); + ASIO_ASSUME(p != 0); + p->execute(static_cast<function&&>(f)); + } + + template <typename Ex> + static void blocking_execute_ex(const any_executor_base& ex, function_view f) + { + const Ex* p = ex.target<Ex>(); + ASIO_ASSUME(p != 0); + p->execute(f); + } + + template <typename Ex> + static const target_fns* target_fns_table(bool is_always_blocking, + enable_if_t< + !is_same<Ex, void>::value + >* = 0) + { + static const target_fns fns_with_execute = + { + &any_executor_base::target_type_ex<Ex>, + &any_executor_base::equal_ex<Ex>, + &any_executor_base::execute_ex<Ex>, + 0 + }; + + static const target_fns fns_with_blocking_execute = + { + &any_executor_base::target_type_ex<Ex>, + &any_executor_base::equal_ex<Ex>, + 0, + &any_executor_base::blocking_execute_ex<Ex> + }; + + return is_always_blocking ? &fns_with_blocking_execute : &fns_with_execute; + } + +#if defined(ASIO_MSVC) +# pragma warning (push) +# pragma warning (disable:4702) +#endif // defined(ASIO_MSVC) + + static void query_fn_void(void*, const void*, const void*) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void*, const void* ex, const void* prop, + enable_if_t< + asio::can_query<const Ex&, const Prop&>::value + && is_same<typename Prop::polymorphic_query_result_type, void>::value + >*) + { + asio::query(*static_cast<const Ex*>(ex), + *static_cast<const Prop*>(prop)); + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void*, const void*, const void*, + enable_if_t< + !asio::can_query<const Ex&, const Prop&>::value + && is_same<typename Prop::polymorphic_query_result_type, void>::value + >*) + { + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void* result, const void* ex, const void* prop, + enable_if_t< + asio::can_query<const Ex&, const Prop&>::value + && !is_same<typename Prop::polymorphic_query_result_type, void>::value + && is_reference<typename Prop::polymorphic_query_result_type>::value + >*) + { + *static_cast<remove_reference_t< + typename Prop::polymorphic_query_result_type>**>(result) + = &static_cast<typename Prop::polymorphic_query_result_type>( + asio::query(*static_cast<const Ex*>(ex), + *static_cast<const Prop*>(prop))); + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void*, const void*, const void*, + enable_if_t< + !asio::can_query<const Ex&, const Prop&>::value + && !is_same<typename Prop::polymorphic_query_result_type, void>::value + && is_reference<typename Prop::polymorphic_query_result_type>::value + >*) + { + std::terminate(); // Combination should not be possible. + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void* result, const void* ex, const void* prop, + enable_if_t< + asio::can_query<const Ex&, const Prop&>::value + && !is_same<typename Prop::polymorphic_query_result_type, void>::value + && is_scalar<typename Prop::polymorphic_query_result_type>::value + >*) + { + *static_cast<typename Prop::polymorphic_query_result_type*>(result) + = static_cast<typename Prop::polymorphic_query_result_type>( + asio::query(*static_cast<const Ex*>(ex), + *static_cast<const Prop*>(prop))); + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void* result, const void*, const void*, + enable_if_t< + !asio::can_query<const Ex&, const Prop&>::value + && !is_same<typename Prop::polymorphic_query_result_type, void>::value + && is_scalar<typename Prop::polymorphic_query_result_type>::value + >*) + { + *static_cast<typename Prop::polymorphic_query_result_type*>(result) + = typename Prop::polymorphic_query_result_type(); + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void* result, const void* ex, const void* prop, + enable_if_t< + asio::can_query<const Ex&, const Prop&>::value + && !is_same<typename Prop::polymorphic_query_result_type, void>::value + && !is_reference<typename Prop::polymorphic_query_result_type>::value + && !is_scalar<typename Prop::polymorphic_query_result_type>::value + >*) + { + *static_cast<typename Prop::polymorphic_query_result_type**>(result) + = new typename Prop::polymorphic_query_result_type( + asio::query(*static_cast<const Ex*>(ex), + *static_cast<const Prop*>(prop))); + } + + template <typename Ex, class Prop> + static void query_fn_non_void(void* result, const void*, const void*, ...) + { + *static_cast<typename Prop::polymorphic_query_result_type**>(result) + = new typename Prop::polymorphic_query_result_type(); + } + + template <typename Ex, class Prop> + static void query_fn_impl(void* result, const void* ex, const void* prop, + enable_if_t< + is_same<Ex, void>::value + >*) + { + query_fn_void(result, ex, prop); + } + + template <typename Ex, class Prop> + static void query_fn_impl(void* result, const void* ex, const void* prop, + enable_if_t< + !is_same<Ex, void>::value + >*) + { + query_fn_non_void<Ex, Prop>(result, ex, prop, 0); + } + + template <typename Ex, class Prop> + static void query_fn(void* result, const void* ex, const void* prop) + { + query_fn_impl<Ex, Prop>(result, ex, prop, 0); + } + + template <typename Poly, typename Ex, class Prop> + static Poly require_fn_impl(const void*, const void*, + enable_if_t< + is_same<Ex, void>::value + >*) + { + bad_executor ex; + asio::detail::throw_exception(ex); + return Poly(); + } + + template <typename Poly, typename Ex, class Prop> + static Poly require_fn_impl(const void* ex, const void* prop, + enable_if_t< + !is_same<Ex, void>::value && Prop::is_requirable + >*) + { + return asio::require(*static_cast<const Ex*>(ex), + *static_cast<const Prop*>(prop)); + } + + template <typename Poly, typename Ex, class Prop> + static Poly require_fn_impl(const void*, const void*, ...) + { + return Poly(); + } + + template <typename Poly, typename Ex, class Prop> + static Poly require_fn(const void* ex, const void* prop) + { + return require_fn_impl<Poly, Ex, Prop>(ex, prop, 0); + } + + template <typename Poly, typename Ex, class Prop> + static Poly prefer_fn_impl(const void*, const void*, + enable_if_t< + is_same<Ex, void>::value + >*) + { + bad_executor ex; + asio::detail::throw_exception(ex); + return Poly(); + } + + template <typename Poly, typename Ex, class Prop> + static Poly prefer_fn_impl(const void* ex, const void* prop, + enable_if_t< + !is_same<Ex, void>::value && Prop::is_preferable + >*) + { + return asio::prefer(*static_cast<const Ex*>(ex), + *static_cast<const Prop*>(prop)); + } + + template <typename Poly, typename Ex, class Prop> + static Poly prefer_fn_impl(const void*, const void*, ...) + { + return Poly(); + } + + template <typename Poly, typename Ex, class Prop> + static Poly prefer_fn(const void* ex, const void* prop) + { + return prefer_fn_impl<Poly, Ex, Prop>(ex, prop, 0); + } + + template <typename Poly> + struct prop_fns + { + void (*query)(void*, const void*, const void*); + Poly (*require)(const void*, const void*); + Poly (*prefer)(const void*, const void*); + }; + +#if defined(ASIO_MSVC) +# pragma warning (pop) +#endif // defined(ASIO_MSVC) + +private: + template <typename Executor> + static execution::blocking_t query_blocking(const Executor& ex, true_type) + { + return asio::query(ex, execution::blocking); + } + + template <typename Executor> + static execution::blocking_t query_blocking(const Executor&, false_type) + { + return execution::blocking_t(); + } + + template <typename Executor> + void construct_object(Executor& ex, true_type) + { + object_fns_ = object_fns_table<Executor>(); + target_ = new (&object_) Executor(static_cast<Executor&&>(ex)); + } + + template <typename Executor> + void construct_object(Executor& ex, false_type) + { + object_fns_ = object_fns_table<shared_target_executor>(); + Executor* p = 0; + new (&object_) shared_target_executor( + static_cast<Executor&&>(ex), p); + target_ = p; + } + + template <typename Executor> + void construct_object(std::nothrow_t, + Executor& ex, true_type) noexcept + { + object_fns_ = object_fns_table<Executor>(); + target_ = new (&object_) Executor(static_cast<Executor&&>(ex)); + } + + template <typename Executor> + void construct_object(std::nothrow_t, + Executor& ex, false_type) noexcept + { + object_fns_ = object_fns_table<shared_target_executor>(); + Executor* p = 0; + new (&object_) shared_target_executor( + std::nothrow, static_cast<Executor&&>(ex), p); + target_ = p; + } + +/*private:*/public: +// template <typename...> friend class any_executor; + + typedef aligned_storage< + sizeof(asio::detail::shared_ptr<void>) + sizeof(void*), + alignment_of<asio::detail::shared_ptr<void>>::value + >::type object_type; + + object_type object_; + const object_fns* object_fns_; + void* target_; + const target_fns* target_fns_; +}; + +template <typename Derived, typename Property, typename = void> +struct any_executor_context +{ +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Derived, typename Property> +struct any_executor_context<Derived, Property, enable_if_t<Property::value>> +{ + typename Property::query_result_type context() const + { + return static_cast<const Derived*>(this)->query(typename Property::type()); + } +}; + +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +} // namespace detail + +template <> +class any_executor<> : public detail::any_executor_base +{ +public: + any_executor() noexcept + : detail::any_executor_base() + { + } + + any_executor(nullptr_t) noexcept + : detail::any_executor_base() + { + } + + template <typename Executor> + any_executor(Executor ex, + enable_if_t< + conditional_t< + !is_same<Executor, any_executor>::value + && !is_base_of<detail::any_executor_base, Executor>::value, + is_executor<Executor>, + false_type + >::value + >* = 0) + : detail::any_executor_base( + static_cast<Executor&&>(ex), false_type()) + { + } + + template <typename Executor> + any_executor(std::nothrow_t, Executor ex, + enable_if_t< + conditional_t< + !is_same<Executor, any_executor>::value + && !is_base_of<detail::any_executor_base, Executor>::value, + is_executor<Executor>, + false_type + >::value + >* = 0) noexcept + : detail::any_executor_base(std::nothrow, + static_cast<Executor&&>(ex), false_type()) + { + } + + template <typename... OtherSupportableProperties> + any_executor(any_executor<OtherSupportableProperties...> other) + : detail::any_executor_base( + static_cast<const detail::any_executor_base&>(other)) + { + } + + template <typename... OtherSupportableProperties> + any_executor(std::nothrow_t, + any_executor<OtherSupportableProperties...> other) noexcept + : detail::any_executor_base( + static_cast<const detail::any_executor_base&>(other)) + { + } + + any_executor(const any_executor& other) noexcept + : detail::any_executor_base( + static_cast<const detail::any_executor_base&>(other)) + { + } + + any_executor(std::nothrow_t, const any_executor& other) noexcept + : detail::any_executor_base( + static_cast<const detail::any_executor_base&>(other)) + { + } + + any_executor& operator=(const any_executor& other) noexcept + { + if (this != &other) + { + detail::any_executor_base::operator=( + static_cast<const detail::any_executor_base&>(other)); + } + return *this; + } + + any_executor& operator=(nullptr_t p) noexcept + { + detail::any_executor_base::operator=(p); + return *this; + } + + any_executor(any_executor&& other) noexcept + : detail::any_executor_base( + static_cast<any_executor_base&&>( + static_cast<any_executor_base&>(other))) + { + } + + any_executor(std::nothrow_t, any_executor&& other) noexcept + : detail::any_executor_base( + static_cast<any_executor_base&&>( + static_cast<any_executor_base&>(other))) + { + } + + any_executor& operator=(any_executor&& other) noexcept + { + if (this != &other) + { + detail::any_executor_base::operator=( + static_cast<detail::any_executor_base&&>( + static_cast<detail::any_executor_base&>(other))); + } + return *this; + } + + void swap(any_executor& other) noexcept + { + detail::any_executor_base::swap( + static_cast<detail::any_executor_base&>(other)); + } + + using detail::any_executor_base::execute; + using detail::any_executor_base::target; + using detail::any_executor_base::target_type; + using detail::any_executor_base::operator unspecified_bool_type; + using detail::any_executor_base::operator!; + + bool equality_helper(const any_executor& other) const noexcept + { + return any_executor_base::equality_helper(other); + } + + template <typename AnyExecutor1, typename AnyExecutor2> + friend enable_if_t< + is_base_of<any_executor, AnyExecutor1>::value + || is_base_of<any_executor, AnyExecutor2>::value, + bool + > operator==(const AnyExecutor1& a, + const AnyExecutor2& b) noexcept + { + return static_cast<const any_executor&>(a).equality_helper(b); + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator==(const AnyExecutor& a, nullptr_t) noexcept + { + return !a; + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator==(nullptr_t, const AnyExecutor& b) noexcept + { + return !b; + } + + template <typename AnyExecutor1, typename AnyExecutor2> + friend enable_if_t< + is_base_of<any_executor, AnyExecutor1>::value + || is_base_of<any_executor, AnyExecutor2>::value, + bool + > operator!=(const AnyExecutor1& a, + const AnyExecutor2& b) noexcept + { + return !static_cast<const any_executor&>(a).equality_helper(b); + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator!=(const AnyExecutor& a, nullptr_t) noexcept + { + return !!a; + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator!=(nullptr_t, const AnyExecutor& b) noexcept + { + return !!b; + } +}; + +inline void swap(any_executor<>& a, any_executor<>& b) noexcept +{ + return a.swap(b); +} + +template <typename... SupportableProperties> +class any_executor : + public detail::any_executor_base, + public detail::any_executor_context< + any_executor<SupportableProperties...>, + typename detail::supportable_properties< + 0, void(SupportableProperties...)>::find_context_as_property> +{ +public: + any_executor() noexcept + : detail::any_executor_base(), + prop_fns_(prop_fns_table<void>()) + { + } + + any_executor(nullptr_t) noexcept + : detail::any_executor_base(), + prop_fns_(prop_fns_table<void>()) + { + } + + template <typename Executor> + any_executor(Executor ex, + enable_if_t< + conditional_t< + !is_same<Executor, any_executor>::value + && !is_base_of<detail::any_executor_base, Executor>::value, + detail::is_valid_target_executor< + Executor, void(SupportableProperties...)>, + false_type + >::value + >* = 0) + : detail::any_executor_base( + static_cast<Executor&&>(ex), false_type()), + prop_fns_(prop_fns_table<Executor>()) + { + } + + template <typename Executor> + any_executor(std::nothrow_t, Executor ex, + enable_if_t< + conditional_t< + !is_same<Executor, any_executor>::value + && !is_base_of<detail::any_executor_base, Executor>::value, + detail::is_valid_target_executor< + Executor, void(SupportableProperties...)>, + false_type + >::value + >* = 0) noexcept + : detail::any_executor_base(std::nothrow, + static_cast<Executor&&>(ex), false_type()), + prop_fns_(prop_fns_table<Executor>()) + { + if (this->template target<void>() == 0) + prop_fns_ = prop_fns_table<void>(); + } + + template <typename... OtherSupportableProperties> + any_executor(any_executor<OtherSupportableProperties...> other, + enable_if_t< + conditional_t< + !is_same< + any_executor<OtherSupportableProperties...>, + any_executor + >::value, + typename detail::supportable_properties< + 0, void(SupportableProperties...)>::template is_valid_target< + any_executor<OtherSupportableProperties...>>, + false_type + >::value + >* = 0) + : detail::any_executor_base( + static_cast<any_executor<OtherSupportableProperties...>&&>(other), + true_type()), + prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...>>()) + { + } + + template <typename... OtherSupportableProperties> + any_executor(std::nothrow_t, + any_executor<OtherSupportableProperties...> other, + enable_if_t< + conditional_t< + !is_same< + any_executor<OtherSupportableProperties...>, + any_executor + >::value, + typename detail::supportable_properties< + 0, void(SupportableProperties...)>::template is_valid_target< + any_executor<OtherSupportableProperties...>>, + false_type + >::value + >* = 0) noexcept + : detail::any_executor_base(std::nothrow, + static_cast<any_executor<OtherSupportableProperties...>&&>(other), + true_type()), + prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...>>()) + { + if (this->template target<void>() == 0) + prop_fns_ = prop_fns_table<void>(); + } + + any_executor(const any_executor& other) noexcept + : detail::any_executor_base( + static_cast<const detail::any_executor_base&>(other)), + prop_fns_(other.prop_fns_) + { + } + + any_executor(std::nothrow_t, const any_executor& other) noexcept + : detail::any_executor_base( + static_cast<const detail::any_executor_base&>(other)), + prop_fns_(other.prop_fns_) + { + } + + any_executor& operator=(const any_executor& other) noexcept + { + if (this != &other) + { + prop_fns_ = other.prop_fns_; + detail::any_executor_base::operator=( + static_cast<const detail::any_executor_base&>(other)); + } + return *this; + } + + any_executor& operator=(nullptr_t p) noexcept + { + prop_fns_ = prop_fns_table<void>(); + detail::any_executor_base::operator=(p); + return *this; + } + + any_executor(any_executor&& other) noexcept + : detail::any_executor_base( + static_cast<any_executor_base&&>( + static_cast<any_executor_base&>(other))), + prop_fns_(other.prop_fns_) + { + other.prop_fns_ = prop_fns_table<void>(); + } + + any_executor(std::nothrow_t, any_executor&& other) noexcept + : detail::any_executor_base( + static_cast<any_executor_base&&>( + static_cast<any_executor_base&>(other))), + prop_fns_(other.prop_fns_) + { + other.prop_fns_ = prop_fns_table<void>(); + } + + any_executor& operator=(any_executor&& other) noexcept + { + if (this != &other) + { + prop_fns_ = other.prop_fns_; + detail::any_executor_base::operator=( + static_cast<detail::any_executor_base&&>( + static_cast<detail::any_executor_base&>(other))); + } + return *this; + } + + void swap(any_executor& other) noexcept + { + if (this != &other) + { + detail::any_executor_base::swap( + static_cast<detail::any_executor_base&>(other)); + const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_; + other.prop_fns_ = prop_fns_; + prop_fns_ = tmp_prop_fns; + } + } + + using detail::any_executor_base::execute; + using detail::any_executor_base::target; + using detail::any_executor_base::target_type; + using detail::any_executor_base::operator unspecified_bool_type; + using detail::any_executor_base::operator!; + + bool equality_helper(const any_executor& other) const noexcept + { + return any_executor_base::equality_helper(other); + } + + template <typename AnyExecutor1, typename AnyExecutor2> + friend enable_if_t< + is_base_of<any_executor, AnyExecutor1>::value + || is_base_of<any_executor, AnyExecutor2>::value, + bool + > operator==(const AnyExecutor1& a, + const AnyExecutor2& b) noexcept + { + return static_cast<const any_executor&>(a).equality_helper(b); + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator==(const AnyExecutor& a, nullptr_t) noexcept + { + return !a; + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator==(nullptr_t, const AnyExecutor& b) noexcept + { + return !b; + } + + template <typename AnyExecutor1, typename AnyExecutor2> + friend enable_if_t< + is_base_of<any_executor, AnyExecutor1>::value + || is_base_of<any_executor, AnyExecutor2>::value, + bool + > operator!=(const AnyExecutor1& a, + const AnyExecutor2& b) noexcept + { + return !static_cast<const any_executor&>(a).equality_helper(b); + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator!=(const AnyExecutor& a, nullptr_t) noexcept + { + return !!a; + } + + template <typename AnyExecutor> + friend enable_if_t< + is_same<AnyExecutor, any_executor>::value, + bool + > operator!=(nullptr_t, const AnyExecutor& b) noexcept + { + return !!b; + } + + template <typename T> + struct find_convertible_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property<T> {}; + + template <typename Property> + void query(const Property& p, + enable_if_t< + is_same< + typename find_convertible_property<Property>::query_result_type, + void + >::value + >* = 0) const + { + if (!target_) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + typedef find_convertible_property<Property> found; + prop_fns_[found::index].query(0, object_fns_->target(*this), + &static_cast<const typename found::type&>(p)); + } + + template <typename Property> + typename find_convertible_property<Property>::query_result_type + query(const Property& p, + enable_if_t< + !is_same< + typename find_convertible_property<Property>::query_result_type, + void + >::value + && + is_reference< + typename find_convertible_property<Property>::query_result_type + >::value + >* = 0) const + { + if (!target_) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + typedef find_convertible_property<Property> found; + remove_reference_t<typename found::query_result_type>* result = 0; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast<const typename found::type&>(p)); + return *result; + } + + template <typename Property> + typename find_convertible_property<Property>::query_result_type + query(const Property& p, + enable_if_t< + !is_same< + typename find_convertible_property<Property>::query_result_type, + void + >::value + && + is_scalar< + typename find_convertible_property<Property>::query_result_type + >::value + >* = 0) const + { + if (!target_) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + typedef find_convertible_property<Property> found; + typename found::query_result_type result; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast<const typename found::type&>(p)); + return result; + } + + template <typename Property> + typename find_convertible_property<Property>::query_result_type + query(const Property& p, + enable_if_t< + !is_same< + typename find_convertible_property<Property>::query_result_type, + void + >::value + && + !is_reference< + typename find_convertible_property<Property>::query_result_type + >::value + && + !is_scalar< + typename find_convertible_property<Property>::query_result_type + >::value + >* = 0) const + { + if (!target_) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + typedef find_convertible_property<Property> found; + typename found::query_result_type* result; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast<const typename found::type&>(p)); + return *asio::detail::scoped_ptr< + typename found::query_result_type>(result); + } + + template <typename T> + struct find_convertible_requirable_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_requirable_property<T> {}; + + template <typename Property> + any_executor require(const Property& p, + enable_if_t< + find_convertible_requirable_property<Property>::value + >* = 0) const + { + if (!target_) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + typedef find_convertible_requirable_property<Property> found; + return prop_fns_[found::index].require(object_fns_->target(*this), + &static_cast<const typename found::type&>(p)); + } + + template <typename T> + struct find_convertible_preferable_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_preferable_property<T> {}; + + template <typename Property> + any_executor prefer(const Property& p, + enable_if_t< + find_convertible_preferable_property<Property>::value + >* = 0) const + { + if (!target_) + { + bad_executor ex; + asio::detail::throw_exception(ex); + } + typedef find_convertible_preferable_property<Property> found; + return prop_fns_[found::index].prefer(object_fns_->target(*this), + &static_cast<const typename found::type&>(p)); + } + +//private: + template <typename Ex> + static const prop_fns<any_executor>* prop_fns_table() + { + static const prop_fns<any_executor> fns[] = + { + { + &detail::any_executor_base::query_fn< + Ex, SupportableProperties>, + &detail::any_executor_base::require_fn< + any_executor, Ex, SupportableProperties>, + &detail::any_executor_base::prefer_fn< + any_executor, Ex, SupportableProperties> + }... + }; + return fns; + } + + const prop_fns<any_executor>* prop_fns_; +}; + +template <typename... SupportableProperties> +inline void swap(any_executor<SupportableProperties...>& a, + any_executor<SupportableProperties...>& b) noexcept +{ + return a.swap(b); +} + +} // namespace execution +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename... SupportableProperties> +struct equality_comparable<execution::any_executor<SupportableProperties...>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename F, typename... SupportableProperties> +struct execute_member<execution::any_executor<SupportableProperties...>, F> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Prop, typename... SupportableProperties> +struct query_member< + execution::any_executor<SupportableProperties...>, Prop, + enable_if_t< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property<Prop>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef typename execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property<Prop>::query_result_type result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Prop, typename... SupportableProperties> +struct require_member< + execution::any_executor<SupportableProperties...>, Prop, + enable_if_t< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_requirable_property<Prop>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef execution::any_executor<SupportableProperties...> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template <typename Prop, typename... SupportableProperties> +struct prefer_member< + execution::any_executor<SupportableProperties...>, Prop, + enable_if_t< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_preferable_property<Prop>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef execution::any_executor<SupportableProperties...> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_ANY_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/execution/bad_executor.hpp b/3rdparty/asio/include/asio/execution/bad_executor.hpp new file mode 100644 index 00000000000..791951684fe --- /dev/null +++ b/3rdparty/asio/include/asio/execution/bad_executor.hpp @@ -0,0 +1,46 @@ +// +// execution/bad_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_BAD_EXECUTOR_HPP +#define ASIO_EXECUTION_BAD_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <exception> +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +/// Exception thrown when trying to access an empty polymorphic executor. +class bad_executor + : public std::exception +{ +public: + /// Constructor. + ASIO_DECL bad_executor() noexcept; + + /// Obtain message associated with exception. + ASIO_DECL virtual const char* what() const noexcept; +}; + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/execution/impl/bad_executor.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_EXECUTION_BAD_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/execution/blocking.hpp b/3rdparty/asio/include/asio/execution/blocking.hpp new file mode 100644 index 00000000000..e120299bded --- /dev/null +++ b/3rdparty/asio/include/asio/execution/blocking.hpp @@ -0,0 +1,1360 @@ +// +// execution/blocking.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_BLOCKING_HPP +#define ASIO_EXECUTION_BLOCKING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/require.hpp" +#include "asio/traits/execute_member.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe what guarantees an executor makes about the blocking +/// behaviour of their execution functions. +struct blocking_t +{ + /// The blocking_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The top-level blocking_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level blocking_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// A sub-property that indicates that invocation of an executor's execution + /// function may block pending completion of one or more invocations of the + /// submitted function object. + struct possibly_t + { + /// The blocking_t::possibly_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The blocking_t::possibly_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::possibly_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr possibly_t(); + + /// Get the value associated with a property object. + /** + * @returns possibly_t(); + */ + static constexpr blocking_t value(); + }; + + /// A sub-property that indicates that invocation of an executor's execution + /// function shall block until completion of all invocations of the submitted + /// function object. + struct always_t + { + /// The blocking_t::always_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The blocking_t::always_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::always_t property can be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr always_t(); + + /// Get the value associated with a property object. + /** + * @returns always_t(); + */ + static constexpr blocking_t value(); + }; + + /// A sub-property that indicates that invocation of an executor's execution + /// function shall not block pending completion of the invocations of the + /// submitted function object. + struct never_t + { + /// The blocking_t::never_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The blocking_t::never_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::never_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr never_t(); + + /// Get the value associated with a property object. + /** + * @returns never_t(); + */ + static constexpr blocking_t value(); + }; + + /// A special value used for accessing the blocking_t::possibly_t property. + static constexpr possibly_t possibly; + + /// A special value used for accessing the blocking_t::always_t property. + static constexpr always_t always; + + /// A special value used for accessing the blocking_t::never_t property. + static constexpr never_t never; + + /// Default constructor. + constexpr blocking_t(); + + /// Construct from a sub-property value. + constexpr blocking_t(possibly_t); + + /// Construct from a sub-property value. + constexpr blocking_t(always_t); + + /// Construct from a sub-property value. + constexpr blocking_t(never_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const blocking_t& a, const blocking_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const blocking_t& a, const blocking_t& b) noexcept; +}; + +/// A special value used for accessing the blocking_t property. +constexpr blocking_t blocking; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace blocking { + +template <int I> struct possibly_t; +template <int I> struct always_t; +template <int I> struct never_t; + +} // namespace blocking +namespace blocking_adaptation { + +template <int I> struct allowed_t; + +template <typename Executor, typename Function> +void blocking_execute( + Executor&& ex, + Function&& func); + +} // namespace blocking_adaptation + +template <int I = 0> +struct blocking_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + typedef blocking_t polymorphic_query_result_type; + + typedef detail::blocking::possibly_t<I> possibly_t; + typedef detail::blocking::always_t<I> always_t; + typedef detail::blocking::never_t<I> never_t; + + constexpr blocking_t() + : value_(-1) + { + } + + constexpr blocking_t(possibly_t) + : value_(0) + { + } + + constexpr blocking_t(always_t) + : value_(1) + { + } + + constexpr blocking_t(never_t) + : value_(2) + { + } + + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template <typename P> + auto query(P&& p) const + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_member : + traits::query_member<typename proxy<T>::type, blocking_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, blocking_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, possibly_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, possibly_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, possibly_t>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, always_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, possibly_t>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, always_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, always_t>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, never_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, possibly_t>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, always_t>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, never_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, never_t>::value(); + } + + template <typename E, typename T = decltype(blocking_t::static_query<E>())> + static constexpr const T static_query_v + = blocking_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend constexpr bool operator==( + const blocking_t& a, const blocking_t& b) + { + return a.value_ == b.value_; + } + + friend constexpr bool operator!=( + const blocking_t& a, const blocking_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_blocking_t + { + constexpr convertible_from_blocking_t(blocking_t) {} + }; + + template <typename Executor> + friend constexpr blocking_t query( + const Executor& ex, convertible_from_blocking_t, + enable_if_t< + can_query<const Executor&, possibly_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, blocking_t<>::possibly_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, possibly_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, possibly_t()); + } + + template <typename Executor> + friend constexpr blocking_t query( + const Executor& ex, convertible_from_blocking_t, + enable_if_t< + !can_query<const Executor&, possibly_t>::value + >* = 0, + enable_if_t< + can_query<const Executor&, always_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, blocking_t<>::always_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, always_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, always_t()); + } + + template <typename Executor> + friend constexpr blocking_t query( + const Executor& ex, convertible_from_blocking_t, + enable_if_t< + !can_query<const Executor&, possibly_t>::value + >* = 0, + enable_if_t< + !can_query<const Executor&, always_t>::value + >* = 0, + enable_if_t< + can_query<const Executor&, never_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, blocking_t<>::never_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, never_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, never_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never); + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T blocking_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I> +const typename blocking_t<I>::possibly_t blocking_t<I>::possibly; + +template <int I> +const typename blocking_t<I>::always_t blocking_t<I>::always; + +template <int I> +const typename blocking_t<I>::never_t blocking_t<I>::never; + +namespace blocking { + +template <int I = 0> +struct possibly_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef blocking_t<I> polymorphic_query_result_type; + + constexpr possibly_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename blocking_t<I>::template proxy<T>::type, possibly_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_t<I>::template static_proxy<T>::type, possibly_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr possibly_t static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::query_free<T, possibly_t>::is_valid + >* = 0, + enable_if_t< + !can_query<T, always_t<I>>::value + >* = 0, + enable_if_t< + !can_query<T, never_t<I>>::value + >* = 0) noexcept + { + return possibly_t(); + } + + template <typename E, typename T = decltype(possibly_t::static_query<E>())> + static constexpr const T static_query_v + = possibly_t::static_query<E>(); +#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr blocking_t<I> value() + { + return possibly_t(); + } + + friend constexpr bool operator==( + const possibly_t&, const possibly_t&) + { + return true; + } + + friend constexpr bool operator!=( + const possibly_t&, const possibly_t&) + { + return false; + } + + friend constexpr bool operator==( + const possibly_t&, const always_t<I>&) + { + return false; + } + + friend constexpr bool operator!=( + const possibly_t&, const always_t<I>&) + { + return true; + } + + friend constexpr bool operator==( + const possibly_t&, const never_t<I>&) + { + return false; + } + + friend constexpr bool operator!=( + const possibly_t&, const never_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T possibly_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename Executor> +class adapter +{ +public: + adapter(int, const Executor& e) noexcept + : executor_(e) + { + } + + adapter(const adapter& other) noexcept + : executor_(other.executor_) + { + } + + adapter(adapter&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)) + { + } + + template <int I> + static constexpr always_t<I> query(blocking_t<I>) noexcept + { + return always_t<I>(); + } + + template <int I> + static constexpr always_t<I> query(possibly_t<I>) noexcept + { + return always_t<I>(); + } + + template <int I> + static constexpr always_t<I> query(always_t<I>) noexcept + { + return always_t<I>(); + } + + template <int I> + static constexpr always_t<I> query(never_t<I>) noexcept + { + return always_t<I>(); + } + + template <typename Property> + enable_if_t< + can_query<const Executor&, Property>::value, + query_result_t<const Executor&, Property> + > query(const Property& p) const + noexcept(is_nothrow_query<const Executor&, Property>::value) + { + return asio::query(executor_, p); + } + + template <int I> + enable_if_t< + can_require<const Executor&, possibly_t<I>>::value, + require_result_t<const Executor&, possibly_t<I>> + > require(possibly_t<I>) const noexcept + { + return asio::require(executor_, possibly_t<I>()); + } + + template <int I> + enable_if_t< + can_require<const Executor&, never_t<I>>::value, + require_result_t<const Executor&, never_t<I>> + > require(never_t<I>) const noexcept + { + return asio::require(executor_, never_t<I>()); + } + + template <typename Property> + enable_if_t< + can_require<const Executor&, Property>::value, + adapter<decay_t<require_result_t<const Executor&, Property>>> + > require(const Property& p) const + noexcept(is_nothrow_require<const Executor&, Property>::value) + { + return adapter<decay_t<require_result_t<const Executor&, Property>>>( + 0, asio::require(executor_, p)); + } + + template <typename Property> + enable_if_t< + can_prefer<const Executor&, Property>::value, + adapter<decay_t<prefer_result_t<const Executor&, Property>>> + > prefer(const Property& p) const + noexcept(is_nothrow_prefer<const Executor&, Property>::value) + { + return adapter<decay_t<prefer_result_t<const Executor&, Property>>>( + 0, asio::prefer(executor_, p)); + } + + template <typename Function> + enable_if_t< + traits::execute_member<const Executor&, Function>::is_valid + > execute(Function&& f) const + { + blocking_adaptation::blocking_execute( + executor_, static_cast<Function&&>(f)); + } + + friend bool operator==(const adapter& a, const adapter& b) noexcept + { + return a.executor_ == b.executor_; + } + + friend bool operator!=(const adapter& a, const adapter& b) noexcept + { + return a.executor_ != b.executor_; + } + +private: + Executor executor_; +}; + +template <int I = 0> +struct always_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = false; + typedef blocking_t<I> polymorphic_query_result_type; + + constexpr always_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename blocking_t<I>::template proxy<T>::type, always_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_t<I>::template static_proxy<T>::type, always_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(always_t::static_query<E>())> + static constexpr const T static_query_v = always_t::static_query<E>(); +#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr blocking_t<I> value() + { + return always_t(); + } + + friend constexpr bool operator==( + const always_t&, const always_t&) + { + return true; + } + + friend constexpr bool operator!=( + const always_t&, const always_t&) + { + return false; + } + + friend constexpr bool operator==( + const always_t&, const possibly_t<I>&) + { + return false; + } + + friend constexpr bool operator!=( + const always_t&, const possibly_t<I>&) + { + return true; + } + + friend constexpr bool operator==( + const always_t&, const never_t<I>&) + { + return false; + } + + friend constexpr bool operator!=( + const always_t&, const never_t<I>&) + { + return true; + } + + template <typename Executor> + friend adapter<Executor> require( + const Executor& e, const always_t&, + enable_if_t< + is_executor<Executor>::value + >* = 0, + enable_if_t< + traits::static_require< + const Executor&, + blocking_adaptation::allowed_t<0> + >::is_valid + >* = 0) + { + return adapter<Executor>(0, e); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T always_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I> +struct never_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef blocking_t<I> polymorphic_query_result_type; + + constexpr never_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename blocking_t<I>::template proxy<T>::type, never_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_t<I>::template static_proxy<T>::type, never_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(never_t::static_query<E>())> + static constexpr const T static_query_v + = never_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr blocking_t<I> value() + { + return never_t(); + } + + friend constexpr bool operator==(const never_t&, const never_t&) + { + return true; + } + + friend constexpr bool operator!=(const never_t&, const never_t&) + { + return false; + } + + friend constexpr bool operator==(const never_t&, const possibly_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const never_t&, const possibly_t<I>&) + { + return true; + } + + friend constexpr bool operator==(const never_t&, const always_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const never_t&, const always_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T never_t<I>::static_query_v; +#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace blocking +} // namespace detail + +typedef detail::blocking_t<> blocking_t; + +constexpr blocking_t blocking; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +struct is_applicable_property<T, execution::blocking_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::blocking_t::possibly_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::blocking_t::always_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::blocking_t::never_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T> +struct query_free_default<T, execution::blocking_t, + enable_if_t< + can_query<T, execution::blocking_t::possibly_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::blocking_t::possibly_t>::value; + + typedef execution::blocking_t result_type; +}; + +template <typename T> +struct query_free_default<T, execution::blocking_t, + enable_if_t< + !can_query<T, execution::blocking_t::possibly_t>::value + && can_query<T, execution::blocking_t::always_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::blocking_t::always_t>::value; + + typedef execution::blocking_t result_type; +}; + +template <typename T> +struct query_free_default<T, execution::blocking_t, + enable_if_t< + !can_query<T, execution::blocking_t::possibly_t>::value + && !can_query<T, execution::blocking_t::always_t>::value + && can_query<T, execution::blocking_t::never_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::blocking_t::never_t>::value; + + typedef execution::blocking_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T> +struct static_query<T, execution::blocking_t, + enable_if_t< + execution::detail::blocking_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::blocking_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::blocking_t::query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_t, + enable_if_t< + !execution::detail::blocking_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::blocking_t<0>:: + query_member<T>::is_valid + && traits::static_query<T, execution::blocking_t::possibly_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::blocking_t::possibly_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, execution::blocking_t::possibly_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_t, + enable_if_t< + !execution::detail::blocking_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::blocking_t<0>:: + query_member<T>::is_valid + && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid + && traits::static_query<T, execution::blocking_t::always_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::blocking_t::always_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, execution::blocking_t::always_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_t, + enable_if_t< + !execution::detail::blocking_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::blocking_t<0>:: + query_member<T>::is_valid + && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid + && !traits::static_query<T, execution::blocking_t::always_t>::is_valid + && traits::static_query<T, execution::blocking_t::never_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::blocking_t::never_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, execution::blocking_t::never_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_t::possibly_t, + enable_if_t< + execution::detail::blocking::possibly_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::blocking::possibly_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::blocking::possibly_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_t::possibly_t, + enable_if_t< + !execution::detail::blocking::possibly_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::blocking::possibly_t<0>:: + query_member<T>::is_valid + && !traits::query_free<T, execution::blocking_t::possibly_t>::is_valid + && !can_query<T, execution::blocking_t::always_t>::value + && !can_query<T, execution::blocking_t::never_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef execution::blocking_t::possibly_t result_type; + + static constexpr result_type value() + { + return result_type(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_t::always_t, + enable_if_t< + execution::detail::blocking::always_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::blocking::always_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::blocking::always_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_t::never_t, + enable_if_t< + execution::detail::blocking::never_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::blocking::never_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::blocking::never_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template <typename T> +struct require_free_default<T, execution::blocking_t::always_t, + enable_if_t< + is_same<T, decay_t<T>>::value + && execution::is_executor<T>::value + && traits::static_require< + const T&, + execution::detail::blocking_adaptation::allowed_t<0> + >::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef execution::detail::blocking::adapter<T> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename Executor> +struct equality_comparable< + execution::detail::blocking::adapter<Executor>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename Executor, typename Function> +struct execute_member< + execution::detail::blocking::adapter<Executor>, Function> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename Executor, int I> +struct query_static_constexpr_member< + execution::detail::blocking::adapter<Executor>, + execution::detail::blocking_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef execution::blocking_t::always_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +template <typename Executor, int I> +struct query_static_constexpr_member< + execution::detail::blocking::adapter<Executor>, + execution::detail::blocking::always_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef execution::blocking_t::always_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +template <typename Executor, int I> +struct query_static_constexpr_member< + execution::detail::blocking::adapter<Executor>, + execution::detail::blocking::possibly_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef execution::blocking_t::always_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +template <typename Executor, int I> +struct query_static_constexpr_member< + execution::detail::blocking::adapter<Executor>, + execution::detail::blocking::never_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef execution::blocking_t::always_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Executor, typename Property> +struct query_member< + execution::detail::blocking::adapter<Executor>, Property, + enable_if_t< + can_query<const Executor&, Property>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<Executor, Property>::value; + typedef query_result_t<Executor, Property> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Executor, int I> +struct require_member< + execution::detail::blocking::adapter<Executor>, + execution::detail::blocking::possibly_t<I>, + enable_if_t< + can_require< + const Executor&, + execution::detail::blocking::possibly_t<I> + >::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_require<const Executor&, + execution::detail::blocking::possibly_t<I>>::value; + typedef require_result_t<const Executor&, + execution::detail::blocking::possibly_t<I>> result_type; +}; + +template <typename Executor, int I> +struct require_member< + execution::detail::blocking::adapter<Executor>, + execution::detail::blocking::never_t<I>, + enable_if_t< + can_require< + const Executor&, + execution::detail::blocking::never_t<I> + >::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_require<const Executor&, + execution::detail::blocking::never_t<I>>::value; + typedef require_result_t<const Executor&, + execution::detail::blocking::never_t<I>> result_type; +}; + +template <typename Executor, typename Property> +struct require_member< + execution::detail::blocking::adapter<Executor>, Property, + enable_if_t< + can_require<const Executor&, Property>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_require<Executor, Property>::value; + typedef execution::detail::blocking::adapter< + decay_t<require_result_t<Executor, Property>>> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template <typename Executor, typename Property> +struct prefer_member< + execution::detail::blocking::adapter<Executor>, Property, + enable_if_t< + can_prefer<const Executor&, Property>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_prefer<Executor, Property>::value; + typedef execution::detail::blocking::adapter< + decay_t<prefer_result_t<Executor, Property>>> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_BLOCKING_HPP diff --git a/3rdparty/asio/include/asio/execution/blocking_adaptation.hpp b/3rdparty/asio/include/asio/execution/blocking_adaptation.hpp new file mode 100644 index 00000000000..a2769b254a5 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/blocking_adaptation.hpp @@ -0,0 +1,1080 @@ +// +// execution/blocking_adaptation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_BLOCKING_ADAPTATION_HPP +#define ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/event.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/require.hpp" +#include "asio/traits/prefer_member.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/require_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether automatic adaptation of an executor is +/// allowed in order to apply the blocking_adaptation_t::allowed_t property. +struct blocking_adaptation_t +{ + /// The blocking_adaptation_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The top-level blocking_adaptation_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level blocking_adaptation_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// A sub-property that indicates that automatic adaptation is not allowed. + struct disallowed_t + { + /// The blocking_adaptation_t::disallowed_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The blocking_adaptation_t::disallowed_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_adaptation_t::disallowed_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// Default constructor. + constexpr disallowed_t(); + + /// Get the value associated with a property object. + /** + * @returns disallowed_t(); + */ + static constexpr blocking_adaptation_t value(); + }; + + /// A sub-property that indicates that automatic adaptation is allowed. + struct allowed_t + { + /// The blocking_adaptation_t::allowed_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The blocking_adaptation_t::allowed_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_adaptation_t::allowed_t property can be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// Default constructor. + constexpr allowed_t(); + + /// Get the value associated with a property object. + /** + * @returns allowed_t(); + */ + static constexpr blocking_adaptation_t value(); + }; + + /// A special value used for accessing the blocking_adaptation_t::disallowed_t + /// property. + static constexpr disallowed_t disallowed; + + /// A special value used for accessing the blocking_adaptation_t::allowed_t + /// property. + static constexpr allowed_t allowed; + + /// Default constructor. + constexpr blocking_adaptation_t(); + + /// Construct from a sub-property value. + constexpr blocking_adaptation_t(disallowed_t); + + /// Construct from a sub-property value. + constexpr blocking_adaptation_t(allowed_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; +}; + +/// A special value used for accessing the blocking_adaptation_t property. +constexpr blocking_adaptation_t blocking_adaptation; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace blocking_adaptation { + +template <int I> struct disallowed_t; +template <int I> struct allowed_t; + +} // namespace blocking_adaptation + +template <int I = 0> +struct blocking_adaptation_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + typedef blocking_adaptation_t polymorphic_query_result_type; + + typedef detail::blocking_adaptation::disallowed_t<I> disallowed_t; + typedef detail::blocking_adaptation::allowed_t<I> allowed_t; + + constexpr blocking_adaptation_t() + : value_(-1) + { + } + + constexpr blocking_adaptation_t(disallowed_t) + : value_(0) + { + } + + constexpr blocking_adaptation_t(allowed_t) + : value_(1) + { + } + + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template <typename P> + auto query(P&& p) const + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_member : + traits::query_member<typename proxy<T>::type, blocking_adaptation_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, blocking_adaptation_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, disallowed_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, disallowed_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, disallowed_t>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, allowed_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, disallowed_t>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, allowed_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, allowed_t>::value(); + } + + template <typename E, + typename T = decltype(blocking_adaptation_t::static_query<E>())> + static constexpr const T static_query_v + = blocking_adaptation_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend constexpr bool operator==( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) + { + return a.value_ == b.value_; + } + + friend constexpr bool operator!=( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_blocking_adaptation_t + { + constexpr convertible_from_blocking_adaptation_t( + blocking_adaptation_t) + { + } + }; + + template <typename Executor> + friend constexpr blocking_adaptation_t query( + const Executor& ex, convertible_from_blocking_adaptation_t, + enable_if_t< + can_query<const Executor&, disallowed_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, + blocking_adaptation_t<>::disallowed_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, disallowed_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, disallowed_t()); + } + + template <typename Executor> + friend constexpr blocking_adaptation_t query( + const Executor& ex, convertible_from_blocking_adaptation_t, + enable_if_t< + !can_query<const Executor&, disallowed_t>::value + >* = 0, + enable_if_t< + can_query<const Executor&, allowed_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, + blocking_adaptation_t<>::allowed_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, allowed_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, allowed_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed); + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T blocking_adaptation_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I> +const typename blocking_adaptation_t<I>::disallowed_t +blocking_adaptation_t<I>::disallowed; + +template <int I> +const typename blocking_adaptation_t<I>::allowed_t +blocking_adaptation_t<I>::allowed; + +namespace blocking_adaptation { + +template <int I = 0> +struct disallowed_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef blocking_adaptation_t<I> polymorphic_query_result_type; + + constexpr disallowed_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename blocking_adaptation_t<I>::template proxy<T>::type, + disallowed_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_adaptation_t<I>::template static_proxy<T>::type, + disallowed_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr disallowed_t static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::query_free<T, disallowed_t>::is_valid + >* = 0, + enable_if_t< + !can_query<T, allowed_t<I>>::value + >* = 0) noexcept + { + return disallowed_t(); + } + + template <typename E, typename T = decltype(disallowed_t::static_query<E>())> + static constexpr const T static_query_v + = disallowed_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr blocking_adaptation_t<I> value() + { + return disallowed_t(); + } + + friend constexpr bool operator==(const disallowed_t&, const disallowed_t&) + { + return true; + } + + friend constexpr bool operator!=(const disallowed_t&, const disallowed_t&) + { + return false; + } + + friend constexpr bool operator==(const disallowed_t&, const allowed_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const disallowed_t&, const allowed_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T disallowed_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename Executor> +class adapter +{ +public: + adapter(int, const Executor& e) noexcept + : executor_(e) + { + } + + adapter(const adapter& other) noexcept + : executor_(other.executor_) + { + } + + adapter(adapter&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)) + { + } + + template <int I> + static constexpr allowed_t<I> query(blocking_adaptation_t<I>) noexcept + { + return allowed_t<I>(); + } + + template <int I> + static constexpr allowed_t<I> query(allowed_t<I>) noexcept + { + return allowed_t<I>(); + } + + template <int I> + static constexpr allowed_t<I> query(disallowed_t<I>) noexcept + { + return allowed_t<I>(); + } + + template <typename Property> + enable_if_t< + can_query<const Executor&, Property>::value, + query_result_t<const Executor&, Property> + > query(const Property& p) const + noexcept(is_nothrow_query<const Executor&, Property>::value) + { + return asio::query(executor_, p); + } + + template <int I> + Executor require(disallowed_t<I>) const noexcept + { + return executor_; + } + + template <typename Property> + enable_if_t< + can_require<const Executor&, Property>::value, + adapter<decay_t<require_result_t<const Executor&, Property>>> + > require(const Property& p) const + noexcept(is_nothrow_require<const Executor&, Property>::value) + { + return adapter<decay_t<require_result_t<const Executor&, Property>>>( + 0, asio::require(executor_, p)); + } + + template <typename Property> + enable_if_t< + can_prefer<const Executor&, Property>::value, + adapter<decay_t<prefer_result_t<const Executor&, Property>>> + > prefer(const Property& p) const + noexcept(is_nothrow_prefer<const Executor&, Property>::value) + { + return adapter<decay_t<prefer_result_t<const Executor&, Property>>>( + 0, asio::prefer(executor_, p)); + } + + template <typename Function> + enable_if_t< + traits::execute_member<const Executor&, Function>::is_valid + > execute(Function&& f) const + { + executor_.execute(static_cast<Function&&>(f)); + } + + friend bool operator==(const adapter& a, const adapter& b) noexcept + { + return a.executor_ == b.executor_; + } + + friend bool operator!=(const adapter& a, const adapter& b) noexcept + { + return a.executor_ != b.executor_; + } + +private: + Executor executor_; +}; + +template <int I = 0> +struct allowed_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = false; + typedef blocking_adaptation_t<I> polymorphic_query_result_type; + + constexpr allowed_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename blocking_adaptation_t<I>::template proxy<T>::type, + allowed_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename blocking_adaptation_t<I>::template static_proxy<T>::type, + allowed_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(allowed_t::static_query<E>())> + static constexpr const T static_query_v = allowed_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr blocking_adaptation_t<I> value() + { + return allowed_t(); + } + + friend constexpr bool operator==(const allowed_t&, const allowed_t&) + { + return true; + } + + friend constexpr bool operator!=(const allowed_t&, const allowed_t&) + { + return false; + } + + friend constexpr bool operator==(const allowed_t&, const disallowed_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const allowed_t&, const disallowed_t<I>&) + { + return true; + } + + template <typename Executor> + friend adapter<Executor> require( + const Executor& e, const allowed_t&, + enable_if_t< + is_executor<Executor>::value + >* = 0) + { + return adapter<Executor>(0, e); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T allowed_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename Function> +class blocking_execute_state +{ +public: + template <typename F> + blocking_execute_state(F&& f) + : func_(static_cast<F&&>(f)), + is_complete_(false) + { + } + + template <typename Executor> + void execute_and_wait(Executor&& ex) + { + handler h = { this }; + ex.execute(h); + asio::detail::mutex::scoped_lock lock(mutex_); + while (!is_complete_) + event_.wait(lock); + } + + struct cleanup + { + ~cleanup() + { + asio::detail::mutex::scoped_lock lock(state_->mutex_); + state_->is_complete_ = true; + state_->event_.unlock_and_signal_one_for_destruction(lock); + } + + blocking_execute_state* state_; + }; + + struct handler + { + void operator()() + { + cleanup c = { state_ }; + state_->func_(); + } + + blocking_execute_state* state_; + }; + + Function func_; + asio::detail::mutex mutex_; + asio::detail::event event_; + bool is_complete_; +}; + +template <typename Executor, typename Function> +void blocking_execute( + Executor&& ex, + Function&& func) +{ + typedef decay_t<Function> func_t; + blocking_execute_state<func_t> state(static_cast<Function&&>(func)); + state.execute_and_wait(ex); +} + +} // namespace blocking_adaptation +} // namespace detail + +typedef detail::blocking_adaptation_t<> blocking_adaptation_t; + +constexpr blocking_adaptation_t blocking_adaptation; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +struct is_applicable_property<T, execution::blocking_adaptation_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::blocking_adaptation_t::disallowed_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::blocking_adaptation_t::allowed_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T> +struct query_free_default<T, execution::blocking_adaptation_t, + enable_if_t< + can_query<T, execution::blocking_adaptation_t::disallowed_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::blocking_adaptation_t::disallowed_t>::value; + + typedef execution::blocking_adaptation_t result_type; +}; + +template <typename T> +struct query_free_default<T, execution::blocking_adaptation_t, + enable_if_t< + !can_query<T, execution::blocking_adaptation_t::disallowed_t>::value + && can_query<T, execution::blocking_adaptation_t::allowed_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::blocking_adaptation_t::allowed_t>::value; + + typedef execution::blocking_adaptation_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T> +struct static_query<T, execution::blocking_adaptation_t, + enable_if_t< + execution::detail::blocking_adaptation_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::blocking_adaptation_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::blocking_adaptation_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_adaptation_t, + enable_if_t< + !execution::detail::blocking_adaptation_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::blocking_adaptation_t<0>:: + query_member<T>::is_valid + && traits::static_query<T, + execution::blocking_adaptation_t::disallowed_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::blocking_adaptation_t::disallowed_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, + execution::blocking_adaptation_t::disallowed_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_adaptation_t, + enable_if_t< + !execution::detail::blocking_adaptation_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::blocking_adaptation_t<0>:: + query_member<T>::is_valid + && !traits::static_query<T, + execution::blocking_adaptation_t::disallowed_t>::is_valid + && traits::static_query<T, + execution::blocking_adaptation_t::allowed_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::blocking_adaptation_t::allowed_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, + execution::blocking_adaptation_t::allowed_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_adaptation_t::disallowed_t, + enable_if_t< + execution::detail::blocking_adaptation::disallowed_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::blocking_adaptation::disallowed_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::blocking_adaptation::disallowed_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_adaptation_t::disallowed_t, + enable_if_t< + !execution::detail::blocking_adaptation::disallowed_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::blocking_adaptation::disallowed_t<0>:: + query_member<T>::is_valid + && !traits::query_free<T, + execution::blocking_adaptation_t::disallowed_t>::is_valid + && !can_query<T, execution::blocking_adaptation_t::allowed_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef execution::blocking_adaptation_t::disallowed_t result_type; + + static constexpr result_type value() + { + return result_type(); + } +}; + +template <typename T> +struct static_query<T, execution::blocking_adaptation_t::allowed_t, + enable_if_t< + execution::detail::blocking_adaptation::allowed_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::blocking_adaptation::allowed_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::blocking_adaptation::allowed_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template <typename T> +struct require_free_default<T, execution::blocking_adaptation_t::allowed_t, + enable_if_t< + is_same<T, decay_t<T>>::value + && execution::is_executor<T>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef execution::detail::blocking_adaptation::adapter<T> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename Executor> +struct equality_comparable< + execution::detail::blocking_adaptation::adapter<Executor>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename Executor, typename Function> +struct execute_member< + execution::detail::blocking_adaptation::adapter<Executor>, Function> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename Executor, int I> +struct query_static_constexpr_member< + execution::detail::blocking_adaptation::adapter<Executor>, + execution::detail::blocking_adaptation_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef execution::blocking_adaptation_t::allowed_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +template <typename Executor, int I> +struct query_static_constexpr_member< + execution::detail::blocking_adaptation::adapter<Executor>, + execution::detail::blocking_adaptation::allowed_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef execution::blocking_adaptation_t::allowed_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +template <typename Executor, int I> +struct query_static_constexpr_member< + execution::detail::blocking_adaptation::adapter<Executor>, + execution::detail::blocking_adaptation::disallowed_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef execution::blocking_adaptation_t::allowed_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Executor, typename Property> +struct query_member< + execution::detail::blocking_adaptation::adapter<Executor>, Property, + enable_if_t< + can_query<const Executor&, Property>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<Executor, Property>::value; + typedef query_result_t<Executor, Property> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Executor, int I> +struct require_member< + execution::detail::blocking_adaptation::adapter<Executor>, + execution::detail::blocking_adaptation::disallowed_t<I>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Executor result_type; +}; + +template <typename Executor, typename Property> +struct require_member< + execution::detail::blocking_adaptation::adapter<Executor>, Property, + enable_if_t< + can_require<const Executor&, Property>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_require<Executor, Property>::value; + typedef execution::detail::blocking_adaptation::adapter< + decay_t<require_result_t<Executor, Property>>> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template <typename Executor, typename Property> +struct prefer_member< + execution::detail::blocking_adaptation::adapter<Executor>, Property, + enable_if_t< + can_prefer<const Executor&, Property>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_prefer<Executor, Property>::value; + typedef execution::detail::blocking_adaptation::adapter< + decay_t<prefer_result_t<Executor, Property>>> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP diff --git a/3rdparty/asio/include/asio/execution/context.hpp b/3rdparty/asio/include/asio/execution/context.hpp new file mode 100644 index 00000000000..a9df9c1c4b6 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/context.hpp @@ -0,0 +1,191 @@ +// +// execution/context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_CONTEXT2_HPP +#define ASIO_EXECUTION_CONTEXT2_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#if defined(ASIO_HAS_STD_ANY) +# include <any> +#endif // defined(ASIO_HAS_STD_ANY) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +struct context_t +{ + /// The context_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef std::any polymorphic_query_result_type; +}; + +/// A special value used for accessing the context_t property. +constexpr context_t context; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template <int I = 0> +struct context_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + +#if defined(ASIO_HAS_STD_ANY) + typedef std::any polymorphic_query_result_type; +#endif // defined(ASIO_HAS_STD_ANY) + + constexpr context_t() + { + } + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, context_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(context_t::static_query<E>())> + static constexpr const T static_query_v = context_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T context_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace detail + +typedef detail::context_t<> context_t; + +constexpr context_t context; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +struct is_applicable_property<T, execution::context_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T> +struct static_query<T, execution::context_t, + enable_if_t< + execution::detail::context_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::context_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::context_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_CONTEXT2_HPP diff --git a/3rdparty/asio/include/asio/execution/context_as.hpp b/3rdparty/asio/include/asio/execution/context_as.hpp new file mode 100644 index 00000000000..f51fb1dc4c7 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/context_as.hpp @@ -0,0 +1,190 @@ +// +// execution/context_as.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_CONTEXT_AS_HPP +#define ASIO_EXECUTION_CONTEXT_AS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/context.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +template <typename U> +struct context_as_t +{ + /// The context_as_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef T polymorphic_query_result_type; +}; + +/// A special value used for accessing the context_as_t property. +template <typename U> +constexpr context_as_t context_as; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +template <typename T> +struct context_as_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename U> + static constexpr bool is_applicable_property_v = is_executor<U>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + + typedef T polymorphic_query_result_type; + + constexpr context_as_t() + { + } + + constexpr context_as_t(context_t) + { + } + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename E> + static constexpr + typename context_t::query_static_constexpr_member<E>::result_type + static_query() + noexcept(context_t::query_static_constexpr_member<E>::is_noexcept) + { + return context_t::query_static_constexpr_member<E>::value(); + } + + template <typename E, typename U = decltype(context_as_t::static_query<E>())> + static constexpr const U static_query_v + = context_as_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template <typename Executor, typename U> + friend constexpr U query( + const Executor& ex, const context_as_t<U>&, + enable_if_t< + is_same<T, U>::value + >* = 0, + enable_if_t< + can_query<const Executor&, const context_t&>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, const context_t&>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, const context_t&>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, context); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <typename T> template <typename E, typename U> +const U context_as_t<T>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) +template <typename T> +constexpr context_as_t<T> context_as{}; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename U> +struct is_applicable_property<T, execution::context_as_t<U>> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T, typename U> +struct static_query<T, execution::context_as_t<U>, + enable_if_t< + static_query<T, execution::context_t>::is_valid + >> : static_query<T, execution::context_t> +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T, typename U> +struct query_free<T, execution::context_as_t<U>, + enable_if_t< + can_query<const T&, const execution::context_t&>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<const T&, const execution::context_t&>::value; + + typedef U result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_CONTEXT_AS_HPP diff --git a/3rdparty/asio/include/asio/execution/executor.hpp b/3rdparty/asio/include/asio/execution/executor.hpp new file mode 100644 index 00000000000..1f34981fa78 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/executor.hpp @@ -0,0 +1,116 @@ +// +// execution/executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_EXECUTOR_HPP +#define ASIO_EXECUTION_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/invocable_archetype.hpp" +#include "asio/traits/equality_comparable.hpp" +#include "asio/traits/execute_member.hpp" + +#if defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) +# define ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT 1 +#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + // && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { +namespace detail { + +template <typename T, typename F, + typename = void, typename = void, typename = void, typename = void, + typename = void, typename = void, typename = void, typename = void> +struct is_executor_of_impl : false_type +{ +}; + +template <typename T, typename F> +struct is_executor_of_impl<T, F, + enable_if_t< + traits::execute_member<add_const_t<T>, F>::is_valid + >, + void_t< + result_of_t<decay_t<F>&()> + >, + enable_if_t< + is_constructible<decay_t<F>, F>::value + >, + enable_if_t< + is_move_constructible<decay_t<F>>::value + >, + enable_if_t< + is_nothrow_copy_constructible<T>::value + >, + enable_if_t< + is_nothrow_destructible<T>::value + >, + enable_if_t< + traits::equality_comparable<T>::is_valid + >, + enable_if_t< + traits::equality_comparable<T>::is_noexcept + >> : true_type +{ +}; + +} // namespace detail + +/// The is_executor trait detects whether a type T satisfies the +/// execution::executor concept. +/** + * Class template @c is_executor is a UnaryTypeTrait that is derived from @c + * true_type if the type @c T meets the concept definition for an executor, + * otherwise @c false_type. + */ +template <typename T> +struct is_executor : +#if defined(GENERATING_DOCUMENTATION) + integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + detail::is_executor_of_impl<T, invocable_archetype> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +constexpr const bool is_executor_v = is_executor<T>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(ASIO_HAS_CONCEPTS) + +template <typename T> +ASIO_CONCEPT executor = is_executor<T>::value; + +#define ASIO_EXECUTION_EXECUTOR ::asio::execution::executor + +#else // defined(ASIO_HAS_CONCEPTS) + +#define ASIO_EXECUTION_EXECUTOR typename + +#endif // defined(ASIO_HAS_CONCEPTS) + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/execution/impl/bad_executor.ipp b/3rdparty/asio/include/asio/execution/impl/bad_executor.ipp new file mode 100644 index 00000000000..4e185acb059 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/impl/bad_executor.ipp @@ -0,0 +1,40 @@ +// +// exection/impl/bad_executor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_IMPL_BAD_EXECUTOR_IPP +#define ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/execution/bad_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +bad_executor::bad_executor() noexcept +{ +} + +const char* bad_executor::what() const noexcept +{ + return "bad executor"; +} + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP diff --git a/3rdparty/asio/include/asio/execution/invocable_archetype.hpp b/3rdparty/asio/include/asio/execution/invocable_archetype.hpp new file mode 100644 index 00000000000..50223279e1f --- /dev/null +++ b/3rdparty/asio/include/asio/execution/invocable_archetype.hpp @@ -0,0 +1,43 @@ +// +// execution/invocable_archetype.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_INVOCABLE_ARCHETYPE_HPP +#define ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace execution { + +/// An archetypal function object used for determining adherence to the +/// execution::executor concept. +struct invocable_archetype +{ + /// Function call operator. + template <typename... Args> + void operator()(Args&&...) + { + } +}; + +} // namespace execution +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP + diff --git a/3rdparty/asio/include/asio/execution/mapping.hpp b/3rdparty/asio/include/asio/execution/mapping.hpp new file mode 100644 index 00000000000..4c6e1791869 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/mapping.hpp @@ -0,0 +1,1002 @@ +// +// execution/mapping.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_MAPPING_HPP +#define ASIO_EXECUTION_MAPPING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe what guarantees an executor makes about the mapping +/// of execution agents on to threads of execution. +struct mapping_t +{ + /// The mapping_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The top-level mapping_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level mapping_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// A sub-property that indicates that execution agents are mapped on to + /// threads of execution. + struct thread_t + { + /// The mapping_t::thread_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The mapping_t::thread_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::thread_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr thread_t(); + + /// Get the value associated with a property object. + /** + * @returns thread_t(); + */ + static constexpr mapping_t value(); + }; + + /// A sub-property that indicates that execution agents are mapped on to + /// new threads of execution. + struct new_thread_t + { + /// The mapping_t::new_thread_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The mapping_t::new_thread_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::new_thread_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr new_thread_t(); + + /// Get the value associated with a property object. + /** + * @returns new_thread_t(); + */ + static constexpr mapping_t value(); + }; + + /// A sub-property that indicates that the mapping of execution agents is + /// implementation-defined. + struct other_t + { + /// The mapping_t::other_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The mapping_t::other_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::other_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr other_t(); + + /// Get the value associated with a property object. + /** + * @returns other_t(); + */ + static constexpr mapping_t value(); + }; + + /// A special value used for accessing the mapping_t::thread_t property. + static constexpr thread_t thread; + + /// A special value used for accessing the mapping_t::new_thread_t property. + static constexpr new_thread_t new_thread; + + /// A special value used for accessing the mapping_t::other_t property. + static constexpr other_t other; + + /// Default constructor. + constexpr mapping_t(); + + /// Construct from a sub-property value. + constexpr mapping_t(thread_t); + + /// Construct from a sub-property value. + constexpr mapping_t(new_thread_t); + + /// Construct from a sub-property value. + constexpr mapping_t(other_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const mapping_t& a, const mapping_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const mapping_t& a, const mapping_t& b) noexcept; +}; + +/// A special value used for accessing the mapping_t property. +constexpr mapping_t mapping; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace mapping { + +template <int I> struct thread_t; +template <int I> struct new_thread_t; +template <int I> struct other_t; + +} // namespace mapping + +template <int I = 0> +struct mapping_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + typedef mapping_t polymorphic_query_result_type; + + typedef detail::mapping::thread_t<I> thread_t; + typedef detail::mapping::new_thread_t<I> new_thread_t; + typedef detail::mapping::other_t<I> other_t; + + constexpr mapping_t() + : value_(-1) + { + } + + constexpr mapping_t(thread_t) + : value_(0) + { + } + + constexpr mapping_t(new_thread_t) + : value_(1) + { + } + + constexpr mapping_t(other_t) + : value_(2) + { + } + + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template <typename P> + auto query(P&& p) const + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_member : + traits::query_member<typename proxy<T>::type, mapping_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, mapping_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, thread_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, thread_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, thread_t>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, new_thread_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, thread_t>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, new_thread_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, new_thread_t>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, other_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, thread_t>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, new_thread_t>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, other_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, other_t>::value(); + } + + template <typename E, typename T = decltype(mapping_t::static_query<E>())> + static constexpr const T static_query_v + = mapping_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend constexpr bool operator==( + const mapping_t& a, const mapping_t& b) + { + return a.value_ == b.value_; + } + + friend constexpr bool operator!=( + const mapping_t& a, const mapping_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_mapping_t + { + constexpr convertible_from_mapping_t(mapping_t) {} + }; + + template <typename Executor> + friend constexpr mapping_t query( + const Executor& ex, convertible_from_mapping_t, + enable_if_t< + can_query<const Executor&, thread_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, mapping_t<>::thread_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, thread_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, thread_t()); + } + + template <typename Executor> + friend constexpr mapping_t query( + const Executor& ex, convertible_from_mapping_t, + enable_if_t< + !can_query<const Executor&, thread_t>::value + >* = 0, + enable_if_t< + can_query<const Executor&, new_thread_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept( + is_nothrow_query<const Executor&, mapping_t<>::new_thread_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, new_thread_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, new_thread_t()); + } + + template <typename Executor> + friend constexpr mapping_t query( + const Executor& ex, convertible_from_mapping_t, + enable_if_t< + !can_query<const Executor&, thread_t>::value + >* = 0, + enable_if_t< + !can_query<const Executor&, new_thread_t>::value + >* = 0, + enable_if_t< + can_query<const Executor&, other_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, mapping_t<>::other_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, other_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, other_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(thread_t, thread); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(new_thread_t, new_thread); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(other_t, other); + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T mapping_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I> +const typename mapping_t<I>::thread_t mapping_t<I>::thread; + +template <int I> +const typename mapping_t<I>::new_thread_t mapping_t<I>::new_thread; + +template <int I> +const typename mapping_t<I>::other_t mapping_t<I>::other; + +namespace mapping { + +template <int I = 0> +struct thread_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef mapping_t<I> polymorphic_query_result_type; + + constexpr thread_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename mapping_t<I>::template proxy<T>::type, thread_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename mapping_t<I>::template static_proxy<T>::type, thread_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr thread_t static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::query_free<T, thread_t>::is_valid + >* = 0, + enable_if_t< + !can_query<T, new_thread_t<I>>::value + >* = 0, + enable_if_t< + !can_query<T, other_t<I>>::value + >* = 0) noexcept + { + return thread_t(); + } + + template <typename E, typename T = decltype(thread_t::static_query<E>())> + static constexpr const T static_query_v + = thread_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr mapping_t<I> value() + { + return thread_t(); + } + + friend constexpr bool operator==(const thread_t&, const thread_t&) + { + return true; + } + + friend constexpr bool operator!=(const thread_t&, const thread_t&) + { + return false; + } + + friend constexpr bool operator==(const thread_t&, const new_thread_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const thread_t&, const new_thread_t<I>&) + { + return true; + } + + friend constexpr bool operator==(const thread_t&, const other_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const thread_t&, const other_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T thread_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I = 0> +struct new_thread_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef mapping_t<I> polymorphic_query_result_type; + + constexpr new_thread_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename mapping_t<I>::template proxy<T>::type, new_thread_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename mapping_t<I>::template static_proxy<T>::type, new_thread_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(new_thread_t::static_query<E>())> + static constexpr const T static_query_v = new_thread_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr mapping_t<I> value() + { + return new_thread_t(); + } + + friend constexpr bool operator==(const new_thread_t&, const new_thread_t&) + { + return true; + } + + friend constexpr bool operator!=(const new_thread_t&, const new_thread_t&) + { + return false; + } + + friend constexpr bool operator==(const new_thread_t&, const thread_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const new_thread_t&, const thread_t<I>&) + { + return true; + } + + friend constexpr bool operator==(const new_thread_t&, const other_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const new_thread_t&, const other_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T new_thread_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I> +struct other_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef mapping_t<I> polymorphic_query_result_type; + + constexpr other_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename mapping_t<I>::template proxy<T>::type, other_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename mapping_t<I>::template static_proxy<T>::type, other_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(other_t::static_query<E>())> + static constexpr const T static_query_v = other_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr mapping_t<I> value() + { + return other_t(); + } + + friend constexpr bool operator==(const other_t&, const other_t&) + { + return true; + } + + friend constexpr bool operator!=(const other_t&, const other_t&) + { + return false; + } + + friend constexpr bool operator==(const other_t&, const thread_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const other_t&, const thread_t<I>&) + { + return true; + } + + friend constexpr bool operator==(const other_t&, const new_thread_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const other_t&, const new_thread_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T other_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace mapping +} // namespace detail + +typedef detail::mapping_t<> mapping_t; + +constexpr mapping_t mapping; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +struct is_applicable_property<T, execution::mapping_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::mapping_t::thread_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::mapping_t::new_thread_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::mapping_t::other_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T> +struct query_free_default<T, execution::mapping_t, + enable_if_t< + can_query<T, execution::mapping_t::thread_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::mapping_t::thread_t>::value; + + typedef execution::mapping_t result_type; +}; + +template <typename T> +struct query_free_default<T, execution::mapping_t, + enable_if_t< + !can_query<T, execution::mapping_t::thread_t>::value + && can_query<T, execution::mapping_t::new_thread_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::mapping_t::new_thread_t>::value; + + typedef execution::mapping_t result_type; +}; + +template <typename T> +struct query_free_default<T, execution::mapping_t, + enable_if_t< + !can_query<T, execution::mapping_t::thread_t>::value + && !can_query<T, execution::mapping_t::new_thread_t>::value + && can_query<T, execution::mapping_t::other_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::mapping_t::other_t>::value; + + typedef execution::mapping_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T> +struct static_query<T, execution::mapping_t, + enable_if_t< + execution::detail::mapping_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::mapping_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::mapping_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::mapping_t, + enable_if_t< + !execution::detail::mapping_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::mapping_t<0>:: + query_member<T>::is_valid + && traits::static_query<T, execution::mapping_t::thread_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::mapping_t::thread_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, execution::mapping_t::thread_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::mapping_t, + enable_if_t< + !execution::detail::mapping_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::mapping_t<0>:: + query_member<T>::is_valid + && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid + && traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::mapping_t::new_thread_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, execution::mapping_t::new_thread_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::mapping_t, + enable_if_t< + !execution::detail::mapping_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::mapping_t<0>:: + query_member<T>::is_valid + && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid + && !traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid + && traits::static_query<T, execution::mapping_t::other_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::mapping_t::other_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, execution::mapping_t::other_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::mapping_t::thread_t, + enable_if_t< + execution::detail::mapping::thread_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::mapping::thread_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::mapping::thread_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::mapping_t::thread_t, + enable_if_t< + !execution::detail::mapping::thread_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::mapping::thread_t<0>:: + query_member<T>::is_valid + && !traits::query_free<T, execution::mapping_t::thread_t>::is_valid + && !can_query<T, execution::mapping_t::new_thread_t>::value + && !can_query<T, execution::mapping_t::other_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef execution::mapping_t::thread_t result_type; + + static constexpr result_type value() + { + return result_type(); + } +}; + +template <typename T> +struct static_query<T, execution::mapping_t::new_thread_t, + enable_if_t< + execution::detail::mapping::new_thread_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::mapping::new_thread_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::mapping::new_thread_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::mapping_t::other_t, + enable_if_t< + execution::detail::mapping::other_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::mapping::other_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::mapping::other_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_MAPPING_HPP diff --git a/3rdparty/asio/include/asio/execution/occupancy.hpp b/3rdparty/asio/include/asio/execution/occupancy.hpp new file mode 100644 index 00000000000..c986c88113d --- /dev/null +++ b/3rdparty/asio/include/asio/execution/occupancy.hpp @@ -0,0 +1,184 @@ +// +// execution/occupancy.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_OCCUPANCY_HPP +#define ASIO_EXECUTION_OCCUPANCY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that gives an estimate of the number of execution agents that +/// should occupy the associated execution context. +struct occupancy_t +{ + /// The occupancy_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The occupancy_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The occupancy_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef std::size_t polymorphic_query_result_type; +}; + +/// A special value used for accessing the occupancy_t property. +constexpr occupancy_t occupancy; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template <int I = 0> +struct occupancy_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + typedef std::size_t polymorphic_query_result_type; + + constexpr occupancy_t() + { + } + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, occupancy_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(occupancy_t::static_query<E>())> + static constexpr const T static_query_v = occupancy_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T occupancy_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace detail + +typedef detail::occupancy_t<> occupancy_t; + +constexpr occupancy_t occupancy; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +struct is_applicable_property<T, execution::occupancy_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T> +struct static_query<T, execution::occupancy_t, + enable_if_t< + execution::detail::occupancy_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::occupancy_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::occupancy_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_OCCUPANCY_HPP diff --git a/3rdparty/asio/include/asio/execution/outstanding_work.hpp b/3rdparty/asio/include/asio/execution/outstanding_work.hpp new file mode 100644 index 00000000000..600792b95b4 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/outstanding_work.hpp @@ -0,0 +1,753 @@ +// +// execution/outstanding_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_OUTSTANDING_WORK_HPP +#define ASIO_EXECUTION_OUTSTANDING_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether task submission is likely in the future. +struct outstanding_work_t +{ + /// The outstanding_work_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The top-level outstanding_work_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level outstanding_work_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// A sub-property that indicates that the executor does not represent likely + /// future submission of a function object. + struct untracked_t + { + /// The outstanding_work_t::untracked_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The outstanding_work_t::untracked_t property can be required. + static constexpr bool is_requirable = true; + + /// The outstanding_work_t::untracked_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// Default constructor. + constexpr untracked_t(); + + /// Get the value associated with a property object. + /** + * @returns untracked_t(); + */ + static constexpr outstanding_work_t value(); + }; + + /// A sub-property that indicates that the executor represents likely + /// future submission of a function object. + struct tracked_t + { + /// The outstanding_work_t::untracked_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The outstanding_work_t::tracked_t property can be required. + static constexpr bool is_requirable = true; + + /// The outstanding_work_t::tracked_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// Default constructor. + constexpr tracked_t(); + + /// Get the value associated with a property object. + /** + * @returns tracked_t(); + */ + static constexpr outstanding_work_t value(); + }; + + /// A special value used for accessing the outstanding_work_t::untracked_t + /// property. + static constexpr untracked_t untracked; + + /// A special value used for accessing the outstanding_work_t::tracked_t + /// property. + static constexpr tracked_t tracked; + + /// Default constructor. + constexpr outstanding_work_t(); + + /// Construct from a sub-property value. + constexpr outstanding_work_t(untracked_t); + + /// Construct from a sub-property value. + constexpr outstanding_work_t(tracked_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const outstanding_work_t& a, const outstanding_work_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const outstanding_work_t& a, const outstanding_work_t& b) noexcept; +}; + +/// A special value used for accessing the outstanding_work_t property. +constexpr outstanding_work_t outstanding_work; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace outstanding_work { + +template <int I> struct untracked_t; +template <int I> struct tracked_t; + +} // namespace outstanding_work + +template <int I = 0> +struct outstanding_work_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + typedef outstanding_work_t polymorphic_query_result_type; + + typedef detail::outstanding_work::untracked_t<I> untracked_t; + typedef detail::outstanding_work::tracked_t<I> tracked_t; + + constexpr outstanding_work_t() + : value_(-1) + { + } + + constexpr outstanding_work_t(untracked_t) + : value_(0) + { + } + + constexpr outstanding_work_t(tracked_t) + : value_(1) + { + } + + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template <typename P> + auto query(P&& p) const + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_member : + traits::query_member<typename proxy<T>::type, outstanding_work_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, outstanding_work_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, untracked_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, untracked_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, untracked_t>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, tracked_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, untracked_t>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, tracked_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, tracked_t>::value(); + } + + template <typename E, + typename T = decltype(outstanding_work_t::static_query<E>())> + static constexpr const T static_query_v + = outstanding_work_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend constexpr bool operator==( + const outstanding_work_t& a, const outstanding_work_t& b) + { + return a.value_ == b.value_; + } + + friend constexpr bool operator!=( + const outstanding_work_t& a, const outstanding_work_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_outstanding_work_t + { + constexpr convertible_from_outstanding_work_t(outstanding_work_t) + { + } + }; + + template <typename Executor> + friend constexpr outstanding_work_t query( + const Executor& ex, convertible_from_outstanding_work_t, + enable_if_t< + can_query<const Executor&, untracked_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, + outstanding_work_t<>::untracked_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, untracked_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, untracked_t()); + } + + template <typename Executor> + friend constexpr outstanding_work_t query( + const Executor& ex, convertible_from_outstanding_work_t, + enable_if_t< + !can_query<const Executor&, untracked_t>::value + >* = 0, + enable_if_t< + can_query<const Executor&, tracked_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, + outstanding_work_t<>::tracked_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, tracked_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, tracked_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(untracked_t, untracked); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(tracked_t, tracked); + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T outstanding_work_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I> +const typename outstanding_work_t<I>::untracked_t +outstanding_work_t<I>::untracked; + +template <int I> +const typename outstanding_work_t<I>::tracked_t +outstanding_work_t<I>::tracked; + +namespace outstanding_work { + +template <int I = 0> +struct untracked_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef outstanding_work_t<I> polymorphic_query_result_type; + + constexpr untracked_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename outstanding_work_t<I>::template proxy<T>::type, untracked_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename outstanding_work_t<I>::template static_proxy<T>::type, + untracked_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr untracked_t static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::query_free<T, untracked_t>::is_valid + >* = 0, + enable_if_t< + !can_query<T, tracked_t<I>>::value + >* = 0) noexcept + { + return untracked_t(); + } + + template <typename E, typename T = decltype(untracked_t::static_query<E>())> + static constexpr const T static_query_v = untracked_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr outstanding_work_t<I> value() + { + return untracked_t(); + } + + friend constexpr bool operator==(const untracked_t&, const untracked_t&) + { + return true; + } + + friend constexpr bool operator!=(const untracked_t&, const untracked_t&) + { + return false; + } + + friend constexpr bool operator==(const untracked_t&, const tracked_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const untracked_t&, const tracked_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T untracked_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I = 0> +struct tracked_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef outstanding_work_t<I> polymorphic_query_result_type; + + constexpr tracked_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename outstanding_work_t<I>::template proxy<T>::type, tracked_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename outstanding_work_t<I>::template static_proxy<T>::type, + tracked_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, typename T = decltype(tracked_t::static_query<E>())> + static constexpr const T static_query_v = tracked_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr outstanding_work_t<I> value() + { + return tracked_t(); + } + + friend constexpr bool operator==(const tracked_t&, const tracked_t&) + { + return true; + } + + friend constexpr bool operator!=(const tracked_t&, const tracked_t&) + { + return false; + } + + friend constexpr bool operator==(const tracked_t&, const untracked_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const tracked_t&, const untracked_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T tracked_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace outstanding_work +} // namespace detail + +typedef detail::outstanding_work_t<> outstanding_work_t; + +constexpr outstanding_work_t outstanding_work; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +struct is_applicable_property<T, execution::outstanding_work_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::outstanding_work_t::untracked_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::outstanding_work_t::tracked_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T> +struct query_free_default<T, execution::outstanding_work_t, + enable_if_t< + can_query<T, execution::outstanding_work_t::untracked_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::outstanding_work_t::untracked_t>::value; + + typedef execution::outstanding_work_t result_type; +}; + +template <typename T> +struct query_free_default<T, execution::outstanding_work_t, + enable_if_t< + !can_query<T, execution::outstanding_work_t::untracked_t>::value + && can_query<T, execution::outstanding_work_t::tracked_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::outstanding_work_t::tracked_t>::value; + + typedef execution::outstanding_work_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T> +struct static_query<T, execution::outstanding_work_t, + enable_if_t< + execution::detail::outstanding_work_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::outstanding_work_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::outstanding_work_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::outstanding_work_t, + enable_if_t< + !execution::detail::outstanding_work_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::outstanding_work_t<0>:: + query_member<T>::is_valid + && traits::static_query<T, + execution::outstanding_work_t::untracked_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::outstanding_work_t::untracked_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, + execution::outstanding_work_t::untracked_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::outstanding_work_t, + enable_if_t< + !execution::detail::outstanding_work_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::outstanding_work_t<0>:: + query_member<T>::is_valid + && !traits::static_query<T, + execution::outstanding_work_t::untracked_t>::is_valid + && traits::static_query<T, + execution::outstanding_work_t::tracked_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::outstanding_work_t::tracked_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, + execution::outstanding_work_t::tracked_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::outstanding_work_t::untracked_t, + enable_if_t< + execution::detail::outstanding_work::untracked_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::outstanding_work::untracked_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::outstanding_work::untracked_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::outstanding_work_t::untracked_t, + enable_if_t< + !execution::detail::outstanding_work::untracked_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::outstanding_work::untracked_t<0>:: + query_member<T>::is_valid + && !traits::query_free<T, + execution::outstanding_work_t::untracked_t>::is_valid + && !can_query<T, execution::outstanding_work_t::tracked_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef execution::outstanding_work_t::untracked_t result_type; + + static constexpr result_type value() + { + return result_type(); + } +}; + +template <typename T> +struct static_query<T, execution::outstanding_work_t::tracked_t, + enable_if_t< + execution::detail::outstanding_work::tracked_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::outstanding_work::tracked_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::outstanding_work::tracked_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_OUTSTANDING_WORK_HPP diff --git a/3rdparty/asio/include/asio/execution/prefer_only.hpp b/3rdparty/asio/include/asio/execution/prefer_only.hpp new file mode 100644 index 00000000000..1a990ebf392 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/prefer_only.hpp @@ -0,0 +1,328 @@ +// +// execution/prefer_only.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_PREFER_ONLY_HPP +#define ASIO_EXECUTION_PREFER_ONLY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/prefer.hpp" +#include "asio/query.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property adapter that is used with the polymorphic executor wrapper +/// to mark properties as preferable, but not requirable. +template <typename Property> +struct prefer_only +{ + /// The prefer_only adapter applies to the same types as the nested property. + template <typename T> + static constexpr bool is_applicable_property_v = + is_applicable_property<T, Property>::value; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property can be preferred, it the underlying property can + /// be preferred. + /** + * @c true if @c Property::is_preferable is @c true, otherwise @c false. + */ + static constexpr bool is_preferable = automatically_determined; + + /// The type returned by queries against an @c any_executor. + typedef typename Property::polymorphic_query_result_type + polymorphic_query_result_type; +}; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template <typename InnerProperty, typename = void> +struct prefer_only_is_preferable +{ + static constexpr bool is_preferable = false; +}; + +template <typename InnerProperty> +struct prefer_only_is_preferable<InnerProperty, + enable_if_t< + InnerProperty::is_preferable + > + > +{ + static constexpr bool is_preferable = true; +}; + +template <typename InnerProperty, typename = void> +struct prefer_only_polymorphic_query_result_type +{ +}; + +template <typename InnerProperty> +struct prefer_only_polymorphic_query_result_type<InnerProperty, + void_t< + typename InnerProperty::polymorphic_query_result_type + > + > +{ + typedef typename InnerProperty::polymorphic_query_result_type + polymorphic_query_result_type; +}; + +template <typename InnerProperty, typename = void> +struct prefer_only_property +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } +}; + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +template <typename InnerProperty> +struct prefer_only_property<InnerProperty, + void_t< + decltype(asio::declval<const InnerProperty>().value()) + > + > +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } + + constexpr auto value() const + noexcept(noexcept(asio::declval<const InnerProperty>().value())) + -> decltype(asio::declval<const InnerProperty>().value()) + { + return property.value(); + } +}; + +#else // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +struct prefer_only_memfns_base +{ + void value(); +}; + +template <typename T> +struct prefer_only_memfns_derived + : T, prefer_only_memfns_base +{ +}; + +template <typename T, T> +struct prefer_only_memfns_check +{ +}; + +template <typename> +char (&prefer_only_value_memfn_helper(...))[2]; + +template <typename T> +char prefer_only_value_memfn_helper( + prefer_only_memfns_check< + void (prefer_only_memfns_base::*)(), + &prefer_only_memfns_derived<T>::value>*); + +template <typename InnerProperty> +struct prefer_only_property<InnerProperty, + enable_if_t< + sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1 + && !is_same<typename InnerProperty::polymorphic_query_result_type, + void>::value + > + > +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } + + constexpr typename InnerProperty::polymorphic_query_result_type + value() const + { + return property.value(); + } +}; + +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +} // namespace detail + +template <typename InnerProperty> +struct prefer_only : + detail::prefer_only_is_preferable<InnerProperty>, + detail::prefer_only_polymorphic_query_result_type<InnerProperty>, + detail::prefer_only_property<InnerProperty> +{ + static constexpr bool is_requirable = false; + + constexpr prefer_only(const InnerProperty& p) + : detail::prefer_only_property<InnerProperty>(p) + { + } + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename traits::static_query<T, InnerProperty>::result_type + static_query() + noexcept(traits::static_query<T, InnerProperty>::is_noexcept) + { + return traits::static_query<T, InnerProperty>::value(); + } + + template <typename E, typename T = decltype(prefer_only::static_query<E>())> + static constexpr const T static_query_v + = prefer_only::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template <typename Executor, typename Property> + friend constexpr + prefer_result_t<const Executor&, const InnerProperty&> + prefer(const Executor& ex, const prefer_only<Property>& p, + enable_if_t< + is_same<Property, InnerProperty>::value + >* = 0, + enable_if_t< + can_prefer<const Executor&, const InnerProperty&>::value + >* = 0) +#if !defined(ASIO_MSVC) \ + && !defined(__clang__) // Clang crashes if noexcept is used here. + noexcept(is_nothrow_prefer<const Executor&, const InnerProperty&>::value) +#endif // !defined(ASIO_MSVC) + // && !defined(__clang__) + { + return asio::prefer(ex, p.property); + } + + template <typename Executor, typename Property> + friend constexpr + query_result_t<const Executor&, const InnerProperty&> + query(const Executor& ex, const prefer_only<Property>& p, + enable_if_t< + is_same<Property, InnerProperty>::value + >* = 0, + enable_if_t< + can_query<const Executor&, const InnerProperty&>::value + >* = 0) +#if !defined(ASIO_MSVC) \ + && !defined(__clang__) // Clang crashes if noexcept is used here. + noexcept(is_nothrow_query<const Executor&, const InnerProperty&>::value) +#endif // !defined(ASIO_MSVC) + // && !defined(__clang__) + { + return asio::query(ex, p.property); + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <typename InnerProperty> template <typename E, typename T> +const T prefer_only<InnerProperty>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace execution + +template <typename T, typename InnerProperty> +struct is_applicable_property<T, execution::prefer_only<InnerProperty>> + : is_applicable_property<T, InnerProperty> +{ +}; + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T, typename InnerProperty> +struct static_query<T, execution::prefer_only<InnerProperty>> : + static_query<T, const InnerProperty&> +{ +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template <typename T, typename InnerProperty> +struct prefer_free_default<T, execution::prefer_only<InnerProperty>, + enable_if_t< + can_prefer<const T&, const InnerProperty&>::value + > + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_prefer<const T&, const InnerProperty&>::value; + + typedef prefer_result_t<const T&, const InnerProperty&> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T, typename InnerProperty> +struct query_free<T, execution::prefer_only<InnerProperty>, + enable_if_t< + can_query<const T&, const InnerProperty&>::value + > + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<const T&, const InnerProperty&>::value; + + typedef query_result_t<const T&, const InnerProperty&> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_PREFER_ONLY_HPP diff --git a/3rdparty/asio/include/asio/execution/relationship.hpp b/3rdparty/asio/include/asio/execution/relationship.hpp new file mode 100644 index 00000000000..e4f27555e24 --- /dev/null +++ b/3rdparty/asio/include/asio/execution/relationship.hpp @@ -0,0 +1,751 @@ +// +// execution/relationship.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_EXECUTION_RELATIONSHIP_HPP +#define ASIO_EXECUTION_RELATIONSHIP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/query.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_static_constexpr_member.hpp" +#include "asio/traits/static_query.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether submitted tasks represent continuations of +/// the calling context. +struct relationship_t +{ + /// The relationship_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The top-level relationship_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level relationship_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// A sub-property that indicates that the executor does not represent a + /// continuation of the calling context. + struct fork_t + { + /// The relationship_t::fork_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The relationship_t::fork_t property can be required. + static constexpr bool is_requirable = true; + + /// The relationship_t::fork_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// Default constructor. + constexpr fork_t(); + + /// Get the value associated with a property object. + /** + * @returns fork_t(); + */ + static constexpr relationship_t value(); + }; + + /// A sub-property that indicates that the executor represents a continuation + /// of the calling context. + struct continuation_t + { + /// The relationship_t::continuation_t property applies to executors. + template <typename T> + static constexpr bool is_applicable_property_v = is_executor_v<T>; + + /// The relationship_t::continuation_t property can be required. + static constexpr bool is_requirable = true; + + /// The relationship_t::continuation_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// Default constructor. + constexpr continuation_t(); + + /// Get the value associated with a property object. + /** + * @returns continuation_t(); + */ + static constexpr relationship_t value(); + }; + + /// A special value used for accessing the relationship_t::fork_t property. + static constexpr fork_t fork; + + /// A special value used for accessing the relationship_t::continuation_t + /// property. + static constexpr continuation_t continuation; + + /// Default constructor. + constexpr relationship_t(); + + /// Construct from a sub-property value. + constexpr relationship_t(fork_t); + + /// Construct from a sub-property value. + constexpr relationship_t(continuation_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const relationship_t& a, const relationship_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const relationship_t& a, const relationship_t& b) noexcept; +}; + +/// A special value used for accessing the relationship_t property. +constexpr relationship_t relationship; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace relationship { + +template <int I> struct fork_t; +template <int I> struct continuation_t; + +} // namespace relationship + +template <int I = 0> +struct relationship_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = false; + static constexpr bool is_preferable = false; + typedef relationship_t polymorphic_query_result_type; + + typedef detail::relationship::fork_t<I> fork_t; + typedef detail::relationship::continuation_t<I> continuation_t; + + constexpr relationship_t() + : value_(-1) + { + } + + constexpr relationship_t(fork_t) + : value_(0) + { + } + + constexpr relationship_t(continuation_t) + : value_(1) + { + } + + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template <typename P> + auto query(P&& p) const + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template <typename T> + struct static_proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + struct type + { + template <typename P> + static constexpr auto query(P&& p) + noexcept( + noexcept( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + ) + -> decltype( + conditional_t<true, T, P>::query(static_cast<P&&>(p)) + ) + { + return T::query(static_cast<P&&>(p)); + } + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + }; + + template <typename T> + struct query_member : + traits::query_member<typename proxy<T>::type, relationship_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename static_proxy<T>::type, relationship_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr + typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, fork_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, fork_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, fork_t>::value(); + } + + template <typename T> + static constexpr + typename traits::static_query<T, continuation_t>::result_type + static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::static_query<T, fork_t>::is_valid + >* = 0, + enable_if_t< + traits::static_query<T, continuation_t>::is_valid + >* = 0) noexcept + { + return traits::static_query<T, continuation_t>::value(); + } + + template <typename E, + typename T = decltype(relationship_t::static_query<E>())> + static constexpr const T static_query_v + = relationship_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend constexpr bool operator==( + const relationship_t& a, const relationship_t& b) + { + return a.value_ == b.value_; + } + + friend constexpr bool operator!=( + const relationship_t& a, const relationship_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_relationship_t + { + constexpr convertible_from_relationship_t(relationship_t) + { + } + }; + + template <typename Executor> + friend constexpr relationship_t query( + const Executor& ex, convertible_from_relationship_t, + enable_if_t< + can_query<const Executor&, fork_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, relationship_t<>::fork_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, fork_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, fork_t()); + } + + template <typename Executor> + friend constexpr relationship_t query( + const Executor& ex, convertible_from_relationship_t, + enable_if_t< + !can_query<const Executor&, fork_t>::value + >* = 0, + enable_if_t< + can_query<const Executor&, continuation_t>::value + >* = 0) +#if !defined(__clang__) // Clang crashes if noexcept is used here. +#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified. + noexcept(is_nothrow_query<const Executor&, + relationship_t<>::continuation_t>::value) +#else // defined(ASIO_MSVC) + noexcept(is_nothrow_query<const Executor&, continuation_t>::value) +#endif // defined(ASIO_MSVC) +#endif // !defined(__clang__) + { + return asio::query(ex, continuation_t()); + } + + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(fork_t, fork); + ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(continuation_t, continuation); + +private: + int value_; +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T relationship_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I> +const typename relationship_t<I>::fork_t relationship_t<I>::fork; + +template <int I> +const typename relationship_t<I>::continuation_t +relationship_t<I>::continuation; + +namespace relationship { + +template <int I = 0> +struct fork_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef relationship_t<I> polymorphic_query_result_type; + + constexpr fork_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename relationship_t<I>::template proxy<T>::type, fork_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename relationship_t<I>::template static_proxy<T>::type, fork_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename T> + static constexpr fork_t static_query( + enable_if_t< + !query_static_constexpr_member<T>::is_valid + >* = 0, + enable_if_t< + !query_member<T>::is_valid + >* = 0, + enable_if_t< + !traits::query_free<T, fork_t>::is_valid + >* = 0, + enable_if_t< + !can_query<T, continuation_t<I>>::value + >* = 0) noexcept + { + return fork_t(); + } + + template <typename E, typename T = decltype(fork_t::static_query<E>())> + static constexpr const T static_query_v + = fork_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr relationship_t<I> value() + { + return fork_t(); + } + + friend constexpr bool operator==(const fork_t&, const fork_t&) + { + return true; + } + + friend constexpr bool operator!=(const fork_t&, const fork_t&) + { + return false; + } + + friend constexpr bool operator==(const fork_t&, const continuation_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const fork_t&, const continuation_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T fork_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <int I = 0> +struct continuation_t +{ +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + template <typename T> + static constexpr bool is_applicable_property_v = is_executor<T>::value; +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + typedef relationship_t<I> polymorphic_query_result_type; + + constexpr continuation_t() + { + } + + template <typename T> + struct query_member : + traits::query_member< + typename relationship_t<I>::template proxy<T>::type, continuation_t> {}; + + template <typename T> + struct query_static_constexpr_member : + traits::query_static_constexpr_member< + typename relationship_t<I>::template static_proxy<T>::type, + continuation_t> {}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template <typename T> + static constexpr typename query_static_constexpr_member<T>::result_type + static_query() + noexcept(query_static_constexpr_member<T>::is_noexcept) + { + return query_static_constexpr_member<T>::value(); + } + + template <typename E, + typename T = decltype(continuation_t::static_query<E>())> + static constexpr const T static_query_v + = continuation_t::static_query<E>(); +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static constexpr relationship_t<I> value() + { + return continuation_t(); + } + + friend constexpr bool operator==(const continuation_t&, const continuation_t&) + { + return true; + } + + friend constexpr bool operator!=(const continuation_t&, const continuation_t&) + { + return false; + } + + friend constexpr bool operator==(const continuation_t&, const fork_t<I>&) + { + return false; + } + + friend constexpr bool operator!=(const continuation_t&, const fork_t<I>&) + { + return true; + } +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template <int I> template <typename E, typename T> +const T continuation_t<I>::static_query_v; +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace relationship +} // namespace detail + +typedef detail::relationship_t<> relationship_t; + +constexpr relationship_t relationship; + +} // namespace execution + +#if !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T> +struct is_applicable_property<T, execution::relationship_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::relationship_t::fork_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +template <typename T> +struct is_applicable_property<T, execution::relationship_t::continuation_t> + : integral_constant<bool, execution::is_executor<T>::value> +{ +}; + +#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T> +struct query_free_default<T, execution::relationship_t, + enable_if_t< + can_query<T, execution::relationship_t::fork_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::relationship_t::fork_t>::value; + + typedef execution::relationship_t result_type; +}; + +template <typename T> +struct query_free_default<T, execution::relationship_t, + enable_if_t< + !can_query<T, execution::relationship_t::fork_t>::value + && can_query<T, execution::relationship_t::continuation_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<T, execution::relationship_t::continuation_t>::value; + + typedef execution::relationship_t result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <typename T> +struct static_query<T, execution::relationship_t, + enable_if_t< + execution::detail::relationship_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::relationship_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::relationship_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::relationship_t, + enable_if_t< + !execution::detail::relationship_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::relationship_t<0>:: + query_member<T>::is_valid + && traits::static_query<T, + execution::relationship_t::fork_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::relationship_t::fork_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, + execution::relationship_t::fork_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::relationship_t, + enable_if_t< + !execution::detail::relationship_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::relationship_t<0>:: + query_member<T>::is_valid + && !traits::static_query<T, + execution::relationship_t::fork_t>::is_valid + && traits::static_query<T, + execution::relationship_t::continuation_t>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename traits::static_query<T, + execution::relationship_t::continuation_t>::result_type result_type; + + static constexpr result_type value() + { + return traits::static_query<T, + execution::relationship_t::continuation_t>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::relationship_t::fork_t, + enable_if_t< + execution::detail::relationship::fork_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::relationship::fork_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::relationship::fork_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +template <typename T> +struct static_query<T, execution::relationship_t::fork_t, + enable_if_t< + !execution::detail::relationship::fork_t<0>:: + query_static_constexpr_member<T>::is_valid + && !execution::detail::relationship::fork_t<0>:: + query_member<T>::is_valid + && !traits::query_free<T, + execution::relationship_t::fork_t>::is_valid + && !can_query<T, execution::relationship_t::continuation_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef execution::relationship_t::fork_t result_type; + + static constexpr result_type value() + { + return result_type(); + } +}; + +template <typename T> +struct static_query<T, execution::relationship_t::continuation_t, + enable_if_t< + execution::detail::relationship::continuation_t<0>:: + query_static_constexpr_member<T>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + + typedef typename execution::detail::relationship::continuation_t<0>:: + query_static_constexpr_member<T>::result_type result_type; + + static constexpr result_type value() + { + return execution::detail::relationship::continuation_t<0>:: + query_static_constexpr_member<T>::value(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXECUTION_RELATIONSHIP_HPP diff --git a/3rdparty/asio/include/asio/execution_context.hpp b/3rdparty/asio/include/asio/execution_context.hpp index 0d91195410e..bce8d431607 100644 --- a/3rdparty/asio/include/asio/execution_context.hpp +++ b/3rdparty/asio/include/asio/execution_context.hpp @@ -2,7 +2,7 @@ // execution_context.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,7 +20,6 @@ #include <stdexcept> #include <typeinfo> #include "asio/detail/noncopyable.hpp" -#include "asio/detail/variadic_templates.hpp" #include "asio/detail/push_options.hpp" @@ -109,13 +108,14 @@ public: class id; class service; -protected: +public: /// Constructor. ASIO_DECL execution_context(); /// Destructor. ASIO_DECL ~execution_context(); +protected: /// Shuts down all services in the context. /** * This function is implemented as follows: @@ -223,8 +223,6 @@ public: template <typename Service> friend Service& use_service(io_context& ioc); -#if defined(GENERATING_DOCUMENTATION) - /// Creates a service object and adds it to the execution_context. /** * This function is used to add a service to the execution_context. @@ -240,27 +238,6 @@ public: template <typename Service, typename... Args> friend Service& make_service(execution_context& e, Args&&... args); -#elif defined(ASIO_HAS_VARIADIC_TEMPLATES) - - template <typename Service, typename... Args> - friend Service& make_service(execution_context& e, - ASIO_MOVE_ARG(Args)... args); - -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - - template <typename Service> - friend Service& make_service(execution_context& e); - -#define ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ - template <typename Service, ASIO_VARIADIC_TPARAMS(n)> \ - friend Service& make_service(execution_context& e, \ - ASIO_VARIADIC_MOVE_PARAMS(n)); \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_MAKE_SERVICE_DEF) -#undef ASIO_PRIVATE_MAKE_SERVICE_DEF - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) - /// (Deprecated: Use make_service().) Add a service object to the /// execution_context. /** diff --git a/3rdparty/asio/include/asio/executor.hpp b/3rdparty/asio/include/asio/executor.hpp index f22b99191f6..c056525460a 100644 --- a/3rdparty/asio/include/asio/executor.hpp +++ b/3rdparty/asio/include/asio/executor.hpp @@ -2,7 +2,7 @@ // executor.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,8 +16,13 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_TS_EXECUTORS) + +#include <new> #include <typeinfo> #include "asio/detail/cstddef.hpp" +#include "asio/detail/executor_function.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/throw_exception.hpp" #include "asio/execution_context.hpp" @@ -32,11 +37,11 @@ class bad_executor { public: /// Constructor. - ASIO_DECL bad_executor() ASIO_NOEXCEPT; + ASIO_DECL bad_executor() noexcept; /// Obtain message associated with exception. ASIO_DECL virtual const char* what() const - ASIO_NOEXCEPT_OR_NOTHROW; + noexcept; }; /// Polymorphic wrapper for executors. @@ -44,36 +49,53 @@ class executor { public: /// Default constructor. - executor() ASIO_NOEXCEPT + executor() noexcept : impl_(0) { } /// Construct from nullptr. - executor(nullptr_t) ASIO_NOEXCEPT + executor(nullptr_t) noexcept : impl_(0) { } /// Copy constructor. - executor(const executor& other) ASIO_NOEXCEPT + executor(const executor& other) noexcept : impl_(other.clone()) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. - executor(executor&& other) ASIO_NOEXCEPT + executor(executor&& other) noexcept : impl_(other.impl_) { other.impl_ = 0; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Construct a polymorphic wrapper for the specified executor. template <typename Executor> executor(Executor e); + /// Construct a polymorphic executor that points to the same target as + /// another polymorphic executor. + executor(std::nothrow_t, const executor& other) noexcept + : impl_(other.clone()) + { + } + + /// Construct a polymorphic executor that moves the target from another + /// polymorphic executor. + executor(std::nothrow_t, executor&& other) noexcept + : impl_(other.impl_) + { + other.impl_ = 0; + } + + /// Construct a polymorphic wrapper for the specified executor. + template <typename Executor> + executor(std::nothrow_t, Executor e) noexcept; + /// Allocator-aware constructor to create a polymorphic wrapper for the /// specified executor. template <typename Executor, typename Allocator> @@ -86,26 +108,24 @@ public: } /// Assignment operator. - executor& operator=(const executor& other) ASIO_NOEXCEPT + executor& operator=(const executor& other) noexcept { destroy(); impl_ = other.clone(); return *this; } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) // Move assignment operator. - executor& operator=(executor&& other) ASIO_NOEXCEPT + executor& operator=(executor&& other) noexcept { destroy(); impl_ = other.impl_; other.impl_ = 0; return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Assignment operator for nullptr_t. - executor& operator=(nullptr_t) ASIO_NOEXCEPT + executor& operator=(nullptr_t) noexcept { destroy(); impl_ = 0; @@ -115,9 +135,9 @@ public: /// Assignment operator to create a polymorphic wrapper for the specified /// executor. template <typename Executor> - executor& operator=(ASIO_MOVE_ARG(Executor) e) ASIO_NOEXCEPT + executor& operator=(Executor&& e) noexcept { - executor tmp(ASIO_MOVE_CAST(Executor)(e)); + executor tmp(static_cast<Executor&&>(e)); destroy(); impl_ = tmp.impl_; tmp.impl_ = 0; @@ -125,19 +145,19 @@ public: } /// Obtain the underlying execution context. - execution_context& context() const ASIO_NOEXCEPT + execution_context& context() const noexcept { return get_impl()->context(); } /// Inform the executor that it has some outstanding work to do. - void on_work_started() const ASIO_NOEXCEPT + void on_work_started() const noexcept { get_impl()->on_work_started(); } /// Inform the executor that some work is no longer outstanding. - void on_work_finished() const ASIO_NOEXCEPT + void on_work_finished() const noexcept { get_impl()->on_work_finished(); } @@ -156,7 +176,7 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + void dispatch(Function&& f, const Allocator& a) const; /// Request the executor to invoke the given function object. /** @@ -172,7 +192,7 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + void post(Function&& f, const Allocator& a) const; /// Request the executor to invoke the given function object. /** @@ -188,14 +208,14 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + void defer(Function&& f, const Allocator& a) const; struct unspecified_bool_type_t {}; typedef void (*unspecified_bool_type)(unspecified_bool_type_t); static void unspecified_bool_true(unspecified_bool_type_t) {} /// Operator to test if the executor contains a valid target. - operator unspecified_bool_type() const ASIO_NOEXCEPT + operator unspecified_bool_type() const noexcept { return impl_ ? &executor::unspecified_bool_true : 0; } @@ -206,12 +226,12 @@ public: * otherwise, <tt>typeid(void)</tt>. */ #if !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) - const std::type_info& target_type() const ASIO_NOEXCEPT + const std::type_info& target_type() const noexcept { return impl_ ? impl_->target_type() : typeid(void); } #else // !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) - const void* target_type() const ASIO_NOEXCEPT + const void* target_type() const noexcept { return impl_ ? impl_->target_type() : 0; } @@ -223,7 +243,7 @@ public: * executor target; otherwise, a null pointer. */ template <typename Executor> - Executor* target() ASIO_NOEXCEPT; + Executor* target() noexcept; /// Obtain a pointer to the target executor object. /** @@ -231,11 +251,11 @@ public: * executor target; otherwise, a null pointer. */ template <typename Executor> - const Executor* target() const ASIO_NOEXCEPT; + const Executor* target() const noexcept; /// Compare two executors for equality. friend bool operator==(const executor& a, - const executor& b) ASIO_NOEXCEPT + const executor& b) noexcept { if (a.impl_ == b.impl_) return true; @@ -246,14 +266,14 @@ public: /// Compare two executors for inequality. friend bool operator!=(const executor& a, - const executor& b) ASIO_NOEXCEPT + const executor& b) noexcept { return !(a == b); } private: #if !defined(GENERATING_DOCUMENTATION) - class function; + typedef detail::executor_function function; template <typename, typename> class impl; #if !defined(ASIO_NO_TYPEID) @@ -277,18 +297,18 @@ private: class impl_base { public: - virtual impl_base* clone() const ASIO_NOEXCEPT = 0; - virtual void destroy() ASIO_NOEXCEPT = 0; - virtual execution_context& context() ASIO_NOEXCEPT = 0; - virtual void on_work_started() ASIO_NOEXCEPT = 0; - virtual void on_work_finished() ASIO_NOEXCEPT = 0; - virtual void dispatch(ASIO_MOVE_ARG(function)) = 0; - virtual void post(ASIO_MOVE_ARG(function)) = 0; - virtual void defer(ASIO_MOVE_ARG(function)) = 0; - virtual type_id_result_type target_type() const ASIO_NOEXCEPT = 0; - virtual void* target() ASIO_NOEXCEPT = 0; - virtual const void* target() const ASIO_NOEXCEPT = 0; - virtual bool equals(const impl_base* e) const ASIO_NOEXCEPT = 0; + virtual impl_base* clone() const noexcept = 0; + virtual void destroy() noexcept = 0; + virtual execution_context& context() noexcept = 0; + virtual void on_work_started() noexcept = 0; + virtual void on_work_finished() noexcept = 0; + virtual void dispatch(function&&) = 0; + virtual void post(function&&) = 0; + virtual void defer(function&&) = 0; + virtual type_id_result_type target_type() const noexcept = 0; + virtual void* target() noexcept = 0; + virtual const void* target() const noexcept = 0; + virtual bool equals(const impl_base* e) const noexcept = 0; protected: impl_base(bool fast_dispatch) : fast_dispatch_(fast_dispatch) {} @@ -311,13 +331,13 @@ private: } // Helper function to clone another implementation. - impl_base* clone() const ASIO_NOEXCEPT + impl_base* clone() const noexcept { return impl_ ? impl_->clone() : 0; } // Helper function to destroy an implementation. - void destroy() ASIO_NOEXCEPT + void destroy() noexcept { if (impl_) impl_->destroy(); @@ -338,4 +358,6 @@ ASIO_USES_ALLOCATOR(asio::executor) # include "asio/impl/executor.ipp" #endif // defined(ASIO_HEADER_ONLY) +#endif // !defined(ASIO_NO_TS_EXECUTORS) + #endif // ASIO_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/executor_work_guard.hpp b/3rdparty/asio/include/asio/executor_work_guard.hpp index a791dcd41f3..72787ccdc83 100644 --- a/3rdparty/asio/include/asio/executor_work_guard.hpp +++ b/3rdparty/asio/include/asio/executor_work_guard.hpp @@ -1,8 +1,8 @@ // // executor_work_guard.hpp -// ~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,16 +16,28 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" + #include "asio/associated_executor.hpp" #include "asio/detail/type_traits.hpp" +#include "asio/execution.hpp" #include "asio/is_executor.hpp" #include "asio/detail/push_options.hpp" namespace asio { -/// An object of type @c executor_work_guard controls ownership of executor work -/// within a scope. +#if !defined(ASIO_EXECUTOR_WORK_GUARD_DECL) +#define ASIO_EXECUTOR_WORK_GUARD_DECL + +template <typename Executor, typename = void, typename = void> +class executor_work_guard; + +#endif // !defined(ASIO_EXECUTOR_WORK_GUARD_DECL) + +#if defined(GENERATING_DOCUMENTATION) + +/// An object of type @c executor_work_guard controls ownership of outstanding +/// executor work within a scope. template <typename Executor> class executor_work_guard { @@ -37,15 +49,58 @@ public: /** * Stores a copy of @c e and calls <tt>on_work_started()</tt> on it. */ - explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT + explicit executor_work_guard(const executor_type& e) noexcept; + + /// Copy constructor. + executor_work_guard(const executor_work_guard& other) noexcept; + + /// Move constructor. + executor_work_guard(executor_work_guard&& other) noexcept; + + /// Destructor. + /** + * Unless the object has already been reset, or is in a moved-from state, + * calls <tt>on_work_finished()</tt> on the stored executor. + */ + ~executor_work_guard(); + + /// Obtain the associated executor. + executor_type get_executor() const noexcept; + + /// Whether the executor_work_guard object owns some outstanding work. + bool owns_work() const noexcept; + + /// Indicate that the work is no longer outstanding. + /** + * Unless the object has already been reset, or is in a moved-from state, + * calls <tt>on_work_finished()</tt> on the stored executor. + */ + void reset() noexcept; +}; + +#endif // defined(GENERATING_DOCUMENTATION) + +#if !defined(GENERATING_DOCUMENTATION) + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor> +class executor_work_guard<Executor, + enable_if_t< + is_executor<Executor>::value + >> +{ +public: + typedef Executor executor_type; + + explicit executor_work_guard(const executor_type& e) noexcept : executor_(e), owns_(true) { executor_.on_work_started(); } - /// Copy constructor. - executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT + executor_work_guard(const executor_work_guard& other) noexcept : executor_(other.executor_), owns_(other.owns_) { @@ -53,45 +108,30 @@ public: executor_.on_work_started(); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move constructor. - executor_work_guard(executor_work_guard&& other) - : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)), + executor_work_guard(executor_work_guard&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)), owns_(other.owns_) { other.owns_ = false; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Destructor. - /** - * Unless the object has already been reset, or is in a moved-from state, - * calls <tt>on_work_finished()</tt> on the stored executor. - */ ~executor_work_guard() { if (owns_) executor_.on_work_finished(); } - /// Obtain the associated executor. - executor_type get_executor() const ASIO_NOEXCEPT + executor_type get_executor() const noexcept { return executor_; } - /// Whether the executor_work_guard object owns some outstanding work. - bool owns_work() const ASIO_NOEXCEPT + bool owns_work() const noexcept { return owns_; } - /// Indicate that the work is no longer outstanding. - /* - * Unless the object has already been reset, or is in a moved-from state, - * calls <tt>on_work_finished()</tt> on the stored executor. - */ - void reset() ASIO_NOEXCEPT + void reset() noexcept { if (owns_) { @@ -108,56 +148,209 @@ private: bool owns_; }; +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor> +class executor_work_guard<Executor, + enable_if_t< + !is_executor<Executor>::value + >, + enable_if_t< + execution::is_executor<Executor>::value + >> +{ +public: + typedef Executor executor_type; + + explicit executor_work_guard(const executor_type& e) noexcept + : executor_(e), + owns_(true) + { + new (&work_) work_type(asio::prefer(executor_, + execution::outstanding_work.tracked)); + } + + executor_work_guard(const executor_work_guard& other) noexcept + : executor_(other.executor_), + owns_(other.owns_) + { + if (owns_) + { + new (&work_) work_type(asio::prefer(executor_, + execution::outstanding_work.tracked)); + } + } + + executor_work_guard(executor_work_guard&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)), + owns_(other.owns_) + { + if (owns_) + { + new (&work_) work_type( + static_cast<work_type&&>( + *static_cast<work_type*>( + static_cast<void*>(&other.work_)))); + other.owns_ = false; + } + } + + ~executor_work_guard() + { + if (owns_) + static_cast<work_type*>(static_cast<void*>(&work_))->~work_type(); + } + + executor_type get_executor() const noexcept + { + return executor_; + } + + bool owns_work() const noexcept + { + return owns_; + } + + void reset() noexcept + { + if (owns_) + { + static_cast<work_type*>(static_cast<void*>(&work_))->~work_type(); + owns_ = false; + } + } + +private: + // Disallow assignment. + executor_work_guard& operator=(const executor_work_guard&); + + typedef decay_t< + prefer_result_t< + const executor_type&, + execution::outstanding_work_t::tracked_t + > + > work_type; + + executor_type executor_; + aligned_storage_t<sizeof(work_type), alignment_of<work_type>::value> work_; + bool owns_; +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + /// Create an @ref executor_work_guard object. +/** + * @param ex An executor. + * + * @returns A work guard constructed with the specified executor. + */ template <typename Executor> -inline executor_work_guard<Executor> make_work_guard(const Executor& ex, - typename enable_if<is_executor<Executor>::value>::type* = 0) +ASIO_NODISCARD inline executor_work_guard<Executor> +make_work_guard(const Executor& ex, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) { return executor_work_guard<Executor>(ex); } /// Create an @ref executor_work_guard object. +/** + * @param ctx An execution context, from which an executor will be obtained. + * + * @returns A work guard constructed with the execution context's executor, + * obtained by performing <tt>ctx.get_executor()</tt>. + */ template <typename ExecutionContext> -inline executor_work_guard<typename ExecutionContext::executor_type> +ASIO_NODISCARD inline +executor_work_guard<typename ExecutionContext::executor_type> make_work_guard(ExecutionContext& ctx, - typename enable_if< - is_convertible<ExecutionContext&, execution_context&>::value>::type* = 0) + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) { return executor_work_guard<typename ExecutionContext::executor_type>( ctx.get_executor()); } /// Create an @ref executor_work_guard object. +/** + * @param t An arbitrary object, such as a completion handler, for which the + * associated executor will be obtained. + * + * @returns A work guard constructed with the associated executor of the object + * @c t, which is obtained as if by calling <tt>get_associated_executor(t)</tt>. + */ template <typename T> -inline executor_work_guard<typename associated_executor<T>::type> -make_work_guard(const T& t, - typename enable_if<!is_executor<T>::value && - !is_convertible<T&, execution_context&>::value>::type* = 0) +ASIO_NODISCARD inline +executor_work_guard< + typename constraint_t< + !is_executor<T>::value + && !execution::is_executor<T>::value + && !is_convertible<T&, execution_context&>::value, + associated_executor<T> + >::type> +make_work_guard(const T& t) { - return executor_work_guard<typename associated_executor<T>::type>( + return executor_work_guard<associated_executor_t<T>>( associated_executor<T>::get(t)); } /// Create an @ref executor_work_guard object. +/** + * @param t An arbitrary object, such as a completion handler, for which the + * associated executor will be obtained. + * + * @param ex An executor to be used as the candidate object when determining the + * associated executor. + * + * @returns A work guard constructed with the associated executor of the object + * @c t, which is obtained as if by calling <tt>get_associated_executor(t, + * ex)</tt>. + */ template <typename T, typename Executor> -inline executor_work_guard<typename associated_executor<T, Executor>::type> +ASIO_NODISCARD inline +executor_work_guard<associated_executor_t<T, Executor>> make_work_guard(const T& t, const Executor& ex, - typename enable_if<is_executor<Executor>::value>::type* = 0) + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) { - return executor_work_guard<typename associated_executor<T, Executor>::type>( + return executor_work_guard<associated_executor_t<T, Executor>>( associated_executor<T, Executor>::get(t, ex)); } /// Create an @ref executor_work_guard object. +/** + * @param t An arbitrary object, such as a completion handler, for which the + * associated executor will be obtained. + * + * @param ctx An execution context, from which an executor is obtained to use as + * the candidate object for determining the associated executor. + * + * @returns A work guard constructed with the associated executor of the object + * @c t, which is obtained as if by calling <tt>get_associated_executor(t, + * ctx.get_executor())</tt>. + */ template <typename T, typename ExecutionContext> -inline executor_work_guard<typename associated_executor<T, - typename ExecutionContext::executor_type>::type> +ASIO_NODISCARD inline executor_work_guard< + associated_executor_t<T, typename ExecutionContext::executor_type>> make_work_guard(const T& t, ExecutionContext& ctx, - typename enable_if<!is_executor<T>::value && - !is_convertible<T&, execution_context&>::value>::type* = 0) + constraint_t< + !is_executor<T>::value + > = 0, + constraint_t< + !execution::is_executor<T>::value + > = 0, + constraint_t< + !is_convertible<T&, execution_context&>::value + > = 0, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) { - return executor_work_guard<typename associated_executor<T, - typename ExecutionContext::executor_type>::type>( + return executor_work_guard< + associated_executor_t<T, typename ExecutionContext::executor_type>>( associated_executor<T, typename ExecutionContext::executor_type>::get( t, ctx.get_executor())); } diff --git a/3rdparty/asio/include/asio/experimental/append.hpp b/3rdparty/asio/include/asio/experimental/append.hpp new file mode 100644 index 00000000000..6a1f280cdd9 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/append.hpp @@ -0,0 +1,36 @@ +// +// experimental/append.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_APPEND_HPP +#define ASIO_EXPERIMENTAL_APPEND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/append.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +#if !defined(ASIO_NO_DEPRECATED) +using asio::append_t; +using asio::append; +#endif // !defined(ASIO_NO_DEPRECATED) + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_APPEND_HPP diff --git a/3rdparty/asio/include/asio/experimental/as_single.hpp b/3rdparty/asio/include/asio/experimental/as_single.hpp new file mode 100644 index 00000000000..6282c14f142 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/as_single.hpp @@ -0,0 +1,132 @@ +// +// experimental/as_single.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_AS_SINGLE_HPP +#define ASIO_EXPERIMENTAL_AS_SINGLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +/// A @ref completion_token adapter used to specify that the completion handler +/// arguments should be combined into a single argument. +/** + * The as_single_t class is used to indicate that any arguments to the + * completion handler should be combined and passed as a single argument. + * If there is already one argument, that argument is passed as-is. If + * there is more than argument, the arguments are first moved into a + * @c std::tuple and that tuple is then passed to the completion handler. + */ +template <typename CompletionToken> +class as_single_t +{ +public: + /// Tag type used to prevent the "default" constructor from being used for + /// conversions. + struct default_constructor_tag {}; + + /// Default constructor. + /** + * This constructor is only valid if the underlying completion token is + * default constructible and move constructible. The underlying completion + * token is itself defaulted as an argument to allow it to capture a source + * location. + */ + constexpr as_single_t( + default_constructor_tag = default_constructor_tag(), + CompletionToken token = CompletionToken()) + : token_(static_cast<CompletionToken&&>(token)) + { + } + + /// Constructor. + template <typename T> + constexpr explicit as_single_t( + T&& completion_token) + : token_(static_cast<T&&>(completion_token)) + { + } + + /// Adapts an executor to add the @c as_single_t completion token as the + /// default. + template <typename InnerExecutor> + struct executor_with_default : InnerExecutor + { + /// Specify @c as_single_t as the default completion token type. + typedef as_single_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + executor_with_default(const InnerExecutor& ex) noexcept + : InnerExecutor(ex) + { + } + + /// Convert the specified executor to the inner executor type, then use + /// that to construct the adapted executor. + template <typename OtherExecutor> + executor_with_default(const OtherExecutor& ex, + constraint_t< + is_convertible<OtherExecutor, InnerExecutor>::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c as_single_t as its + /// default completion token type. + template <typename T> + using as_default_on_t = typename T::template rebind_executor< + executor_with_default<typename T::executor_type>>::other; + + /// Function helper to adapt an I/O object to use @c as_single_t as its + /// default completion token type. + template <typename T> + static typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other(static_cast<T&&>(object)); + } + +//private: + CompletionToken token_; +}; + +/// Adapt a @ref completion_token to specify that the completion handler +/// arguments should be combined into a single argument. +template <typename CompletionToken> +ASIO_NODISCARD inline +constexpr as_single_t<decay_t<CompletionToken>> +as_single(CompletionToken&& completion_token) +{ + return as_single_t<decay_t<CompletionToken>>( + static_cast<CompletionToken&&>(completion_token)); +} + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/as_single.hpp" + +#endif // ASIO_EXPERIMENTAL_AS_SINGLE_HPP diff --git a/3rdparty/asio/include/asio/experimental/as_tuple.hpp b/3rdparty/asio/include/asio/experimental/as_tuple.hpp new file mode 100644 index 00000000000..02f23f2909b --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/as_tuple.hpp @@ -0,0 +1,36 @@ +// +// experimental/as_tuple.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_AS_TUPLE_HPP +#define ASIO_EXPERIMENTAL_AS_TUPLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/as_tuple.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +#if !defined(ASIO_NO_DEPRECATED) +using asio::as_tuple_t; +using asio::as_tuple; +#endif // !defined(ASIO_NO_DEPRECATED) + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_AS_TUPLE_HPP diff --git a/3rdparty/asio/include/asio/experimental/awaitable_operators.hpp b/3rdparty/asio/include/asio/experimental/awaitable_operators.hpp new file mode 100644 index 00000000000..45799daaa5f --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/awaitable_operators.hpp @@ -0,0 +1,536 @@ +// +// experimental/awaitable_operators.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_AWAITABLE_OPERATORS_HPP +#define ASIO_EXPERIMENTAL_AWAITABLE_OPERATORS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <optional> +#include <stdexcept> +#include <tuple> +#include <variant> +#include "asio/awaitable.hpp" +#include "asio/co_spawn.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/experimental/deferred.hpp" +#include "asio/experimental/parallel_group.hpp" +#include "asio/multiple_exceptions.hpp" +#include "asio/this_coro.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace awaitable_operators { +namespace detail { + +template <typename T, typename Executor> +awaitable<T, Executor> awaitable_wrap(awaitable<T, Executor> a, + constraint_t<is_constructible<T>::value>* = 0) +{ + return a; +} + +template <typename T, typename Executor> +awaitable<std::optional<T>, Executor> awaitable_wrap(awaitable<T, Executor> a, + constraint_t<!is_constructible<T>::value>* = 0) +{ + co_return std::optional<T>(co_await std::move(a)); +} + +template <typename T> +T& awaitable_unwrap(conditional_t<true, T, void>& r, + constraint_t<is_constructible<T>::value>* = 0) +{ + return r; +} + +template <typename T> +T& awaitable_unwrap(std::optional<conditional_t<true, T, void>>& r, + constraint_t<!is_constructible<T>::value>* = 0) +{ + return *r; +} + +} // namespace detail + +/// Wait for both operations to succeed. +/** + * If one operations fails, the other is cancelled as the AND-condition can no + * longer be satisfied. + */ +template <typename Executor> +awaitable<void, Executor> operator&&( + awaitable<void, Executor> t, awaitable<void, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, ex1] = + co_await make_parallel_group( + co_spawn(ex, std::move(t), deferred), + co_spawn(ex, std::move(u), deferred) + ).async_wait( + wait_for_one_error(), + deferred + ); + + if (ex0 && ex1) + throw multiple_exceptions(ex0); + if (ex0) + std::rethrow_exception(ex0); + if (ex1) + std::rethrow_exception(ex1); + co_return; +} + +/// Wait for both operations to succeed. +/** + * If one operations fails, the other is cancelled as the AND-condition can no + * longer be satisfied. + */ +template <typename U, typename Executor> +awaitable<U, Executor> operator&&( + awaitable<void, Executor> t, awaitable<U, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, ex1, r1] = + co_await make_parallel_group( + co_spawn(ex, std::move(t), deferred), + co_spawn(ex, detail::awaitable_wrap(std::move(u)), deferred) + ).async_wait( + wait_for_one_error(), + deferred + ); + + if (ex0 && ex1) + throw multiple_exceptions(ex0); + if (ex0) + std::rethrow_exception(ex0); + if (ex1) + std::rethrow_exception(ex1); + co_return std::move(detail::awaitable_unwrap<U>(r1)); +} + +/// Wait for both operations to succeed. +/** + * If one operations fails, the other is cancelled as the AND-condition can no + * longer be satisfied. + */ +template <typename T, typename Executor> +awaitable<T, Executor> operator&&( + awaitable<T, Executor> t, awaitable<void, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, std::move(u), deferred) + ).async_wait( + wait_for_one_error(), + deferred + ); + + if (ex0 && ex1) + throw multiple_exceptions(ex0); + if (ex0) + std::rethrow_exception(ex0); + if (ex1) + std::rethrow_exception(ex1); + co_return std::move(detail::awaitable_unwrap<T>(r0)); +} + +/// Wait for both operations to succeed. +/** + * If one operations fails, the other is cancelled as the AND-condition can no + * longer be satisfied. + */ +template <typename T, typename U, typename Executor> +awaitable<std::tuple<T, U>, Executor> operator&&( + awaitable<T, Executor> t, awaitable<U, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1, r1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, detail::awaitable_wrap(std::move(u)), deferred) + ).async_wait( + wait_for_one_error(), + deferred + ); + + if (ex0 && ex1) + throw multiple_exceptions(ex0); + if (ex0) + std::rethrow_exception(ex0); + if (ex1) + std::rethrow_exception(ex1); + co_return std::make_tuple( + std::move(detail::awaitable_unwrap<T>(r0)), + std::move(detail::awaitable_unwrap<U>(r1))); +} + +/// Wait for both operations to succeed. +/** + * If one operations fails, the other is cancelled as the AND-condition can no + * longer be satisfied. + */ +template <typename... T, typename Executor> +awaitable<std::tuple<T..., std::monostate>, Executor> operator&&( + awaitable<std::tuple<T...>, Executor> t, awaitable<void, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1, r1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, std::move(u), deferred) + ).async_wait( + wait_for_one_error(), + deferred + ); + + if (ex0 && ex1) + throw multiple_exceptions(ex0); + if (ex0) + std::rethrow_exception(ex0); + if (ex1) + std::rethrow_exception(ex1); + co_return std::move(detail::awaitable_unwrap<std::tuple<T...>>(r0)); +} + +/// Wait for both operations to succeed. +/** + * If one operations fails, the other is cancelled as the AND-condition can no + * longer be satisfied. + */ +template <typename... T, typename U, typename Executor> +awaitable<std::tuple<T..., U>, Executor> operator&&( + awaitable<std::tuple<T...>, Executor> t, awaitable<U, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1, r1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, detail::awaitable_wrap(std::move(u)), deferred) + ).async_wait( + wait_for_one_error(), + deferred + ); + + if (ex0 && ex1) + throw multiple_exceptions(ex0); + if (ex0) + std::rethrow_exception(ex0); + if (ex1) + std::rethrow_exception(ex1); + co_return std::tuple_cat( + std::move(detail::awaitable_unwrap<std::tuple<T...>>(r0)), + std::make_tuple(std::move(detail::awaitable_unwrap<U>(r1)))); +} + +/// Wait for one operation to succeed. +/** + * If one operations succeeds, the other is cancelled as the OR-condition is + * already satisfied. + */ +template <typename Executor> +awaitable<std::variant<std::monostate, std::monostate>, Executor> operator||( + awaitable<void, Executor> t, awaitable<void, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, ex1] = + co_await make_parallel_group( + co_spawn(ex, std::move(t), deferred), + co_spawn(ex, std::move(u), deferred) + ).async_wait( + wait_for_one_success(), + deferred + ); + + if (order[0] == 0) + { + if (!ex0) + co_return std::variant<std::monostate, std::monostate>{ + std::in_place_index<0>}; + if (!ex1) + co_return std::variant<std::monostate, std::monostate>{ + std::in_place_index<1>}; + throw multiple_exceptions(ex0); + } + else + { + if (!ex1) + co_return std::variant<std::monostate, std::monostate>{ + std::in_place_index<1>}; + if (!ex0) + co_return std::variant<std::monostate, std::monostate>{ + std::in_place_index<0>}; + throw multiple_exceptions(ex1); + } +} + +/// Wait for one operation to succeed. +/** + * If one operations succeeds, the other is cancelled as the OR-condition is + * already satisfied. + */ +template <typename U, typename Executor> +awaitable<std::variant<std::monostate, U>, Executor> operator||( + awaitable<void, Executor> t, awaitable<U, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, ex1, r1] = + co_await make_parallel_group( + co_spawn(ex, std::move(t), deferred), + co_spawn(ex, detail::awaitable_wrap(std::move(u)), deferred) + ).async_wait( + wait_for_one_success(), + deferred + ); + + if (order[0] == 0) + { + if (!ex0) + co_return std::variant<std::monostate, U>{ + std::in_place_index<0>}; + if (!ex1) + co_return std::variant<std::monostate, U>{ + std::in_place_index<1>, + std::move(detail::awaitable_unwrap<U>(r1))}; + throw multiple_exceptions(ex0); + } + else + { + if (!ex1) + co_return std::variant<std::monostate, U>{ + std::in_place_index<1>, + std::move(detail::awaitable_unwrap<U>(r1))}; + if (!ex0) + co_return std::variant<std::monostate, U>{ + std::in_place_index<0>}; + throw multiple_exceptions(ex1); + } +} + +/// Wait for one operation to succeed. +/** + * If one operations succeeds, the other is cancelled as the OR-condition is + * already satisfied. + */ +template <typename T, typename Executor> +awaitable<std::variant<T, std::monostate>, Executor> operator||( + awaitable<T, Executor> t, awaitable<void, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, std::move(u), deferred) + ).async_wait( + wait_for_one_success(), + deferred + ); + + if (order[0] == 0) + { + if (!ex0) + co_return std::variant<T, std::monostate>{ + std::in_place_index<0>, + std::move(detail::awaitable_unwrap<T>(r0))}; + if (!ex1) + co_return std::variant<T, std::monostate>{ + std::in_place_index<1>}; + throw multiple_exceptions(ex0); + } + else + { + if (!ex1) + co_return std::variant<T, std::monostate>{ + std::in_place_index<1>}; + if (!ex0) + co_return std::variant<T, std::monostate>{ + std::in_place_index<0>, + std::move(detail::awaitable_unwrap<T>(r0))}; + throw multiple_exceptions(ex1); + } +} + +/// Wait for one operation to succeed. +/** + * If one operations succeeds, the other is cancelled as the OR-condition is + * already satisfied. + */ +template <typename T, typename U, typename Executor> +awaitable<std::variant<T, U>, Executor> operator||( + awaitable<T, Executor> t, awaitable<U, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1, r1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, detail::awaitable_wrap(std::move(u)), deferred) + ).async_wait( + wait_for_one_success(), + deferred + ); + + if (order[0] == 0) + { + if (!ex0) + co_return std::variant<T, U>{ + std::in_place_index<0>, + std::move(detail::awaitable_unwrap<T>(r0))}; + if (!ex1) + co_return std::variant<T, U>{ + std::in_place_index<1>, + std::move(detail::awaitable_unwrap<U>(r1))}; + throw multiple_exceptions(ex0); + } + else + { + if (!ex1) + co_return std::variant<T, U>{ + std::in_place_index<1>, + std::move(detail::awaitable_unwrap<U>(r1))}; + if (!ex0) + co_return std::variant<T, U>{ + std::in_place_index<0>, + std::move(detail::awaitable_unwrap<T>(r0))}; + throw multiple_exceptions(ex1); + } +} + +namespace detail { + +template <typename... T> +struct widen_variant +{ + template <std::size_t I, typename SourceVariant> + static std::variant<T...> call(SourceVariant& source) + { + if (source.index() == I) + return std::variant<T...>{ + std::in_place_index<I>, std::move(std::get<I>(source))}; + else if constexpr (I + 1 < std::variant_size_v<SourceVariant>) + return call<I + 1>(source); + else + throw std::logic_error("empty variant"); + } +}; + +} // namespace detail + +/// Wait for one operation to succeed. +/** + * If one operations succeeds, the other is cancelled as the OR-condition is + * already satisfied. + */ +template <typename... T, typename Executor> +awaitable<std::variant<T..., std::monostate>, Executor> operator||( + awaitable<std::variant<T...>, Executor> t, awaitable<void, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, std::move(u), deferred) + ).async_wait( + wait_for_one_success(), + deferred + ); + + using widen = detail::widen_variant<T..., std::monostate>; + if (order[0] == 0) + { + if (!ex0) + co_return widen::template call<0>( + detail::awaitable_unwrap<std::variant<T...>>(r0)); + if (!ex1) + co_return std::variant<T..., std::monostate>{ + std::in_place_index<sizeof...(T)>}; + throw multiple_exceptions(ex0); + } + else + { + if (!ex1) + co_return std::variant<T..., std::monostate>{ + std::in_place_index<sizeof...(T)>}; + if (!ex0) + co_return widen::template call<0>( + detail::awaitable_unwrap<std::variant<T...>>(r0)); + throw multiple_exceptions(ex1); + } +} + +/// Wait for one operation to succeed. +/** + * If one operations succeeds, the other is cancelled as the OR-condition is + * already satisfied. + */ +template <typename... T, typename U, typename Executor> +awaitable<std::variant<T..., U>, Executor> operator||( + awaitable<std::variant<T...>, Executor> t, awaitable<U, Executor> u) +{ + auto ex = co_await this_coro::executor; + + auto [order, ex0, r0, ex1, r1] = + co_await make_parallel_group( + co_spawn(ex, detail::awaitable_wrap(std::move(t)), deferred), + co_spawn(ex, detail::awaitable_wrap(std::move(u)), deferred) + ).async_wait( + wait_for_one_success(), + deferred + ); + + using widen = detail::widen_variant<T..., U>; + if (order[0] == 0) + { + if (!ex0) + co_return widen::template call<0>( + detail::awaitable_unwrap<std::variant<T...>>(r0)); + if (!ex1) + co_return std::variant<T..., U>{ + std::in_place_index<sizeof...(T)>, + std::move(detail::awaitable_unwrap<U>(r1))}; + throw multiple_exceptions(ex0); + } + else + { + if (!ex1) + co_return std::variant<T..., U>{ + std::in_place_index<sizeof...(T)>, + std::move(detail::awaitable_unwrap<U>(r1))}; + if (!ex0) + co_return widen::template call<0>( + detail::awaitable_unwrap<std::variant<T...>>(r0)); + throw multiple_exceptions(ex1); + } +} + +} // namespace awaitable_operators +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_AWAITABLE_OPERATORS_HPP diff --git a/3rdparty/asio/include/asio/experimental/basic_channel.hpp b/3rdparty/asio/include/asio/experimental/basic_channel.hpp new file mode 100644 index 00000000000..6ca1438a093 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/basic_channel.hpp @@ -0,0 +1,513 @@ +// +// experimental/basic_channel.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BASIC_CHANNEL_HPP +#define ASIO_EXPERIMENTAL_BASIC_CHANNEL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/null_mutex.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/experimental/detail/channel_send_functions.hpp" +#include "asio/experimental/detail/channel_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +} // namespace detail + +/// A channel for messages. +/** + * The basic_channel class template is used for sending messages between + * different parts of the same application. A <em>message</em> is defined as a + * collection of arguments to be passed to a completion handler, and the set of + * messages supported by a channel is specified by its @c Traits and + * <tt>Signatures...</tt> template parameters. Messages may be sent and received + * using asynchronous or non-blocking synchronous operations. + * + * Unless customising the traits, applications will typically use the @c + * experimental::channel alias template. For example: + * @code void send_loop(int i, steady_timer& timer, + * channel<void(error_code, int)>& ch) + * { + * if (i < 10) + * { + * timer.expires_after(chrono::seconds(1)); + * timer.async_wait( + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * ch.async_send(error_code(), i, + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * send_loop(i + 1, timer, ch); + * } + * }); + * } + * }); + * } + * else + * { + * ch.close(); + * } + * } + * + * void receive_loop(channel<void(error_code, int)>& ch) + * { + * ch.async_receive( + * [&ch](error_code error, int i) + * { + * if (!error) + * { + * std::cout << "Received " << i << "\n"; + * receive_loop(ch); + * } + * }); + * } @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * The basic_channel class template is not thread-safe, and would typically be + * used for passing messages between application code that runs on the same + * thread or in the same strand. Consider using @ref basic_concurrent_channel, + * and its alias template @c experimental::concurrent_channel, to pass messages + * between code running in different threads. + */ +template <typename Executor, typename Traits, typename... Signatures> +class basic_channel +#if !defined(GENERATING_DOCUMENTATION) + : public detail::channel_send_functions< + basic_channel<Executor, Traits, Signatures...>, + Executor, Signatures...> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +private: + class initiate_async_send; + class initiate_async_receive; + typedef detail::channel_service<asio::detail::null_mutex> service_type; + typedef typename service_type::template implementation_type< + Traits, Signatures...>::payload_type payload_type; + + template <typename... PayloadSignatures, + ASIO_COMPLETION_TOKEN_FOR(PayloadSignatures...) CompletionToken> + auto do_async_receive(detail::channel_payload<PayloadSignatures...>*, + CompletionToken&& token) + -> decltype( + async_initiate<CompletionToken, PayloadSignatures...>( + declval<initiate_async_receive>(), token)) + { + return async_initiate<CompletionToken, PayloadSignatures...>( + initiate_async_receive(this), token); + } + +public: + /// The type of the executor associated with the channel. + typedef Executor executor_type; + + /// Rebinds the channel type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The channel type when rebound to the specified executor. + typedef basic_channel<Executor1, Traits, Signatures...> other; + }; + + /// The traits type associated with the channel. + typedef typename Traits::template rebind<Signatures...>::other traits_type; + + /// Construct a basic_channel. + /** + * This constructor creates and channel. + * + * @param ex The I/O executor that the channel will use, by default, to + * dispatch handlers for any asynchronous operations performed on the channel. + * + * @param max_buffer_size The maximum number of messages that may be buffered + * in the channel. + */ + basic_channel(const executor_type& ex, std::size_t max_buffer_size = 0) + : service_(&asio::use_service<service_type>( + basic_channel::get_context(ex))), + impl_(), + executor_(ex) + { + service_->construct(impl_, max_buffer_size); + } + + /// Construct and open a basic_channel. + /** + * This constructor creates and opens a channel. + * + * @param context An execution context which provides the I/O executor that + * the channel will use, by default, to dispatch handlers for any asynchronous + * operations performed on the channel. + * + * @param max_buffer_size The maximum number of messages that may be buffered + * in the channel. + */ + template <typename ExecutionContext> + basic_channel(ExecutionContext& context, std::size_t max_buffer_size = 0, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : service_(&asio::use_service<service_type>(context)), + impl_(), + executor_(context.get_executor()) + { + service_->construct(impl_, max_buffer_size); + } + + /// Move-construct a basic_channel from another. + /** + * This constructor moves a channel from one object to another. + * + * @param other The other basic_channel object from which the move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_channel(const executor_type&) constructor. + */ + basic_channel(basic_channel&& other) + : service_(other.service_), + executor_(other.executor_) + { + service_->move_construct(impl_, other.impl_); + } + + /// Move-assign a basic_channel from another. + /** + * This assignment operator moves a channel from one object to another. + * Cancels any outstanding asynchronous operations associated with the target + * object. + * + * @param other The other basic_channel object from which the move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_channel(const executor_type&) + * constructor. + */ + basic_channel& operator=(basic_channel&& other) + { + if (this != &other) + { + service_->move_assign(impl_, *other.service_, other.impl_); + executor_.~executor_type(); + new (&executor_) executor_type(other.executor_); + service_ = other.service_; + } + return *this; + } + + // All channels have access to each other's implementations. + template <typename, typename, typename...> + friend class basic_channel; + + /// Move-construct a basic_channel from another. + /** + * This constructor moves a channel from one object to another. + * + * @param other The other basic_channel object from which the move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_channel(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_channel( + basic_channel<Executor1, Traits, Signatures...>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value + > = 0) + : service_(other.service_), + executor_(other.executor_) + { + service_->move_construct(impl_, other.impl_); + } + + /// Move-assign a basic_channel from another. + /** + * This assignment operator moves a channel from one object to another. + * Cancels any outstanding asynchronous operations associated with the target + * object. + * + * @param other The other basic_channel object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_channel(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_channel& + > operator=(basic_channel<Executor1, Traits, Signatures...>&& other) + { + if (this != &other) + { + service_->move_assign(impl_, *other.service_, other.impl_); + executor_.~executor_type(); + new (&executor_) executor_type(other.executor_); + service_ = other.service_; + } + return *this; + } + + /// Destructor. + ~basic_channel() + { + service_->destroy(impl_); + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return executor_; + } + + /// Get the capacity of the channel's buffer. + std::size_t capacity() noexcept + { + return service_->capacity(impl_); + } + + /// Determine whether the channel is open. + bool is_open() const noexcept + { + return service_->is_open(impl_); + } + + /// Reset the channel to its initial state. + void reset() + { + service_->reset(impl_); + } + + /// Close the channel. + void close() + { + service_->close(impl_); + } + + /// Cancel all asynchronous operations waiting on the channel. + /** + * All outstanding send operations will complete with the error + * @c asio::experimental::error::channel_cancelled. Outstanding receive + * operations complete with the result as determined by the channel traits. + */ + void cancel() + { + service_->cancel(impl_); + } + + /// Determine whether a message can be received without blocking. + bool ready() const noexcept + { + return service_->ready(impl_); + } + +#if defined(GENERATING_DOCUMENTATION) + + /// Try to send a message without blocking. + /** + * Fails if the buffer is full and there are no waiting receive operations. + * + * @returns @c true on success, @c false on failure. + */ + template <typename... Args> + bool try_send(Args&&... args); + + /// Try to send a message without blocking, using dispatch semantics to call + /// the receive operation's completion handler. + /** + * Fails if the buffer is full and there are no waiting receive operations. + * + * The receive operation's completion handler may be called from inside this + * function. + * + * @returns @c true on success, @c false on failure. + */ + template <typename... Args> + bool try_send_via_dispatch(Args&&... args); + + /// Try to send a number of messages without blocking. + /** + * @returns The number of messages that were sent. + */ + template <typename... Args> + std::size_t try_send_n(std::size_t count, Args&&... args); + + /// Try to send a number of messages without blocking, using dispatch + /// semantics to call the receive operations' completion handlers. + /** + * The receive operations' completion handlers may be called from inside this + * function. + * + * @returns The number of messages that were sent. + */ + template <typename... Args> + std::size_t try_send_n_via_dispatch(std::size_t count, Args&&... args); + + /// Asynchronously send a message. + /** + * @par Completion Signature + * @code void(asio::error_code) @endcode + */ + template <typename... Args, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + CompletionToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + auto async_send(Args&&... args, + CompletionToken&& token); + +#endif // defined(GENERATING_DOCUMENTATION) + + /// Try to receive a message without blocking. + /** + * Fails if the buffer is full and there are no waiting receive operations. + * + * @returns @c true on success, @c false on failure. + */ + template <typename Handler> + bool try_receive(Handler&& handler) + { + return service_->try_receive(impl_, static_cast<Handler&&>(handler)); + } + + /// Asynchronously receive a message. + /** + * @par Completion Signature + * As determined by the <tt>Signatures...</tt> template parameter and the + * channel traits. + */ + template <typename CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + auto async_receive( + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor)) +#if !defined(GENERATING_DOCUMENTATION) + -> decltype( + this->do_async_receive(static_cast<payload_type*>(0), + static_cast<CompletionToken&&>(token))) +#endif // !defined(GENERATING_DOCUMENTATION) + { + return this->do_async_receive(static_cast<payload_type*>(0), + static_cast<CompletionToken&&>(token)); + } + +private: + // Disallow copying and assignment. + basic_channel(const basic_channel&) = delete; + basic_channel& operator=(const basic_channel&) = delete; + + template <typename, typename, typename...> + friend class detail::channel_send_functions; + + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<execution::is_executor<T>::value>* = 0) + { + return asio::query(t, execution::context); + } + + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<!execution::is_executor<T>::value>* = 0) + { + return t.context(); + } + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_channel* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename SendHandler> + void operator()(SendHandler&& handler, + payload_type&& payload) const + { + asio::detail::non_const_lvalue<SendHandler> handler2(handler); + self_->service_->async_send(self_->impl_, + static_cast<payload_type&&>(payload), + handler2.value, self_->get_executor()); + } + + private: + basic_channel* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_channel* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReceiveHandler> + void operator()(ReceiveHandler&& handler) const + { + asio::detail::non_const_lvalue<ReceiveHandler> handler2(handler); + self_->service_->async_receive(self_->impl_, + handler2.value, self_->get_executor()); + } + + private: + basic_channel* self_; + }; + + // The service associated with the I/O object. + service_type* service_; + + // The underlying implementation of the I/O object. + typename service_type::template implementation_type< + Traits, Signatures...> impl_; + + // The associated executor. + Executor executor_; +}; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_BASIC_CHANNEL_HPP diff --git a/3rdparty/asio/include/asio/experimental/basic_concurrent_channel.hpp b/3rdparty/asio/include/asio/experimental/basic_concurrent_channel.hpp new file mode 100644 index 00000000000..9dbfea39527 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/basic_concurrent_channel.hpp @@ -0,0 +1,513 @@ +// +// experimental/basic_concurrent_channel.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_BASIC_CONCURRENT_CHANNEL_HPP +#define ASIO_EXPERIMENTAL_BASIC_CONCURRENT_CHANNEL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution_context.hpp" +#include "asio/experimental/detail/channel_send_functions.hpp" +#include "asio/experimental/detail/channel_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +} // namespace detail + +/// A channel for messages. +/** + * The basic_concurrent_channel class template is used for sending messages + * between different parts of the same application. A <em>message</em> is + * defined as a collection of arguments to be passed to a completion handler, + * and the set of messages supported by a channel is specified by its @c Traits + * and <tt>Signatures...</tt> template parameters. Messages may be sent and + * received using asynchronous or non-blocking synchronous operations. + * + * Unless customising the traits, applications will typically use the @c + * experimental::concurrent_channel alias template. For example: + * @code void send_loop(int i, steady_timer& timer, + * concurrent_channel<void(error_code, int)>& ch) + * { + * if (i < 10) + * { + * timer.expires_after(chrono::seconds(1)); + * timer.async_wait( + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * ch.async_send(error_code(), i, + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * send_loop(i + 1, timer, ch); + * } + * }); + * } + * }); + * } + * else + * { + * ch.close(); + * } + * } + * + * void receive_loop(concurent_channel<void(error_code, int)>& ch) + * { + * ch.async_receive( + * [&ch](error_code error, int i) + * { + * if (!error) + * { + * std::cout << "Received " << i << "\n"; + * receive_loop(ch); + * } + * }); + * } @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * The basic_concurrent_channel class template is thread-safe, and would + * typically be used for passing messages between application code that run on + * different threads. Consider using @ref basic_channel, and its alias template + * @c experimental::channel, to pass messages between code running in a single + * thread or on the same strand. + */ +template <typename Executor, typename Traits, typename... Signatures> +class basic_concurrent_channel +#if !defined(GENERATING_DOCUMENTATION) + : public detail::channel_send_functions< + basic_concurrent_channel<Executor, Traits, Signatures...>, + Executor, Signatures...> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +private: + class initiate_async_send; + class initiate_async_receive; + typedef detail::channel_service<asio::detail::mutex> service_type; + typedef typename service_type::template implementation_type< + Traits, Signatures...>::payload_type payload_type; + + template <typename... PayloadSignatures, + ASIO_COMPLETION_TOKEN_FOR(PayloadSignatures...) CompletionToken> + auto do_async_receive(detail::channel_payload<PayloadSignatures...>*, + CompletionToken&& token) + -> decltype( + async_initiate<CompletionToken, PayloadSignatures...>( + declval<initiate_async_receive>(), token)) + { + return async_initiate<CompletionToken, PayloadSignatures...>( + initiate_async_receive(this), token); + } + +public: + /// The type of the executor associated with the channel. + typedef Executor executor_type; + + /// Rebinds the channel type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The channel type when rebound to the specified executor. + typedef basic_concurrent_channel<Executor1, Traits, Signatures...> other; + }; + + /// The traits type associated with the channel. + typedef typename Traits::template rebind<Signatures...>::other traits_type; + + /// Construct a basic_concurrent_channel. + /** + * This constructor creates and channel. + * + * @param ex The I/O executor that the channel will use, by default, to + * dispatch handlers for any asynchronous operations performed on the channel. + * + * @param max_buffer_size The maximum number of messages that may be buffered + * in the channel. + */ + basic_concurrent_channel(const executor_type& ex, + std::size_t max_buffer_size = 0) + : service_(&asio::use_service<service_type>( + basic_concurrent_channel::get_context(ex))), + impl_(), + executor_(ex) + { + service_->construct(impl_, max_buffer_size); + } + + /// Construct and open a basic_concurrent_channel. + /** + * This constructor creates and opens a channel. + * + * @param context An execution context which provides the I/O executor that + * the channel will use, by default, to dispatch handlers for any asynchronous + * operations performed on the channel. + * + * @param max_buffer_size The maximum number of messages that may be buffered + * in the channel. + */ + template <typename ExecutionContext> + basic_concurrent_channel(ExecutionContext& context, + std::size_t max_buffer_size = 0, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : service_(&asio::use_service<service_type>(context)), + impl_(), + executor_(context.get_executor()) + { + service_->construct(impl_, max_buffer_size); + } + + /// Move-construct a basic_concurrent_channel from another. + /** + * This constructor moves a channel from one object to another. + * + * @param other The other basic_concurrent_channel object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_concurrent_channel(const executor_type&) + * constructor. + */ + basic_concurrent_channel(basic_concurrent_channel&& other) + : service_(other.service_), + executor_(other.executor_) + { + service_->move_construct(impl_, other.impl_); + } + + /// Move-assign a basic_concurrent_channel from another. + /** + * This assignment operator moves a channel from one object to another. + * Cancels any outstanding asynchronous operations associated with the target + * object. + * + * @param other The other basic_concurrent_channel object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_concurrent_channel(const executor_type&) + * constructor. + */ + basic_concurrent_channel& operator=(basic_concurrent_channel&& other) + { + if (this != &other) + { + service_->move_assign(impl_, *other.service_, other.impl_); + executor_.~executor_type(); + new (&executor_) executor_type(other.executor_); + service_ = other.service_; + } + return *this; + } + + // All channels have access to each other's implementations. + template <typename, typename, typename...> + friend class basic_concurrent_channel; + + /// Move-construct a basic_concurrent_channel from another. + /** + * This constructor moves a channel from one object to another. + * + * @param other The other basic_concurrent_channel object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_concurrent_channel(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_concurrent_channel( + basic_concurrent_channel<Executor1, Traits, Signatures...>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value + > = 0) + : service_(other.service_), + executor_(other.executor_) + { + service_->move_construct(impl_, other.impl_); + } + + /// Move-assign a basic_concurrent_channel from another. + /** + * This assignment operator moves a channel from one object to another. + * Cancels any outstanding asynchronous operations associated with the target + * object. + * + * @param other The other basic_concurrent_channel object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_concurrent_channel(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_concurrent_channel& + > operator=( + basic_concurrent_channel<Executor1, Traits, Signatures...>&& other) + { + if (this != &other) + { + service_->move_assign(impl_, *other.service_, other.impl_); + executor_.~executor_type(); + new (&executor_) executor_type(other.executor_); + service_ = other.service_; + } + return *this; + } + + /// Destructor. + ~basic_concurrent_channel() + { + service_->destroy(impl_); + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return executor_; + } + + /// Get the capacity of the channel's buffer. + std::size_t capacity() noexcept + { + return service_->capacity(impl_); + } + + /// Determine whether the channel is open. + bool is_open() const noexcept + { + return service_->is_open(impl_); + } + + /// Reset the channel to its initial state. + void reset() + { + service_->reset(impl_); + } + + /// Close the channel. + void close() + { + service_->close(impl_); + } + + /// Cancel all asynchronous operations waiting on the channel. + /** + * All outstanding send operations will complete with the error + * @c asio::experimental::error::channel_cancelled. Outstanding receive + * operations complete with the result as determined by the channel traits. + */ + void cancel() + { + service_->cancel(impl_); + } + + /// Determine whether a message can be received without blocking. + bool ready() const noexcept + { + return service_->ready(impl_); + } + +#if defined(GENERATING_DOCUMENTATION) + + /// Try to send a message without blocking. + /** + * Fails if the buffer is full and there are no waiting receive operations. + * + * @returns @c true on success, @c false on failure. + */ + template <typename... Args> + bool try_send(Args&&... args); + + /// Try to send a message without blocking, using dispatch semantics to call + /// the receive operation's completion handler. + /** + * Fails if the buffer is full and there are no waiting receive operations. + * + * The receive operation's completion handler may be called from inside this + * function. + * + * @returns @c true on success, @c false on failure. + */ + template <typename... Args> + bool try_send_via_dispatch(Args&&... args); + + /// Try to send a number of messages without blocking. + /** + * @returns The number of messages that were sent. + */ + template <typename... Args> + std::size_t try_send_n(std::size_t count, Args&&... args); + + /// Try to send a number of messages without blocking, using dispatch + /// semantics to call the receive operations' completion handlers. + /** + * The receive operations' completion handlers may be called from inside this + * function. + * + * @returns The number of messages that were sent. + */ + template <typename... Args> + std::size_t try_send_n_via_dispatch(std::size_t count, Args&&... args); + + /// Asynchronously send a message. + template <typename... Args, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + CompletionToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + auto async_send(Args&&... args, + CompletionToken&& token); + +#endif // defined(GENERATING_DOCUMENTATION) + + /// Try to receive a message without blocking. + /** + * Fails if the buffer is full and there are no waiting receive operations. + * + * @returns @c true on success, @c false on failure. + */ + template <typename Handler> + bool try_receive(Handler&& handler) + { + return service_->try_receive(impl_, static_cast<Handler&&>(handler)); + } + + /// Asynchronously receive a message. + template <typename CompletionToken + ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + auto async_receive( + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor)) +#if !defined(GENERATING_DOCUMENTATION) + -> decltype( + this->do_async_receive(static_cast<payload_type*>(0), + static_cast<CompletionToken&&>(token))) +#endif // !defined(GENERATING_DOCUMENTATION) + { + return this->do_async_receive(static_cast<payload_type*>(0), + static_cast<CompletionToken&&>(token)); + } + +private: + // Disallow copying and assignment. + basic_concurrent_channel( + const basic_concurrent_channel&) = delete; + basic_concurrent_channel& operator=( + const basic_concurrent_channel&) = delete; + + template <typename, typename, typename...> + friend class detail::channel_send_functions; + + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<execution::is_executor<T>::value>* = 0) + { + return asio::query(t, execution::context); + } + + // Helper function to get an executor's context. + template <typename T> + static execution_context& get_context(const T& t, + enable_if_t<!execution::is_executor<T>::value>* = 0) + { + return t.context(); + } + + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_concurrent_channel* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename SendHandler> + void operator()(SendHandler&& handler, + payload_type&& payload) const + { + asio::detail::non_const_lvalue<SendHandler> handler2(handler); + self_->service_->async_send(self_->impl_, + static_cast<payload_type&&>(payload), + handler2.value, self_->get_executor()); + } + + private: + basic_concurrent_channel* self_; + }; + + class initiate_async_receive + { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_concurrent_channel* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReceiveHandler> + void operator()(ReceiveHandler&& handler) const + { + asio::detail::non_const_lvalue<ReceiveHandler> handler2(handler); + self_->service_->async_receive(self_->impl_, + handler2.value, self_->get_executor()); + } + + private: + basic_concurrent_channel* self_; + }; + + // The service associated with the I/O object. + service_type* service_; + + // The underlying implementation of the I/O object. + typename service_type::template implementation_type< + Traits, Signatures...> impl_; + + // The associated executor. + Executor executor_; +}; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_BASIC_CONCURRENT_CHANNEL_HPP diff --git a/3rdparty/asio/include/asio/experimental/cancellation_condition.hpp b/3rdparty/asio/include/asio/experimental/cancellation_condition.hpp new file mode 100644 index 00000000000..6b1b46dd759 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/cancellation_condition.hpp @@ -0,0 +1,152 @@ +// +// experimental/cancellation_condition.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CANCELLATION_CONDITION_HPP +#define ASIO_EXPERIMENTAL_CANCELLATION_CONDITION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <exception> +#include "asio/cancellation_type.hpp" +#include "asio/error_code.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +/// Wait for all operations to complete. +class wait_for_all +{ +public: + template <typename... Args> + constexpr cancellation_type_t operator()(Args&&...) const noexcept + { + return cancellation_type::none; + } +}; + +/// Wait until an operation completes, then cancel the others. +class wait_for_one +{ +public: + constexpr explicit wait_for_one( + cancellation_type_t cancel_type = cancellation_type::all) + : cancel_type_(cancel_type) + { + } + + template <typename... Args> + constexpr cancellation_type_t operator()(Args&&...) const noexcept + { + return cancel_type_; + } + +private: + cancellation_type_t cancel_type_; +}; + +/// Wait until an operation completes without an error, then cancel the others. +/** + * If no operation completes without an error, waits for completion of all + * operations. + */ +class wait_for_one_success +{ +public: + constexpr explicit wait_for_one_success( + cancellation_type_t cancel_type = cancellation_type::all) + : cancel_type_(cancel_type) + { + } + + constexpr cancellation_type_t + operator()() const noexcept + { + return cancel_type_; + } + + template <typename E, typename... Args> + constexpr constraint_t< + !is_same<decay_t<E>, asio::error_code>::value + && !is_same<decay_t<E>, std::exception_ptr>::value, + cancellation_type_t + > operator()(const E&, Args&&...) const noexcept + { + return cancel_type_; + } + + template <typename E, typename... Args> + constexpr constraint_t< + is_same<decay_t<E>, asio::error_code>::value + || is_same<decay_t<E>, std::exception_ptr>::value, + cancellation_type_t + > operator()(const E& e, Args&&...) const noexcept + { + return !!e ? cancellation_type::none : cancel_type_; + } + +private: + cancellation_type_t cancel_type_; +}; + +/// Wait until an operation completes with an error, then cancel the others. +/** + * If no operation completes with an error, waits for completion of all + * operations. + */ +class wait_for_one_error +{ +public: + constexpr explicit wait_for_one_error( + cancellation_type_t cancel_type = cancellation_type::all) + : cancel_type_(cancel_type) + { + } + + constexpr cancellation_type_t operator()() const noexcept + { + return cancellation_type::none; + } + + template <typename E, typename... Args> + constexpr constraint_t< + !is_same<decay_t<E>, asio::error_code>::value + && !is_same<decay_t<E>, std::exception_ptr>::value, + cancellation_type_t + > operator()(const E&, Args&&...) const noexcept + { + return cancellation_type::none; + } + + template <typename E, typename... Args> + constexpr constraint_t< + is_same<decay_t<E>, asio::error_code>::value + || is_same<decay_t<E>, std::exception_ptr>::value, + cancellation_type_t + > operator()(const E& e, Args&&...) const noexcept + { + return !!e ? cancel_type_ : cancellation_type::none; + } + +private: + cancellation_type_t cancel_type_; +}; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_CANCELLATION_CONDITION_HPP diff --git a/3rdparty/asio/include/asio/experimental/channel.hpp b/3rdparty/asio/include/asio/experimental/channel.hpp new file mode 100644 index 00000000000..c808bb4aafd --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/channel.hpp @@ -0,0 +1,70 @@ +// +// experimental/channel.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CHANNEL_HPP +#define ASIO_EXPERIMENTAL_CHANNEL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_executor.hpp" +#include "asio/experimental/basic_channel.hpp" +#include "asio/experimental/channel_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename ExecutorOrSignature, typename = void> +struct channel_type +{ + template <typename... Signatures> + struct inner + { + typedef basic_channel<any_io_executor, channel_traits<>, + ExecutorOrSignature, Signatures...> type; + }; +}; + +template <typename ExecutorOrSignature> +struct channel_type<ExecutorOrSignature, + enable_if_t< + is_executor<ExecutorOrSignature>::value + || execution::is_executor<ExecutorOrSignature>::value + >> +{ + template <typename... Signatures> + struct inner + { + typedef basic_channel<ExecutorOrSignature, + channel_traits<>, Signatures...> type; + }; +}; + +} // namespace detail + +/// Template type alias for common use of channel. +template <typename ExecutorOrSignature, typename... Signatures> +using channel = typename detail::channel_type< + ExecutorOrSignature>::template inner<Signatures...>::type; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_CHANNEL_HPP diff --git a/3rdparty/asio/include/asio/experimental/channel_error.hpp b/3rdparty/asio/include/asio/experimental/channel_error.hpp new file mode 100644 index 00000000000..dd419757cc3 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/channel_error.hpp @@ -0,0 +1,82 @@ +// +// experimental/channel_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CHANNEL_ERROR_HPP +#define ASIO_EXPERIMENTAL_CHANNEL_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace error { + +enum channel_errors +{ + /// The channel was closed. + channel_closed = 1, + + /// The channel was cancelled. + channel_cancelled = 2 +}; + +extern ASIO_DECL +const asio::error_category& get_channel_category(); + +static const asio::error_category& + channel_category ASIO_UNUSED_VARIABLE + = asio::experimental::error::get_channel_category(); + +} // namespace error +namespace channel_errc { + // Simulates a scoped enum. + using error::channel_closed; + using error::channel_cancelled; +} // namespace channel_errc +} // namespace experimental +} // namespace asio + +namespace std { + +template<> struct is_error_code_enum< + asio::experimental::error::channel_errors> +{ + static const bool value = true; +}; + +} // namespace std + +namespace asio { +namespace experimental { +namespace error { + +inline asio::error_code make_error_code(channel_errors e) +{ + return asio::error_code( + static_cast<int>(e), get_channel_category()); +} + +} // namespace error +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/experimental/impl/channel_error.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_EXPERIMENTAL_CHANNEL_ERROR_HPP diff --git a/3rdparty/asio/include/asio/experimental/channel_traits.hpp b/3rdparty/asio/include/asio/experimental/channel_traits.hpp new file mode 100644 index 00000000000..bccff9876e4 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/channel_traits.hpp @@ -0,0 +1,301 @@ +// +// experimental/channel_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CHANNEL_TRAITS_HPP +#define ASIO_EXPERIMENTAL_CHANNEL_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <deque> +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/experimental/channel_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +#if defined(GENERATING_DOCUMENTATION) + +template <typename... Signatures> +struct channel_traits +{ + /// Rebind the traits to a new set of signatures. + /** + * This nested structure must have a single nested type @c other that + * aliases a traits type with the specified set of signatures. + */ + template <typename... NewSignatures> + struct rebind + { + typedef user_defined other; + }; + + /// Determine the container for the specified elements. + /** + * This nested structure must have a single nested type @c other that + * aliases a container type for the specified element type. + */ + template <typename Element> + struct container + { + typedef user_defined type; + }; + + /// The signature of a channel cancellation notification. + typedef void receive_cancelled_signature(...); + + /// Invoke the specified handler with a cancellation notification. + template <typename F> + static void invoke_receive_cancelled(F f); + + /// The signature of a channel closed notification. + typedef void receive_closed_signature(...); + + /// Invoke the specified handler with a closed notification. + template <typename F> + static void invoke_receive_closed(F f); +}; + +#else // defined(GENERATING_DOCUMENTATION) + +/// Traits used for customising channel behaviour. +template <typename... Signatures> +struct channel_traits +{ + template <typename... NewSignatures> + struct rebind + { + typedef channel_traits<NewSignatures...> other; + }; +}; + +template <typename R> +struct channel_traits<R(asio::error_code)> +{ + template <typename... NewSignatures> + struct rebind + { + typedef channel_traits<NewSignatures...> other; + }; + + template <typename Element> + struct container + { + typedef std::deque<Element> type; + }; + + typedef R receive_cancelled_signature(asio::error_code); + + template <typename F> + static void invoke_receive_cancelled(F f) + { + const asio::error_code e = error::channel_cancelled; + static_cast<F&&>(f)(e); + } + + typedef R receive_closed_signature(asio::error_code); + + template <typename F> + static void invoke_receive_closed(F f) + { + const asio::error_code e = error::channel_closed; + static_cast<F&&>(f)(e); + } +}; + +template <typename R, typename... Args, typename... Signatures> +struct channel_traits<R(asio::error_code, Args...), Signatures...> +{ + template <typename... NewSignatures> + struct rebind + { + typedef channel_traits<NewSignatures...> other; + }; + + template <typename Element> + struct container + { + typedef std::deque<Element> type; + }; + + typedef R receive_cancelled_signature(asio::error_code, Args...); + + template <typename F> + static void invoke_receive_cancelled(F f) + { + const asio::error_code e = error::channel_cancelled; + static_cast<F&&>(f)(e, decay_t<Args>()...); + } + + typedef R receive_closed_signature(asio::error_code, Args...); + + template <typename F> + static void invoke_receive_closed(F f) + { + const asio::error_code e = error::channel_closed; + static_cast<F&&>(f)(e, decay_t<Args>()...); + } +}; + +template <typename R> +struct channel_traits<R(std::exception_ptr)> +{ + template <typename... NewSignatures> + struct rebind + { + typedef channel_traits<NewSignatures...> other; + }; + + template <typename Element> + struct container + { + typedef std::deque<Element> type; + }; + + typedef R receive_cancelled_signature(std::exception_ptr); + + template <typename F> + static void invoke_receive_cancelled(F f) + { + const asio::error_code e = error::channel_cancelled; + static_cast<F&&>(f)( + std::make_exception_ptr(asio::system_error(e))); + } + + typedef R receive_closed_signature(std::exception_ptr); + + template <typename F> + static void invoke_receive_closed(F f) + { + const asio::error_code e = error::channel_closed; + static_cast<F&&>(f)( + std::make_exception_ptr(asio::system_error(e))); + } +}; + +template <typename R, typename... Args, typename... Signatures> +struct channel_traits<R(std::exception_ptr, Args...), Signatures...> +{ + template <typename... NewSignatures> + struct rebind + { + typedef channel_traits<NewSignatures...> other; + }; + + template <typename Element> + struct container + { + typedef std::deque<Element> type; + }; + + typedef R receive_cancelled_signature(std::exception_ptr, Args...); + + template <typename F> + static void invoke_receive_cancelled(F f) + { + const asio::error_code e = error::channel_cancelled; + static_cast<F&&>(f)( + std::make_exception_ptr(asio::system_error(e)), + decay_t<Args>()...); + } + + typedef R receive_closed_signature(std::exception_ptr, Args...); + + template <typename F> + static void invoke_receive_closed(F f) + { + const asio::error_code e = error::channel_closed; + static_cast<F&&>(f)( + std::make_exception_ptr(asio::system_error(e)), + decay_t<Args>()...); + } +}; + +template <typename R> +struct channel_traits<R()> +{ + template <typename... NewSignatures> + struct rebind + { + typedef channel_traits<NewSignatures...> other; + }; + + template <typename Element> + struct container + { + typedef std::deque<Element> type; + }; + + typedef R receive_cancelled_signature(asio::error_code); + + template <typename F> + static void invoke_receive_cancelled(F f) + { + const asio::error_code e = error::channel_cancelled; + static_cast<F&&>(f)(e); + } + + typedef R receive_closed_signature(asio::error_code); + + template <typename F> + static void invoke_receive_closed(F f) + { + const asio::error_code e = error::channel_closed; + static_cast<F&&>(f)(e); + } +}; + +template <typename R, typename T> +struct channel_traits<R(T)> +{ + template <typename... NewSignatures> + struct rebind + { + typedef channel_traits<NewSignatures...> other; + }; + + template <typename Element> + struct container + { + typedef std::deque<Element> type; + }; + + typedef R receive_cancelled_signature(asio::error_code); + + template <typename F> + static void invoke_receive_cancelled(F f) + { + const asio::error_code e = error::channel_cancelled; + static_cast<F&&>(f)(e); + } + + typedef R receive_closed_signature(asio::error_code); + + template <typename F> + static void invoke_receive_closed(F f) + { + const asio::error_code e = error::channel_closed; + static_cast<F&&>(f)(e); + } +}; + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_CHANNEL_TRAITS_HPP diff --git a/3rdparty/asio/include/asio/experimental/co_composed.hpp b/3rdparty/asio/include/asio/experimental/co_composed.hpp new file mode 100644 index 00000000000..dd1b82939cd --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/co_composed.hpp @@ -0,0 +1,145 @@ +// +// experimental/co_composed.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CO_COMPOSED_HPP +#define ASIO_EXPERIMENTAL_CO_COMPOSED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +/// Creates an initiation function object that may be used to launch a +/// coroutine-based composed asynchronous operation. +/** + * The experimental::co_composed utility simplifies the implementation of + * composed asynchronous operations by automatically adapting a coroutine to be + * an initiation function object for use with @c async_initiate. When awaiting + * asynchronous operations, the coroutine automatically uses a conforming + * intermediate completion handler. + * + * @param implementation A function object that contains the coroutine-based + * implementation of the composed asynchronous operation. The first argument to + * the function object represents the state of the operation, and may be used + * to test for cancellation. The remaining arguments are those passed to @c + * async_initiate after the completion token. + * + * @param io_objects_or_executors Zero or more I/O objects or I/O executors for + * which outstanding work must be maintained while the operation is incomplete. + * + * @par Per-Operation Cancellation + * By default, terminal per-operation cancellation is enabled for composed + * operations that use experimental::co_composed. To disable cancellation for + * the composed operation, or to alter its supported cancellation types, call + * the state's @c reset_cancellation_state function. + * + * @par Examples + * The following example illustrates manual error handling and explicit checks + * for cancellation. The completion handler is invoked via a @c co_yield to the + * state's @c complete function, which never returns. + * + * @code template <typename CompletionToken> + * auto async_echo(tcp::socket& socket, + * CompletionToken&& token) + * { + * return asio::async_initiate< + * CompletionToken, void(std::error_code)>( + * asio::experimental::co_composed( + * [](auto state, tcp::socket& socket) -> void + * { + * state.reset_cancellation_state( + * asio::enable_terminal_cancellation()); + * + * while (!state.cancelled()) + * { + * char data[1024]; + * auto [e1, n1] = + * co_await socket.async_read_some( + * asio::buffer(data), + * asio::as_tuple(asio::deferred)); + * + * if (e1) + * co_yield state.complete(e1); + * + * if (!!state.cancelled()) + * co_yield state.complete( + * make_error_code(asio::error::operation_aborted)); + * + * auto [e2, n2] = + * co_await asio::async_write(socket, + * asio::buffer(data, n1), + * asio::as_tuple(asio::deferred)); + * + * if (e2) + * co_yield state.complete(e2); + * } + * }, socket), + * token, std::ref(socket)); + * } @endcode + * + * This next example shows exception-based error handling and implicit checks + * for cancellation. The completion handler is invoked after returning from the + * coroutine via @c co_return. Valid @c co_return values are specified using + * completion signatures passed to the @c co_composed function. + * + * @code template <typename CompletionToken> + * auto async_echo(tcp::socket& socket, + * CompletionToken&& token) + * { + * return asio::async_initiate< + * CompletionToken, void(std::error_code)>( + * asio::experimental::co_composed< + * void(std::error_code)>( + * [](auto state, tcp::socket& socket) -> void + * { + * try + * { + * state.throw_if_cancelled(true); + * state.reset_cancellation_state( + * asio::enable_terminal_cancellation()); + * + * for (;;) + * { + * char data[1024]; + * std::size_t n = co_await socket.async_read_some( + * asio::buffer(data), asio::deferred); + * + * co_await asio::async_write(socket, + * asio::buffer(data, n), asio::deferred); + * } + * } + * catch (const std::system_error& e) + * { + * co_return {e.code()}; + * } + * }, socket), + * token, std::ref(socket)); + * } @endcode + */ +template <completion_signature... Signatures, + typename Implementation, typename... IoObjectsOrExecutors> +auto co_composed(Implementation&& implementation, + IoObjectsOrExecutors&&... io_objects_or_executors); + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/co_composed.hpp" + +#endif // ASIO_EXPERIMENTAL_CO_COMPOSED_HPP diff --git a/3rdparty/asio/include/asio/experimental/co_spawn.hpp b/3rdparty/asio/include/asio/experimental/co_spawn.hpp new file mode 100644 index 00000000000..8ef59283178 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/co_spawn.hpp @@ -0,0 +1,187 @@ +// +// experimental/co_spawn.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_CO_SPAWN_HPP +#define ASIO_EXPERIMENTAL_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <utility> +#include "asio/compose.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/experimental/coro.hpp" +#include "asio/experimental/deferred.hpp" +#include "asio/experimental/prepend.hpp" +#include "asio/redirect_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename T, typename U, typename Executor> +struct coro_spawn_op +{ + coro<T, U, Executor> c; + + void operator()(auto& self) + { + auto op = c.async_resume(deferred); + std::move(op)((prepend)(std::move(self), 0)); + } + + void operator()(auto& self, int, auto... res) + { + self.complete(std::move(res)...); + } +}; + +} // namespace detail + +/// Spawn a resumable coroutine. +/** + * This function spawns the coroutine for execution on its executor. It binds + * the lifetime of the coroutine to the executor. + * + * @param c The coroutine + * + * @param token The completion token + * + * @returns Implementation defined + */ +template <typename T, typename Executor, typename CompletionToken> +ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(coro<void, T, Executor> c, CompletionToken&& token) +{ + auto exec = c.get_executor(); + return async_compose<CompletionToken, void(std::exception_ptr, T)>( + detail::coro_spawn_op<void, T, Executor>{std::move(c)}, + token, exec); +} + +/// Spawn a resumable coroutine. +/** + * This function spawns the coroutine for execution on its executor. It binds + * the lifetime of the coroutine to the executor. + * + * @param c The coroutine + * + * @param token The completion token + * + * @returns Implementation defined + */ +template <typename T, typename Executor, typename CompletionToken> +ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(coro<void(), T, Executor> c, CompletionToken&& token) +{ + auto exec = c.get_executor(); + return async_compose<CompletionToken, void(std::exception_ptr, T)>( + detail::coro_spawn_op<void(), T, Executor>{std::move(c)}, + token, exec); +} + +/// Spawn a resumable coroutine. +/** + * This function spawns the coroutine for execution on its executor. It binds + * the lifetime of the coroutine to the executor. + * + * @param c The coroutine + * + * @param token The completion token + * + * @returns Implementation defined + */ +template <typename T, typename Executor, typename CompletionToken> +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(T)) +co_spawn(coro<void() noexcept, T, Executor> c, CompletionToken&& token) +{ + auto exec = c.get_executor(); + return async_compose<CompletionToken, void(T)>( + detail::coro_spawn_op<void() noexcept, T, Executor>{std::move(c)}, + token, exec); +} + +/// Spawn a resumable coroutine. +/** + * This function spawns the coroutine for execution on its executor. It binds + * the lifetime of the coroutine to the executor. + * + * @param c The coroutine + * + * @param token The completion token + * + * @returns Implementation defined + */ +template <typename Executor, typename CompletionToken> +ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(coro<void, void, Executor> c, CompletionToken&& token) +{ + auto exec = c.get_executor(); + return async_compose<CompletionToken, void(std::exception_ptr)>( + detail::coro_spawn_op<void, void, Executor>{std::move(c)}, + token, exec); +} + +/// Spawn a resumable coroutine. +/** + * This function spawns the coroutine for execution on its executor. It binds + * the lifetime of the coroutine to the executor. + * + * @param c The coroutine + * + * @param token The completion token + * + * @returns Implementation defined + */ +template <typename Executor, typename CompletionToken> +ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(coro<void(), void, Executor> c, CompletionToken&& token) +{ + auto exec = c.get_executor(); + return async_compose<CompletionToken, void(std::exception_ptr)>( + detail::coro_spawn_op<void(), void, Executor>{std::move(c)}, + token, exec); +} + +/// Spawn a resumable coroutine. +/** + * This function spawns the coroutine for execution on its executor. It binds + * the lifetime of the coroutine to the executor. + * + * @param c The coroutine + * + * @param token The completion token + * + * @returns Implementation defined + */ +template <typename Executor, typename CompletionToken> +ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) +co_spawn(coro<void() noexcept, void, Executor> c, CompletionToken&& token) +{ + auto exec = c.get_executor(); + return async_compose<CompletionToken, void()>( + detail::coro_spawn_op<void() noexcept, void, Executor>{std::move(c)}, + token, exec); +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif //ASIO_EXPERIMENTAL_CO_SPAWN_HPP diff --git a/3rdparty/asio/include/asio/experimental/concurrent_channel.hpp b/3rdparty/asio/include/asio/experimental/concurrent_channel.hpp new file mode 100644 index 00000000000..b326be96d31 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/concurrent_channel.hpp @@ -0,0 +1,70 @@ +// +// experimental/concurrent_channel.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CONCURRENT_CHANNEL_HPP +#define ASIO_EXPERIMENTAL_CONCURRENT_CHANNEL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_executor.hpp" +#include "asio/experimental/basic_concurrent_channel.hpp" +#include "asio/experimental/channel_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename ExecutorOrSignature, typename = void> +struct concurrent_channel_type +{ + template <typename... Signatures> + struct inner + { + typedef basic_concurrent_channel<any_io_executor, channel_traits<>, + ExecutorOrSignature, Signatures...> type; + }; +}; + +template <typename ExecutorOrSignature> +struct concurrent_channel_type<ExecutorOrSignature, + enable_if_t< + is_executor<ExecutorOrSignature>::value + || execution::is_executor<ExecutorOrSignature>::value + >> +{ + template <typename... Signatures> + struct inner + { + typedef basic_concurrent_channel<ExecutorOrSignature, + channel_traits<>, Signatures...> type; + }; +}; + +} // namespace detail + +/// Template type alias for common use of channel. +template <typename ExecutorOrSignature, typename... Signatures> +using concurrent_channel = typename detail::concurrent_channel_type< + ExecutorOrSignature>::template inner<Signatures...>::type; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_CONCURRENT_CHANNEL_HPP diff --git a/3rdparty/asio/include/asio/experimental/coro.hpp b/3rdparty/asio/include/asio/experimental/coro.hpp new file mode 100644 index 00000000000..de909d29a6b --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/coro.hpp @@ -0,0 +1,293 @@ +// +// experimental/coro.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_CORO_HPP +#define ASIO_EXPERIMENTAL_CORO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/dispatch.hpp" +#include "asio/error.hpp" +#include "asio/error_code.hpp" +#include "asio/experimental/coro_traits.hpp" +#include "asio/experimental/detail/coro_promise_allocator.hpp" +#include "asio/experimental/detail/partial_promise.hpp" +#include "asio/post.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Signature, typename Return, + typename Executor, typename Allocator> +struct coro_promise; + +template <typename T, typename Coroutine> +struct coro_with_arg; + +} // namespace detail + +/// The main type of a resumable coroutine. +/** + * Template parameter @c Yield specifies type or signature used by co_yield, + * @c Return specifies the type used for co_return, and @c Executor specifies + * the underlying executor type. + */ +template <typename Yield = void, typename Return = void, + typename Executor = any_io_executor, + typename Allocator = std::allocator<void>> +struct coro +{ + /// The traits of the coroutine. See asio::experimental::coro_traits + /// for details. + using traits = coro_traits<Yield, Return, Executor>; + + /// The value that can be passed into a symmetrical cororoutine. @c void if + /// asymmetrical. + using input_type = typename traits::input_type; + + /// The type that can be passed out through a co_yield. + using yield_type = typename traits::yield_type; + + /// The type that can be passed out through a co_return. + using return_type = typename traits::return_type; + + /// The type received by a co_await or async_resume. Its a combination of + /// yield and return. + using result_type = typename traits::result_type; + + /// The signature used by the async_resume. + using signature_type = typename traits::signature_type; + + /// Whether or not the coroutine is noexcept. + constexpr static bool is_noexcept = traits::is_noexcept; + + /// The error type of the coroutine. Void for noexcept + using error_type = typename traits::error_type; + + /// Completion handler type used by async_resume. + using completion_handler = typename traits::completion_handler; + + /// The internal promise-type of the coroutine. + using promise_type = detail::coro_promise<Yield, Return, Executor, Allocator>; + +#if !defined(GENERATING_DOCUMENTATION) + template <typename T, typename Coroutine> + friend struct detail::coro_with_arg; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// The executor type. + using executor_type = Executor; + + /// The allocator type. + using allocator_type = Allocator; + +#if !defined(GENERATING_DOCUMENTATION) + friend struct detail::coro_promise<Yield, Return, Executor, Allocator>; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// The default constructor, gives an invalid coroutine. + coro() = default; + + /// Move constructor. + coro(coro&& lhs) noexcept + : coro_(std::exchange(lhs.coro_, nullptr)) + { + } + + coro(const coro&) = delete; + + /// Move assignment. + coro& operator=(coro&& lhs) noexcept + { + std::swap(coro_, lhs.coro_); + return *this; + } + + coro& operator=(const coro&) = delete; + + /// Destructor. Destroys the coroutine, if it holds a valid one. + /** + * @note This does not cancel an active coroutine. Destructing a resumable + * coroutine, i.e. one with a call to async_resume that has not completed, is + * undefined behaviour. + */ + ~coro() + { + if (coro_ != nullptr) + { + struct destroyer + { + detail::coroutine_handle<promise_type> handle; + + destroyer(const detail::coroutine_handle<promise_type>& handle) + : handle(handle) + { } + + destroyer(destroyer&& lhs) + : handle(std::exchange(lhs.handle, nullptr)) + { + } + + destroyer(const destroyer&) = delete; + + void operator()() {} + + ~destroyer() + { + if (handle) + handle.destroy(); + } + }; + + auto handle = + detail::coroutine_handle<promise_type>::from_promise(*coro_); + if (handle) + asio::dispatch(coro_->get_executor(), destroyer{handle}); + } + } + + /// Get the used executor. + executor_type get_executor() const + { + if (coro_) + return coro_->get_executor(); + + if constexpr (std::is_default_constructible_v<Executor>) + return Executor{}; + else + throw std::logic_error("Coroutine has no executor"); + } + + /// Get the used allocator. + allocator_type get_allocator() const + { + if (coro_) + return coro_->get_allocator(); + + if constexpr (std::is_default_constructible_v<Allocator>) + return Allocator{}; + else + throw std::logic_error( + "Coroutine has no available allocator without a constructed promise"); + } + + /// Resume the coroutine. + /** + * @param token The completion token of the async resume. + * + * @attention Calling an invalid coroutine with a noexcept signature is + * undefined behaviour. + * + * @note This overload is only available for coroutines without an input + * value. + */ + template <typename CompletionToken> + requires std::is_void_v<input_type> + auto async_resume(CompletionToken&& token) & + { + return async_initiate<CompletionToken, + typename traits::completion_handler>( + initiate_async_resume(this), token); + } + + /// Resume the coroutine. + /** + * @param token The completion token of the async resume. + * + * @attention Calling an invalid coroutine with a noexcept signature is + * undefined behaviour. + * + * @note This overload is only available for coroutines with an input value. + */ + template <typename CompletionToken, detail::convertible_to<input_type> T> + auto async_resume(T&& ip, CompletionToken&& token) & + { + return async_initiate<CompletionToken, + typename traits::completion_handler>( + initiate_async_resume(this), token, std::forward<T>(ip)); + } + + /// Operator used for coroutines without input value. + auto operator co_await() requires (std::is_void_v<input_type>) + { + return awaitable_t{*this}; + } + + /// Operator used for coroutines with input value. + /** + * @param ip The input value + * + * @returns An awaitable handle. + * + * @code + * coro<void> push_values(coro<double(int)> c) + * { + * std::optional<double> res = co_await c(42); + * } + * @endcode + */ + template <detail::convertible_to<input_type> T> + auto operator()(T&& ip) + { + return detail::coro_with_arg<std::decay_t<T>, coro>{ + std::forward<T>(ip), *this}; + } + + /// Check whether the coroutine is open, i.e. can be resumed. + bool is_open() const + { + if (coro_) + { + auto handle = + detail::coroutine_handle<promise_type>::from_promise(*coro_); + return handle && !handle.done(); + } + else + return false; + } + + /// Check whether the coroutine is open, i.e. can be resumed. + explicit operator bool() const { return is_open(); } + +private: + struct awaitable_t; + + struct initiate_async_resume; + + explicit coro(promise_type* const cr) : coro_(cr) {} + + promise_type* coro_{nullptr}; +}; + +/// A generator is a coro that returns void and yields value. +template<typename T, typename Executor = asio::any_io_executor, + typename Allocator = std::allocator<void>> +using generator = coro<T, void, Executor, Allocator>; + +/// A task is a coro that does not yield values +template<typename T, typename Executor = asio::any_io_executor, + typename Allocator = std::allocator<void>> +using task = coro<void(), T, Executor, Allocator>; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/coro.hpp" + +#endif // ASIO_EXPERIMENTAL_CORO_HPP diff --git a/3rdparty/asio/include/asio/experimental/coro_traits.hpp b/3rdparty/asio/include/asio/experimental/coro_traits.hpp new file mode 100644 index 00000000000..7da904b1273 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/coro_traits.hpp @@ -0,0 +1,228 @@ +// +// experimental/detail/coro_traits.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_DETAIL_CORO_TRAITS_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CORO_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <optional> +#include <variant> +#include "asio/any_io_executor.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <class From, class To> +concept convertible_to = std::is_convertible_v<From, To>; + +template <typename T> +concept decays_to_executor = execution::executor<std::decay_t<T>>; + +template <typename T, typename Executor = any_io_executor> +concept execution_context = requires (T& t) +{ + {t.get_executor()} -> convertible_to<Executor>; +}; + +template <typename Yield, typename Return> +struct coro_result +{ + using type = std::variant<Yield, Return>; +}; + +template <typename Yield> +struct coro_result<Yield, void> +{ + using type = std::optional<Yield>; +}; + +template <typename Return> +struct coro_result<void, Return> +{ + using type = Return; +}; + +template <typename YieldReturn> +struct coro_result<YieldReturn, YieldReturn> +{ + using type = YieldReturn; +}; + +template <> +struct coro_result<void, void> +{ + using type = void; +}; + +template <typename Yield, typename Return> +using coro_result_t = typename coro_result<Yield, Return>::type; + +template <typename Result, bool IsNoexcept> +struct coro_handler; + +template <> +struct coro_handler<void, false> +{ + using type = void(std::exception_ptr); +}; + +template <> +struct coro_handler<void, true> +{ + using type = void(); +}; + +template <typename T> +struct coro_handler<T, false> +{ + using type = void(std::exception_ptr, T); +}; + +template <typename T> +struct coro_handler<T, true> +{ + using type = void(T); +}; + +template <typename Result, bool IsNoexcept> +using coro_handler_t = typename coro_handler<Result, IsNoexcept>::type; + +} // namespace detail + +#if defined(GENERATING_DOCUMENTATION) + +/// The traits describing the resumable coroutine behaviour. +/** + * Template parameter @c Yield specifies type or signature used by co_yield, + * @c Return specifies the type used for co_return, and @c Executor specifies + * the underlying executor type. + */ +template <typename Yield, typename Return, typename Executor> +struct coro_traits +{ + /// The value that can be passed into a symmetrical cororoutine. @c void if + /// asymmetrical. + using input_type = argument_dependent; + + /// The type that can be passed out through a co_yield. + using yield_type = argument_dependent; + + /// The type that can be passed out through a co_return. + using return_type = argument_dependent; + + /// The type received by a co_await or async_resume. It's a combination of + /// yield and return. + using result_type = argument_dependent; + + /// The signature used by the async_resume. + using signature_type = argument_dependent; + + /// Whether or not the coroutine is noexcept. + constexpr static bool is_noexcept = argument_dependent; + + /// The error type of the coroutine. @c void for noexcept. + using error_type = argument_dependent; + + /// Completion handler type used by async_resume. + using completion_handler = argument_dependent; +}; + +#else // defined(GENERATING_DOCUMENTATION) + +template <typename Yield, typename Return, typename Executor> +struct coro_traits +{ + using input_type = void; + using yield_type = Yield; + using return_type = Return; + using result_type = detail::coro_result_t<yield_type, return_type>; + using signature_type = result_type(); + constexpr static bool is_noexcept = false; + using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; + using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; +}; + +template <typename T, typename Return, typename Executor> +struct coro_traits<T(), Return, Executor> +{ + using input_type = void; + using yield_type = T; + using return_type = Return; + using result_type = detail::coro_result_t<yield_type, return_type>; + using signature_type = result_type(); + constexpr static bool is_noexcept = false; + using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; + using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; +}; + +template <typename T, typename Return, typename Executor> +struct coro_traits<T() noexcept, Return, Executor> +{ + using input_type = void; + using yield_type = T; + using return_type = Return; + using result_type = detail::coro_result_t<yield_type, return_type>; + using signature_type = result_type(); + constexpr static bool is_noexcept = true; + using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; + using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; +}; + +template <typename T, typename U, typename Return, typename Executor> +struct coro_traits<T(U), Return, Executor> +{ + using input_type = U; + using yield_type = T; + using return_type = Return; + using result_type = detail::coro_result_t<yield_type, return_type>; + using signature_type = result_type(input_type); + constexpr static bool is_noexcept = false; + using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; + using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; +}; + +template <typename T, typename U, typename Return, typename Executor> +struct coro_traits<T(U) noexcept, Return, Executor> +{ + using input_type = U; + using yield_type = T; + using return_type = Return; + using result_type = detail::coro_result_t<yield_type, return_type>; + using signature_type = result_type(input_type); + constexpr static bool is_noexcept = true; + using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; + using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; +}; + +template <typename Executor> +struct coro_traits<void() noexcept, void, Executor> +{ + using input_type = void; + using yield_type = void; + using return_type = void; + using result_type = detail::coro_result_t<yield_type, return_type>; + using signature_type = result_type(input_type); + constexpr static bool is_noexcept = true; + using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; + using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; +}; + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace experimental +} // namespace asio + +#endif // ASIO_EXPERIMENTAL_DETAIL_CORO_TRAITS_HPP diff --git a/3rdparty/asio/include/asio/experimental/deferred.hpp b/3rdparty/asio/include/asio/experimental/deferred.hpp new file mode 100644 index 00000000000..c722ad1a2de --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/deferred.hpp @@ -0,0 +1,36 @@ +// +// experimental/deferred.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DEFERRED_HPP +#define ASIO_EXPERIMENTAL_DEFERRED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/deferred.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +#if !defined(ASIO_NO_DEPRECATED) +using asio::deferred_t; +using asio::deferred; +#endif // !defined(ASIO_NO_DEPRECATED) + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DEFERRED_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_handler.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_handler.hpp new file mode 100644 index 00000000000..0152c2e76ff --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_handler.hpp @@ -0,0 +1,77 @@ +// +// experimental/detail/channel_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_HANDLER_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/experimental/detail/channel_payload.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Payload, typename Handler> +class channel_handler +{ +public: + channel_handler(Payload&& p, Handler& h) + : payload_(static_cast<Payload&&>(p)), + handler_(static_cast<Handler&&>(h)) + { + } + + void operator()() + { + payload_.receive(handler_); + } + +//private: + Payload payload_; + Handler handler_; +}; + +} // namespace detail +} // namespace experimental + +template <template <typename, typename> class Associator, + typename Payload, typename Handler, typename DefaultCandidate> +struct associator<Associator, + experimental::detail::channel_handler<Payload, Handler>, + DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const experimental::detail::channel_handler<Payload, Handler>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get( + const experimental::detail::channel_handler<Payload, Handler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_HANDLER_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_message.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_message.hpp new file mode 100644 index 00000000000..16446f0c1bb --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_message.hpp @@ -0,0 +1,129 @@ +// +// experimental/detail/channel_message.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_MESSAGE_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_MESSAGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <tuple> +#include "asio/detail/type_traits.hpp" +#include "asio/detail/utility.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Signature> +class channel_message; + +template <typename R> +class channel_message<R()> +{ +public: + channel_message(int) + { + } + + template <typename Handler> + void receive(Handler& handler) + { + static_cast<Handler&&>(handler)(); + } +}; + +template <typename R, typename Arg0> +class channel_message<R(Arg0)> +{ +public: + template <typename T0> + channel_message(int, T0&& t0) + : arg0_(static_cast<T0&&>(t0)) + { + } + + template <typename Handler> + void receive(Handler& handler) + { + static_cast<Handler&&>(handler)( + static_cast<arg0_type&&>(arg0_)); + } + +private: + typedef decay_t<Arg0> arg0_type; + arg0_type arg0_; +}; + +template <typename R, typename Arg0, typename Arg1> +class channel_message<R(Arg0, Arg1)> +{ +public: + template <typename T0, typename T1> + channel_message(int, T0&& t0, T1&& t1) + : arg0_(static_cast<T0&&>(t0)), + arg1_(static_cast<T1&&>(t1)) + { + } + + template <typename Handler> + void receive(Handler& handler) + { + static_cast<Handler&&>(handler)( + static_cast<arg0_type&&>(arg0_), + static_cast<arg1_type&&>(arg1_)); + } + +private: + typedef decay_t<Arg0> arg0_type; + arg0_type arg0_; + typedef decay_t<Arg1> arg1_type; + arg1_type arg1_; +}; + +template <typename R, typename... Args> +class channel_message<R(Args...)> +{ +public: + template <typename... T> + channel_message(int, T&&... t) + : args_(static_cast<T&&>(t)...) + { + } + + template <typename Handler> + void receive(Handler& h) + { + this->do_receive(h, asio::detail::index_sequence_for<Args...>()); + } + +private: + template <typename Handler, std::size_t... I> + void do_receive(Handler& h, asio::detail::index_sequence<I...>) + { + static_cast<Handler&&>(h)( + std::get<I>(static_cast<args_type&&>(args_))...); + } + + typedef std::tuple<decay_t<Args>...> args_type; + args_type args_; +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_MESSAGE_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_operation.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_operation.hpp new file mode 100644 index 00000000000..1231f1f87c1 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_operation.hpp @@ -0,0 +1,361 @@ +// +// experimental/detail/channel_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_OPERATION_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_immediate_executor.hpp" +#include "asio/detail/initiate_post.hpp" +#include "asio/detail/initiate_dispatch.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/prefer.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +// Base class for all channel operations. A function pointer is used instead of +// virtual functions to avoid the associated overhead. +class channel_operation ASIO_INHERIT_TRACKED_HANDLER +{ +public: + template <typename Executor, typename = void, typename = void> + class handler_work_base; + + template <typename Handler, typename IoExecutor, typename = void> + class handler_work; + + void destroy() + { + func_(this, destroy_op, 0); + } + +protected: + enum action + { + destroy_op = 0, + immediate_op = 1, + post_op = 2, + dispatch_op = 3, + cancel_op = 4, + close_op = 5 + }; + + typedef void (*func_type)(channel_operation*, action, void*); + + channel_operation(func_type func) + : next_(0), + func_(func), + cancellation_key_(0) + { + } + + // Prevents deletion through this type. + ~channel_operation() + { + } + + friend class asio::detail::op_queue_access; + channel_operation* next_; + func_type func_; + +public: + // The operation key used for targeted cancellation. + void* cancellation_key_; +}; + +template <typename Executor, typename, typename> +class channel_operation::handler_work_base +{ +public: + typedef decay_t< + prefer_result_t<Executor, + execution::outstanding_work_t::tracked_t + > + > executor_type; + + handler_work_base(int, const Executor& ex) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + const executor_type& get_executor() const noexcept + { + return executor_; + } + + template <typename IoExecutor, typename Function, typename Handler> + void post(const IoExecutor& io_exec, Function& function, Handler&) + { + (asio::detail::initiate_post_with_executor<IoExecutor>(io_exec))( + static_cast<Function&&>(function)); + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + associated_allocator_t<Handler> allocator = + (get_associated_allocator)(handler); + + asio::prefer(executor_, + execution::allocator(allocator) + ).execute(static_cast<Function&&>(function)); + } + +private: + executor_type executor_; +}; + +template <typename Executor> +class channel_operation::handler_work_base<Executor, + enable_if_t< + execution::is_executor<Executor>::value + >, + enable_if_t< + can_require<Executor, execution::blocking_t::never_t>::value + > + > +{ +public: + typedef decay_t< + prefer_result_t<Executor, + execution::outstanding_work_t::tracked_t + > + > executor_type; + + handler_work_base(int, const Executor& ex) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + const executor_type& get_executor() const noexcept + { + return executor_; + } + + template <typename IoExecutor, typename Function, typename Handler> + void post(const IoExecutor&, Function& function, Handler& handler) + { + associated_allocator_t<Handler> allocator = + (get_associated_allocator)(handler); + + asio::prefer( + asio::require(executor_, execution::blocking.never), + execution::allocator(allocator) + ).execute(static_cast<Function&&>(function)); + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + associated_allocator_t<Handler> allocator = + (get_associated_allocator)(handler); + + asio::prefer(executor_, + execution::allocator(allocator) + ).execute(static_cast<Function&&>(function)); + } + +private: + executor_type executor_; +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor> +class channel_operation::handler_work_base<Executor, + enable_if_t< + !execution::is_executor<Executor>::value + > + > +{ +public: + typedef Executor executor_type; + + handler_work_base(int, const Executor& ex) + : work_(ex) + { + } + + executor_type get_executor() const noexcept + { + return work_.get_executor(); + } + + template <typename IoExecutor, typename Function, typename Handler> + void post(const IoExecutor&, Function& function, Handler& handler) + { + associated_allocator_t<Handler> allocator = + (get_associated_allocator)(handler); + + work_.get_executor().post( + static_cast<Function&&>(function), allocator); + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + associated_allocator_t<Handler> allocator = + (get_associated_allocator)(handler); + + work_.get_executor().dispatch( + static_cast<Function&&>(function), allocator); + } + +private: + executor_work_guard<Executor> work_; +}; + +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Handler, typename IoExecutor, typename> +class channel_operation::handler_work : + channel_operation::handler_work_base<IoExecutor>, + channel_operation::handler_work_base< + associated_executor_t<Handler, IoExecutor>, IoExecutor> +{ +public: + typedef channel_operation::handler_work_base<IoExecutor> base1_type; + + typedef channel_operation::handler_work_base< + associated_executor_t<Handler, IoExecutor>, IoExecutor> + base2_type; + + handler_work(Handler& handler, const IoExecutor& io_ex) noexcept + : base1_type(0, io_ex), + base2_type(0, (get_associated_executor)(handler, io_ex)) + { + } + + template <typename Function> + void post(Function& function, Handler& handler) + { + base2_type::post(base1_type::get_executor(), function, handler); + } + + template <typename Function> + void dispatch(Function& function, Handler& handler) + { + base2_type::dispatch(function, handler); + } + + template <typename Function> + void immediate(Function& function, Handler& handler, ...) + { + typedef associated_immediate_executor_t<Handler, + typename base1_type::executor_type> immediate_ex_type; + + immediate_ex_type immediate_ex = (get_associated_immediate_executor)( + handler, base1_type::get_executor()); + + (asio::detail::initiate_dispatch_with_executor<immediate_ex_type>( + immediate_ex))(static_cast<Function&&>(function)); + } + + template <typename Function> + void immediate(Function& function, Handler&, + enable_if_t< + is_same< + typename associated_immediate_executor< + conditional_t<false, Function, Handler>, + typename base1_type::executor_type>:: + asio_associated_immediate_executor_is_unspecialised, + void + >::value + >*) + { + (asio::detail::initiate_post_with_executor< + typename base1_type::executor_type>( + base1_type::get_executor()))( + static_cast<Function&&>(function)); + } +}; + +template <typename Handler, typename IoExecutor> +class channel_operation::handler_work< + Handler, IoExecutor, + enable_if_t< + is_same< + typename associated_executor<Handler, + IoExecutor>::asio_associated_executor_is_unspecialised, + void + >::value + > + > : handler_work_base<IoExecutor> +{ +public: + typedef channel_operation::handler_work_base<IoExecutor> base1_type; + + handler_work(Handler&, const IoExecutor& io_ex) noexcept + : base1_type(0, io_ex) + { + } + + template <typename Function> + void post(Function& function, Handler& handler) + { + base1_type::post(base1_type::get_executor(), function, handler); + } + + template <typename Function> + void dispatch(Function& function, Handler& handler) + { + base1_type::dispatch(function, handler); + } + + template <typename Function> + void immediate(Function& function, Handler& handler, ...) + { + typedef associated_immediate_executor_t<Handler, + typename base1_type::executor_type> immediate_ex_type; + + immediate_ex_type immediate_ex = (get_associated_immediate_executor)( + handler, base1_type::get_executor()); + + (asio::detail::initiate_dispatch_with_executor<immediate_ex_type>( + immediate_ex))(static_cast<Function&&>(function)); + } + + template <typename Function> + void immediate(Function& function, Handler& handler, + enable_if_t< + is_same< + typename associated_immediate_executor< + conditional_t<false, Function, Handler>, + typename base1_type::executor_type>:: + asio_associated_immediate_executor_is_unspecialised, + void + >::value + >*) + { + base1_type::post(base1_type::get_executor(), function, handler); + } +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_payload.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_payload.hpp new file mode 100644 index 00000000000..31614cd5dbc --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_payload.hpp @@ -0,0 +1,222 @@ +// +// experimental/detail/channel_payload.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_PAYLOAD_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_PAYLOAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error_code.hpp" +#include "asio/experimental/detail/channel_message.hpp" + +#if defined(ASIO_HAS_STD_VARIANT) +# include <variant> +#else // defined(ASIO_HAS_STD_VARIANT) +# include <new> +#endif // defined(ASIO_HAS_STD_VARIANT) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename... Signatures> +class channel_payload; + +template <typename R> +class channel_payload<R()> +{ +public: + explicit channel_payload(channel_message<R()>) + { + } + + template <typename Handler> + void receive(Handler& handler) + { + static_cast<Handler&&>(handler)(); + } +}; + +template <typename Signature> +class channel_payload<Signature> +{ +public: + channel_payload(channel_message<Signature>&& m) + : message_(static_cast<channel_message<Signature>&&>(m)) + { + } + + template <typename Handler> + void receive(Handler& handler) + { + message_.receive(handler); + } + +private: + channel_message<Signature> message_; +}; + +#if defined(ASIO_HAS_STD_VARIANT) + +template <typename... Signatures> +class channel_payload +{ +public: + template <typename Signature> + channel_payload(channel_message<Signature>&& m) + : message_(static_cast<channel_message<Signature>&&>(m)) + { + } + + template <typename Handler> + void receive(Handler& handler) + { + std::visit( + [&](auto& message) + { + message.receive(handler); + }, message_); + } + +private: + std::variant<channel_message<Signatures>...> message_; +}; + +#else // defined(ASIO_HAS_STD_VARIANT) + +template <typename R1, typename R2> +class channel_payload<R1(), R2(asio::error_code)> +{ +public: + typedef channel_message<R1()> void_message_type; + typedef channel_message<R2(asio::error_code)> error_message_type; + + channel_payload(void_message_type&&) + : message_(0, asio::error_code()), + empty_(true) + { + } + + channel_payload(error_message_type&& m) + : message_(static_cast<error_message_type&&>(m)), + empty_(false) + { + } + + template <typename Handler> + void receive(Handler& handler) + { + if (empty_) + channel_message<R1()>(0).receive(handler); + else + message_.receive(handler); + } + +private: + error_message_type message_; + bool empty_; +}; + +template <typename Sig1, typename Sig2> +class channel_payload<Sig1, Sig2> +{ +public: + typedef channel_message<Sig1> message_1_type; + typedef channel_message<Sig2> message_2_type; + + channel_payload(message_1_type&& m) + : index_(1) + { + new (&storage_.message_1_) message_1_type(static_cast<message_1_type&&>(m)); + } + + channel_payload(message_2_type&& m) + : index_(2) + { + new (&storage_.message_2_) message_2_type(static_cast<message_2_type&&>(m)); + } + + channel_payload(channel_payload&& other) + : index_(other.index_) + { + switch (index_) + { + case 1: + new (&storage_.message_1_) message_1_type( + static_cast<message_1_type&&>(other.storage_.message_1_)); + break; + case 2: + new (&storage_.message_2_) message_2_type( + static_cast<message_2_type&&>(other.storage_.message_2_)); + break; + default: + break; + } + } + + ~channel_payload() + { + switch (index_) + { + case 1: + storage_.message_1_.~message_1_type(); + break; + case 2: + storage_.message_2_.~message_2_type(); + break; + default: + break; + } + } + + template <typename Handler> + void receive(Handler& handler) + { + switch (index_) + { + case 1: + storage_.message_1_.receive(handler); + break; + case 2: + storage_.message_2_.receive(handler); + break; + default: + break; + } + } + +private: + union storage + { + storage() {} + ~storage() {} + + char dummy_; + message_1_type message_1_; + message_2_type message_2_; + } storage_; + unsigned char index_; +}; + +#endif // defined(ASIO_HAS_STD_VARIANT) + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_PAYLOAD_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_receive_op.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_receive_op.hpp new file mode 100644 index 00000000000..89d8ac2a5ab --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_receive_op.hpp @@ -0,0 +1,127 @@ +// +// experimental/detail/channel_receive_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_RECEIVE_OP_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_RECEIVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/error.hpp" +#include "asio/experimental/detail/channel_handler.hpp" +#include "asio/experimental/detail/channel_operation.hpp" +#include "asio/experimental/detail/channel_payload.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Payload> +class channel_receive : public channel_operation +{ +public: + void immediate(Payload payload) + { + func_(this, immediate_op, &payload); + } + + void post(Payload payload) + { + func_(this, post_op, &payload); + } + + void dispatch(Payload payload) + { + func_(this, dispatch_op, &payload); + } + +protected: + channel_receive(func_type func) + : channel_operation(func) + { + } +}; + +template <typename Payload, typename Handler, typename IoExecutor> +class channel_receive_op : public channel_receive<Payload> +{ +public: + ASIO_DEFINE_HANDLER_PTR(channel_receive_op); + + template <typename... Args> + channel_receive_op(Handler& handler, const IoExecutor& io_ex) + : channel_receive<Payload>(&channel_receive_op::do_action), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_action(channel_operation* base, + channel_operation::action a, void* v) + { + // Take ownership of the operation object. + channel_receive_op* o(static_cast<channel_receive_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + channel_operation::handler_work<Handler, IoExecutor> w( + static_cast<channel_operation::handler_work<Handler, IoExecutor>&&>( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the handler is posted. Even if we're not about to post the handler, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + if (a != channel_operation::destroy_op) + { + Payload* payload = static_cast<Payload*>(v); + channel_handler<Payload, Handler> handler( + static_cast<Payload&&>(*payload), o->handler_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + ASIO_HANDLER_INVOCATION_BEGIN(()); + if (a == channel_operation::immediate_op) + w.immediate(handler, handler.handler_, 0); + else if (a == channel_operation::dispatch_op) + w.dispatch(handler, handler.handler_); + else + w.post(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + else + { + asio::detail::binder0<Handler> handler(o->handler_); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + } + } + +private: + Handler handler_; + channel_operation::handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_RECEIVE_OP_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_send_functions.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_send_functions.hpp new file mode 100644 index 00000000000..108dffec934 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_send_functions.hpp @@ -0,0 +1,192 @@ +// +// experimental/detail/channel_send_functions.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_SEND_FUNCTIONS_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_SEND_FUNCTIONS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error_code.hpp" +#include "asio/experimental/detail/channel_message.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Derived, typename Executor, typename... Signatures> +class channel_send_functions; + +template <typename Derived, typename Executor, typename R, typename... Args> +class channel_send_functions<Derived, Executor, R(Args...)> +{ +public: + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + bool + > try_send(Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send<message_type>( + self->impl_, false, static_cast<Args2&&>(args)...); + } + + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + bool + > try_send_via_dispatch(Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send<message_type>( + self->impl_, true, static_cast<Args2&&>(args)...); + } + + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + std::size_t + > try_send_n(std::size_t count, Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send_n<message_type>( + self->impl_, count, false, static_cast<Args2&&>(args)...); + } + + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + std::size_t + > try_send_n_via_dispatch(std::size_t count, Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send_n<message_type>( + self->impl_, count, true, static_cast<Args2&&>(args)...); + } + + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + CompletionToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> + auto async_send(Args... args, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor)) + -> decltype( + async_initiate<CompletionToken, void (asio::error_code)>( + declval<typename conditional_t<false, CompletionToken, + Derived>::initiate_async_send>(), token, + declval<typename conditional_t<false, CompletionToken, + Derived>::payload_type>())) + { + typedef typename Derived::payload_type payload_type; + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return async_initiate<CompletionToken, void (asio::error_code)>( + typename Derived::initiate_async_send(self), token, + payload_type(message_type(0, static_cast<Args&&>(args)...))); + } +}; + +template <typename Derived, typename Executor, + typename R, typename... Args, typename... Signatures> +class channel_send_functions<Derived, Executor, R(Args...), Signatures...> : + public channel_send_functions<Derived, Executor, Signatures...> +{ +public: + using channel_send_functions<Derived, Executor, Signatures...>::try_send; + using channel_send_functions<Derived, Executor, Signatures...>::async_send; + + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + bool + > try_send(Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send<message_type>( + self->impl_, false, static_cast<Args2&&>(args)...); + } + + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + bool + > try_send_via_dispatch(Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send<message_type>( + self->impl_, true, static_cast<Args2&&>(args)...); + } + + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + std::size_t + > try_send_n(std::size_t count, Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send_n<message_type>( + self->impl_, count, false, static_cast<Args2&&>(args)...); + } + + template <typename... Args2> + enable_if_t< + is_constructible<detail::channel_message<R(Args...)>, int, Args2...>::value, + std::size_t + > try_send_n_via_dispatch(std::size_t count, Args2&&... args) + { + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return self->service_->template try_send_n<message_type>( + self->impl_, count, true, static_cast<Args2&&>(args)...); + } + + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + CompletionToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> + auto async_send(Args... args, + CompletionToken&& token + ASIO_DEFAULT_COMPLETION_TOKEN(Executor)) + -> decltype( + async_initiate<CompletionToken, void (asio::error_code)>( + declval<typename conditional_t<false, CompletionToken, + Derived>::initiate_async_send>(), token, + declval<typename conditional_t<false, CompletionToken, + Derived>::payload_type>())) + { + typedef typename Derived::payload_type payload_type; + typedef typename detail::channel_message<R(Args...)> message_type; + Derived* self = static_cast<Derived*>(this); + return async_initiate<CompletionToken, void (asio::error_code)>( + typename Derived::initiate_async_send(self), token, + payload_type(message_type(0, static_cast<Args&&>(args)...))); + } +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_SEND_FUNCTIONS_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_send_op.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_send_op.hpp new file mode 100644 index 00000000000..4326c23253e --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_send_op.hpp @@ -0,0 +1,148 @@ +// +// experimental/detail/channel_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_SEND_OP_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/error.hpp" +#include "asio/experimental/channel_error.hpp" +#include "asio/experimental/detail/channel_operation.hpp" +#include "asio/experimental/detail/channel_payload.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Payload> +class channel_send : public channel_operation +{ +public: + Payload get_payload() + { + return static_cast<Payload&&>(payload_); + } + + void immediate() + { + func_(this, immediate_op, 0); + } + + void post() + { + func_(this, post_op, 0); + } + + void cancel() + { + func_(this, cancel_op, 0); + } + + void close() + { + func_(this, close_op, 0); + } + +protected: + channel_send(func_type func, Payload&& payload) + : channel_operation(func), + payload_(static_cast<Payload&&>(payload)) + { + } + +private: + Payload payload_; +}; + +template <typename Payload, typename Handler, typename IoExecutor> +class channel_send_op : public channel_send<Payload> +{ +public: + ASIO_DEFINE_HANDLER_PTR(channel_send_op); + + channel_send_op(Payload&& payload, + Handler& handler, const IoExecutor& io_ex) + : channel_send<Payload>(&channel_send_op::do_action, + static_cast<Payload&&>(payload)), + handler_(static_cast<Handler&&>(handler)), + work_(handler_, io_ex) + { + } + + static void do_action(channel_operation* base, + channel_operation::action a, void*) + { + // Take ownership of the operation object. + channel_send_op* o(static_cast<channel_send_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + + ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + channel_operation::handler_work<Handler, IoExecutor> w( + static_cast<channel_operation::handler_work<Handler, IoExecutor>&&>( + o->work_)); + + asio::error_code ec; + switch (a) + { + case channel_operation::cancel_op: + ec = error::channel_cancelled; + break; + case channel_operation::close_op: + ec = error::channel_closed; + break; + default: + break; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the handler is posted. Even if we're not about to post the handler, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + asio::detail::binder1<Handler, asio::error_code> + handler(o->handler_, ec); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Post the completion if required. + if (a != channel_operation::destroy_op) + { + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + if (a == channel_operation::immediate_op) + w.immediate(handler, handler.handler_, 0); + else + w.post(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + channel_operation::handler_work<Handler, IoExecutor> work_; +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_SEND_OP_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/channel_service.hpp b/3rdparty/asio/include/asio/experimental/detail/channel_service.hpp new file mode 100644 index 00000000000..12324414613 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/channel_service.hpp @@ -0,0 +1,677 @@ +// +// experimental/detail/channel_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_CHANNEL_SERVICE_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/cancellation_type.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/op_queue.hpp" +#include "asio/execution_context.hpp" +#include "asio/experimental/detail/channel_message.hpp" +#include "asio/experimental/detail/channel_receive_op.hpp" +#include "asio/experimental/detail/channel_send_op.hpp" +#include "asio/experimental/detail/has_signature.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Mutex> +class channel_service + : public asio::detail::execution_context_service_base< + channel_service<Mutex>> +{ +public: + // Possible states for a channel end. + enum state + { + buffer = 0, + waiter = 1, + block = 2, + closed = 3 + }; + + // The base implementation type of all channels. + struct base_implementation_type + { + // Default constructor. + base_implementation_type() + : receive_state_(block), + send_state_(block), + max_buffer_size_(0), + next_(0), + prev_(0) + { + } + + // The current state of the channel. + state receive_state_ : 16; + state send_state_ : 16; + + // The maximum number of elements that may be buffered in the channel. + std::size_t max_buffer_size_; + + // The operations that are waiting on the channel. + asio::detail::op_queue<channel_operation> waiters_; + + // Pointers to adjacent channel implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + + // The mutex type to protect the internal implementation. + mutable Mutex mutex_; + }; + + // The implementation for a specific value type. + template <typename Traits, typename... Signatures> + struct implementation_type; + + // Constructor. + channel_service(asio::execution_context& ctx); + + // Destroy all user-defined handler objects owned by the service. + void shutdown(); + + // Construct a new channel implementation. + void construct(base_implementation_type& impl, std::size_t max_buffer_size); + + // Destroy a channel implementation. + template <typename Traits, typename... Signatures> + void destroy(implementation_type<Traits, Signatures...>& impl); + + // Move-construct a new channel implementation. + template <typename Traits, typename... Signatures> + void move_construct(implementation_type<Traits, Signatures...>& impl, + implementation_type<Traits, Signatures...>& other_impl); + + // Move-assign from another channel implementation. + template <typename Traits, typename... Signatures> + void move_assign(implementation_type<Traits, Signatures...>& impl, + channel_service& other_service, + implementation_type<Traits, Signatures...>& other_impl); + + // Get the capacity of the channel. + std::size_t capacity( + const base_implementation_type& impl) const noexcept; + + // Determine whether the channel is open. + bool is_open(const base_implementation_type& impl) const noexcept; + + // Reset the channel to its initial state. + template <typename Traits, typename... Signatures> + void reset(implementation_type<Traits, Signatures...>& impl); + + // Close the channel. + template <typename Traits, typename... Signatures> + void close(implementation_type<Traits, Signatures...>& impl); + + // Cancel all operations associated with the channel. + template <typename Traits, typename... Signatures> + void cancel(implementation_type<Traits, Signatures...>& impl); + + // Cancel the operation associated with the channel that has the given key. + template <typename Traits, typename... Signatures> + void cancel_by_key(implementation_type<Traits, Signatures...>& impl, + void* cancellation_key); + + // Determine whether a value can be read from the channel without blocking. + bool ready(const base_implementation_type& impl) const noexcept; + + // Synchronously send a new value into the channel. + template <typename Message, typename Traits, + typename... Signatures, typename... Args> + bool try_send(implementation_type<Traits, Signatures...>& impl, + bool via_dispatch, Args&&... args); + + // Synchronously send a number of new values into the channel. + template <typename Message, typename Traits, + typename... Signatures, typename... Args> + std::size_t try_send_n(implementation_type<Traits, Signatures...>& impl, + std::size_t count, bool via_dispatch, Args&&... args); + + // Asynchronously send a new value into the channel. + template <typename Traits, typename... Signatures, + typename Handler, typename IoExecutor> + void async_send(implementation_type<Traits, Signatures...>& impl, + typename implementation_type<Traits, + Signatures...>::payload_type&& payload, + Handler& handler, const IoExecutor& io_ex) + { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef channel_send_op< + typename implementation_type<Traits, Signatures...>::payload_type, + Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(static_cast<typename implementation_type< + Traits, Signatures...>::payload_type&&>(payload), handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<op_cancellation<Traits, Signatures...>>( + this, &impl); + } + + ASIO_HANDLER_CREATION((this->context(), *p.p, + "channel", &impl, 0, "async_send")); + + start_send_op(impl, p.p); + p.v = p.p = 0; + } + + // Synchronously receive a value from the channel. + template <typename Traits, typename... Signatures, typename Handler> + bool try_receive(implementation_type<Traits, Signatures...>& impl, + Handler&& handler); + + // Asynchronously receive a value from the channel. + template <typename Traits, typename... Signatures, + typename Handler, typename IoExecutor> + void async_receive(implementation_type<Traits, Signatures...>& impl, + Handler& handler, const IoExecutor& io_ex) + { + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Allocate and construct an operation to wrap the handler. + typedef channel_receive_op< + typename implementation_type<Traits, Signatures...>::payload_type, + Handler, IoExecutor> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + // Optionally register for per-operation cancellation. + if (slot.is_connected()) + { + p.p->cancellation_key_ = + &slot.template emplace<op_cancellation<Traits, Signatures...>>( + this, &impl); + } + + ASIO_HANDLER_CREATION((this->context(), *p.p, + "channel", &impl, 0, "async_receive")); + + start_receive_op(impl, p.p); + p.v = p.p = 0; + } + +private: + // Helper function object to handle a closed notification. + template <typename Payload, typename Signature> + struct post_receive + { + explicit post_receive(channel_receive<Payload>* op) + : op_(op) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + op_->post( + channel_message<Signature>(0, + static_cast<Args&&>(args)...)); + } + + channel_receive<Payload>* op_; + }; + + // Destroy a base channel implementation. + void base_destroy(base_implementation_type& impl); + + // Helper function to start an asynchronous put operation. + template <typename Traits, typename... Signatures> + void start_send_op(implementation_type<Traits, Signatures...>& impl, + channel_send<typename implementation_type< + Traits, Signatures...>::payload_type>* send_op); + + // Helper function to start an asynchronous get operation. + template <typename Traits, typename... Signatures> + void start_receive_op(implementation_type<Traits, Signatures...>& impl, + channel_receive<typename implementation_type< + Traits, Signatures...>::payload_type>* receive_op); + + // Helper class used to implement per-operation cancellation. + template <typename Traits, typename... Signatures> + class op_cancellation + { + public: + op_cancellation(channel_service* s, + implementation_type<Traits, Signatures...>* impl) + : service_(s), + impl_(impl) + { + } + + void operator()(cancellation_type_t type) + { + if (!!(type & + (cancellation_type::terminal + | cancellation_type::partial + | cancellation_type::total))) + { + service_->cancel_by_key(*impl_, this); + } + } + + private: + channel_service* service_; + implementation_type<Traits, Signatures...>* impl_; + }; + + // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +// The implementation for a specific value type. +template <typename Mutex> +template <typename Traits, typename... Signatures> +struct channel_service<Mutex>::implementation_type : base_implementation_type +{ + // The traits type associated with the channel. + typedef typename Traits::template rebind<Signatures...>::other traits_type; + + // Type of an element stored in the buffer. + typedef conditional_t< + has_signature< + typename traits_type::receive_cancelled_signature, + Signatures... + >::value, + conditional_t< + has_signature< + typename traits_type::receive_closed_signature, + Signatures... + >::value, + channel_payload<Signatures...>, + channel_payload< + Signatures..., + typename traits_type::receive_closed_signature + > + >, + conditional_t< + has_signature< + typename traits_type::receive_closed_signature, + Signatures..., + typename traits_type::receive_cancelled_signature + >::value, + channel_payload< + Signatures..., + typename traits_type::receive_cancelled_signature + >, + channel_payload< + Signatures..., + typename traits_type::receive_cancelled_signature, + typename traits_type::receive_closed_signature + > + > + > payload_type; + + // Move from another buffer. + void buffer_move_from(implementation_type& other) + { + buffer_ = static_cast< + typename traits_type::template container<payload_type>::type&&>( + other.buffer_); + other.buffer_clear(); + } + + // Get number of buffered elements. + std::size_t buffer_size() const + { + return buffer_.size(); + } + + // Push a new value to the back of the buffer. + void buffer_push(payload_type payload) + { + buffer_.push_back(static_cast<payload_type&&>(payload)); + } + + // Push new values to the back of the buffer. + std::size_t buffer_push_n(std::size_t count, payload_type payload) + { + std::size_t i = 0; + for (; i < count && buffer_.size() < this->max_buffer_size_; ++i) + buffer_.push_back(payload); + return i; + } + + // Get the element at the front of the buffer. + payload_type buffer_front() + { + return static_cast<payload_type&&>(buffer_.front()); + } + + // Pop a value from the front of the buffer. + void buffer_pop() + { + buffer_.pop_front(); + } + + // Clear all buffered values. + void buffer_clear() + { + buffer_.clear(); + } + +private: + // Buffered values. + typename traits_type::template container<payload_type>::type buffer_; +}; + +// The implementation for a void value type. +template <typename Mutex> +template <typename Traits, typename R> +struct channel_service<Mutex>::implementation_type<Traits, R()> + : channel_service::base_implementation_type +{ + // The traits type associated with the channel. + typedef typename Traits::template rebind<R()>::other traits_type; + + // Type of an element stored in the buffer. + typedef conditional_t< + has_signature< + typename traits_type::receive_cancelled_signature, + R() + >::value, + conditional_t< + has_signature< + typename traits_type::receive_closed_signature, + R() + >::value, + channel_payload<R()>, + channel_payload< + R(), + typename traits_type::receive_closed_signature + > + >, + conditional_t< + has_signature< + typename traits_type::receive_closed_signature, + R(), + typename traits_type::receive_cancelled_signature + >::value, + channel_payload< + R(), + typename traits_type::receive_cancelled_signature + >, + channel_payload< + R(), + typename traits_type::receive_cancelled_signature, + typename traits_type::receive_closed_signature + > + > + > payload_type; + + // Construct with empty buffer. + implementation_type() + : buffer_(0) + { + } + + // Move from another buffer. + void buffer_move_from(implementation_type& other) + { + buffer_ = other.buffer_; + other.buffer_ = 0; + } + + // Get number of buffered elements. + std::size_t buffer_size() const + { + return buffer_; + } + + // Push a new value to the back of the buffer. + void buffer_push(payload_type) + { + ++buffer_; + } + + // Push new values to the back of the buffer. + std::size_t buffer_push_n(std::size_t count, payload_type) + { + std::size_t available = this->max_buffer_size_ - buffer_; + count = (count < available) ? count : available; + buffer_ += count; + return count; + } + + // Get the element at the front of the buffer. + payload_type buffer_front() + { + return payload_type(channel_message<R()>(0)); + } + + // Pop a value from the front of the buffer. + void buffer_pop() + { + --buffer_; + } + + // Clear all values from the buffer. + void buffer_clear() + { + buffer_ = 0; + } + +private: + // Number of buffered "values". + std::size_t buffer_; +}; + +// The implementation for an error_code signature. +template <typename Mutex> +template <typename Traits, typename R> +struct channel_service<Mutex>::implementation_type< + Traits, R(asio::error_code)> + : channel_service::base_implementation_type +{ + // The traits type associated with the channel. + typedef typename Traits::template rebind<R(asio::error_code)>::other + traits_type; + + // Type of an element stored in the buffer. + typedef conditional_t< + has_signature< + typename traits_type::receive_cancelled_signature, + R(asio::error_code) + >::value, + conditional_t< + has_signature< + typename traits_type::receive_closed_signature, + R(asio::error_code) + >::value, + channel_payload<R(asio::error_code)>, + channel_payload< + R(asio::error_code), + typename traits_type::receive_closed_signature + > + >, + conditional_t< + has_signature< + typename traits_type::receive_closed_signature, + R(asio::error_code), + typename traits_type::receive_cancelled_signature + >::value, + channel_payload< + R(asio::error_code), + typename traits_type::receive_cancelled_signature + >, + channel_payload< + R(asio::error_code), + typename traits_type::receive_cancelled_signature, + typename traits_type::receive_closed_signature + > + > + > payload_type; + + // Construct with empty buffer. + implementation_type() + : size_(0) + { + first_.count_ = 0; + } + + // Move from another buffer. + void buffer_move_from(implementation_type& other) + { + size_ = other.buffer_; + other.size_ = 0; + first_ = other.first_; + other.first.count_ = 0; + rest_ = static_cast< + typename traits_type::template container<buffered_value>::type&&>( + other.rest_); + other.buffer_clear(); + } + + // Get number of buffered elements. + std::size_t buffer_size() const + { + return size_; + } + + // Push a new value to the back of the buffer. + void buffer_push(payload_type payload) + { + buffered_value& last = rest_.empty() ? first_ : rest_.back(); + if (last.count_ == 0) + { + value_handler handler{last.value_}; + payload.receive(handler); + last.count_ = 1; + } + else + { + asio::error_code value{last.value_}; + value_handler handler{value}; + payload.receive(handler); + if (last.value_ == value) + ++last.count_; + else + rest_.push_back({value, 1}); + } + ++size_; + } + + // Push new values to the back of the buffer. + std::size_t buffer_push_n(std::size_t count, payload_type payload) + { + std::size_t available = this->max_buffer_size_ - size_; + count = (count < available) ? count : available; + if (count > 0) + { + buffered_value& last = rest_.empty() ? first_ : rest_.back(); + if (last.count_ == 0) + { + payload.receive(value_handler{last.value_}); + last.count_ = count; + } + else + { + asio::error_code value{last.value_}; + payload.receive(value_handler{value}); + if (last.value_ == value) + last.count_ += count; + else + rest_.push_back({value, count}); + } + size_ += count; + } + return count; + } + + // Get the element at the front of the buffer. + payload_type buffer_front() + { + return payload_type({0, first_.value_}); + } + + // Pop a value from the front of the buffer. + void buffer_pop() + { + --size_; + if (--first_.count_ == 0 && !rest_.empty()) + { + first_ = rest_.front(); + rest_.pop_front(); + } + } + + // Clear all values from the buffer. + void buffer_clear() + { + size_ = 0; + first_.count_ == 0; + rest_.clear(); + } + +private: + struct buffered_value + { + asio::error_code value_; + std::size_t count_; + }; + + struct value_handler + { + asio::error_code& target_; + + template <typename... Args> + void operator()(const asio::error_code& value, Args&&...) + { + target_ = value; + } + }; + + buffered_value& last_value() + { + return rest_.empty() ? first_ : rest_.back(); + } + + // Total number of buffered values. + std::size_t size_; + + // The first buffered value is maintained as a separate data member to avoid + // allocating space in the container in the common case. + buffered_value first_; + + // The rest of the buffered values. + typename traits_type::template container<buffered_value>::type rest_; +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/detail/impl/channel_service.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/coro_completion_handler.hpp b/3rdparty/asio/include/asio/experimental/detail/coro_completion_handler.hpp new file mode 100644 index 00000000000..52809134cb0 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/coro_completion_handler.hpp @@ -0,0 +1,169 @@ +// +// experimental/detail/coro_completion_handler.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_DETAIL_CORO_COMPLETION_HANDLER_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CORO_COMPLETION_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/deferred.hpp" +#include "asio/experimental/coro.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Promise, typename... Args> +struct coro_completion_handler +{ + coro_completion_handler(coroutine_handle<Promise> h, + std::optional<std::tuple<Args...>>& result) + : self(h), + result(result) + { + } + + coro_completion_handler(coro_completion_handler&&) = default; + + coroutine_handle<Promise> self; + + std::optional<std::tuple<Args...>>& result; + + using promise_type = Promise; + + void operator()(Args... args) + { + result.emplace(std::move(args)...); + self.resume(); + } + + using allocator_type = typename promise_type::allocator_type; + allocator_type get_allocator() const noexcept + { + return self.promise().get_allocator(); + } + + using executor_type = typename promise_type::executor_type; + executor_type get_executor() const noexcept + { + return self.promise().get_executor(); + } + + using cancellation_slot_type = typename promise_type::cancellation_slot_type; + cancellation_slot_type get_cancellation_slot() const noexcept + { + return self.promise().get_cancellation_slot(); + } +}; + +template <typename Signature> +struct coro_completion_handler_type; + +template <typename... Args> +struct coro_completion_handler_type<void(Args...)> +{ + using type = std::tuple<Args...>; + + template <typename Promise> + using completion_handler = coro_completion_handler<Promise, Args...>; +}; + +template <typename Signature> +using coro_completion_handler_type_t = + typename coro_completion_handler_type<Signature>::type; + +inline void coro_interpret_result(std::tuple<>&&) +{ +} + +template <typename... Args> +inline auto coro_interpret_result(std::tuple<Args...>&& args) +{ + return std::move(args); +} + +template <typename... Args> +auto coro_interpret_result(std::tuple<std::exception_ptr, Args...>&& args) +{ + if (std::get<0>(args)) + std::rethrow_exception(std::get<0>(args)); + + return std::apply( + [](auto, auto&&... rest) + { + return std::make_tuple(std::move(rest)...); + }, std::move(args)); +} + +template <typename... Args> +auto coro_interpret_result( + std::tuple<asio::error_code, Args...>&& args) +{ + if (std::get<0>(args)) + asio::detail::throw_exception( + asio::system_error(std::get<0>(args))); + + return std::apply( + [](auto, auto&&... rest) + { + return std::make_tuple(std::move(rest)...); + }, std::move(args)); +} + +template <typename Arg> +inline auto coro_interpret_result(std::tuple<Arg>&& args) +{ + return std::get<0>(std::move(args)); +} + +template <typename Arg> +auto coro_interpret_result(std::tuple<std::exception_ptr, Arg>&& args) +{ + if (std::get<0>(args)) + std::rethrow_exception(std::get<0>(args)); + return std::get<1>(std::move(args)); +} + +inline auto coro_interpret_result( + std::tuple<asio::error_code>&& args) +{ + if (std::get<0>(args)) + asio::detail::throw_exception( + asio::system_error(std::get<0>(args))); +} + +inline auto coro_interpret_result(std::tuple<std::exception_ptr>&& args) +{ + if (std::get<0>(args)) + std::rethrow_exception(std::get<0>(args)); +} + +template <typename Arg> +auto coro_interpret_result(std::tuple<asio::error_code, Arg>&& args) +{ + if (std::get<0>(args)) + asio::detail::throw_exception( + asio::system_error(std::get<0>(args))); + return std::get<1>(std::move(args)); +} + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_CORO_COMPLETION_HANDLER_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/coro_promise_allocator.hpp b/3rdparty/asio/include/asio/experimental/detail/coro_promise_allocator.hpp new file mode 100644 index 00000000000..328646968f3 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/coro_promise_allocator.hpp @@ -0,0 +1,141 @@ +// +// experimental/detail/coro_promise_allocator.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_DETAIL_CORO_PROMISE_ALLOCATOR_HPP +#define ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP + +#include "asio/detail/config.hpp" +#include "asio/experimental/coro_traits.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +/// Allocate the memory and put the allocator behind the coro memory +template <typename AllocatorType> +void* allocate_coroutine(const std::size_t size, AllocatorType alloc_) +{ + using alloc_type = typename std::allocator_traits<AllocatorType>::template + rebind_alloc<unsigned char>; + alloc_type alloc{alloc_}; + + const auto align_needed = size % alignof(alloc_type); + const auto align_offset = align_needed != 0 + ? alignof(alloc_type) - align_needed : 0ull; + const auto alloc_size = size + sizeof(alloc_type) + align_offset; + const auto raw = + std::allocator_traits<alloc_type>::allocate(alloc, alloc_size); + new(raw + size + align_offset) alloc_type(std::move(alloc)); + + return raw; +} + +/// Deallocate the memory and destroy the allocator in the coro memory. +template <typename AllocatorType> +void deallocate_coroutine(void* raw_, const std::size_t size) +{ + using alloc_type = typename std::allocator_traits<AllocatorType>::template + rebind_alloc<unsigned char>; + + const auto raw = static_cast<unsigned char *>(raw_); + + const auto align_needed = size % alignof(alloc_type); + const auto align_offset = align_needed != 0 + ? alignof(alloc_type) - align_needed : 0ull; + const auto alloc_size = size + sizeof(alloc_type) + align_offset; + + auto alloc_p = reinterpret_cast<alloc_type *>(raw + size + align_offset); + auto alloc = std::move(*alloc_p); + alloc_p->~alloc_type(); + std::allocator_traits<alloc_type>::deallocate(alloc, raw, alloc_size); +} + +template <typename T> +constexpr std::size_t variadic_first(std::size_t = 0u) +{ + return std::numeric_limits<std::size_t>::max(); +} + + +template <typename T, typename First, typename... Args> +constexpr std::size_t variadic_first(std::size_t pos = 0u) +{ + if constexpr (std::is_same_v<std::decay_t<First>, T>) + return pos; + else + return variadic_first<T, Args...>(pos+1); +} + +template <std::size_t Idx, typename First, typename... Args> + requires (Idx <= sizeof...(Args)) +constexpr decltype(auto) get_variadic(First&& first, Args&&... args) +{ + if constexpr (Idx == 0u) + return static_cast<First>(first); + else + return get_variadic<Idx-1u>(static_cast<Args>(args)...); +} + +template <std::size_t Idx> +constexpr decltype(auto) get_variadic(); + +template <typename Allocator> +struct coro_promise_allocator +{ + using allocator_type = Allocator; + allocator_type get_allocator() const {return alloc_;} + + template <typename... Args> + void* operator new(const std::size_t size, Args & ... args) + { + return allocate_coroutine(size, + get_variadic<variadic_first<std::allocator_arg_t, + std::decay_t<Args>...>() + 1u>(args...)); + } + + void operator delete(void* raw, const std::size_t size) + { + deallocate_coroutine<allocator_type>(raw, size); + } + + template <typename... Args> + coro_promise_allocator(Args&& ... args) + : alloc_( + get_variadic<variadic_first<std::allocator_arg_t, + std::decay_t<Args>...>() + 1u>(args...)) + { + } + +private: + allocator_type alloc_; +}; + +template <> +struct coro_promise_allocator<std::allocator<void>> +{ + using allocator_type = std::allocator<void>; + + template <typename... Args> + coro_promise_allocator(Args&&...) + { + } + + allocator_type get_allocator() const + { + return {}; + } +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#endif // ASIO_EXPERIMENTAL_DETAIL_CORO_PROMISE_ALLOCATOR_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/has_signature.hpp b/3rdparty/asio/include/asio/experimental/detail/has_signature.hpp new file mode 100644 index 00000000000..ea5dac8c69b --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/has_signature.hpp @@ -0,0 +1,54 @@ +// +// experimental/detail/has_signature.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_HAS_SIGNATURE_HPP +#define ASIO_EXPERIMENTAL_DETAIL_HAS_SIGNATURE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename S, typename... Signatures> +struct has_signature; + +template <typename S, typename... Signatures> +struct has_signature; + +template <typename S> +struct has_signature<S> : false_type +{ +}; + +template <typename S, typename... Signatures> +struct has_signature<S, S, Signatures...> : true_type +{ +}; + +template <typename S, typename Head, typename... Tail> +struct has_signature<S, Head, Tail...> : has_signature<S, Tail...> +{ +}; + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_HAS_SIGNATURE_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/impl/channel_service.hpp b/3rdparty/asio/include/asio/experimental/detail/impl/channel_service.hpp new file mode 100644 index 00000000000..797c9f433c7 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/impl/channel_service.hpp @@ -0,0 +1,621 @@ +// +// experimental/detail/impl/channel_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_DETAIL_IMPL_CHANNEL_SERVICE_HPP +#define ASIO_EXPERIMENTAL_DETAIL_IMPL_CHANNEL_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +template <typename Mutex> +inline channel_service<Mutex>::channel_service( + asio::execution_context& ctx) + : asio::detail::execution_context_service_base<channel_service>(ctx), + mutex_(), + impl_list_(0) +{ +} + +template <typename Mutex> +inline void channel_service<Mutex>::shutdown() +{ + // Abandon all pending operations. + asio::detail::op_queue<channel_operation> ops; + asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + ops.push(impl->waiters_); + impl = impl->next_; + } +} + +template <typename Mutex> +inline void channel_service<Mutex>::construct( + channel_service<Mutex>::base_implementation_type& impl, + std::size_t max_buffer_size) +{ + impl.max_buffer_size_ = max_buffer_size; + impl.receive_state_ = block; + impl.send_state_ = max_buffer_size ? buffer : block; + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::destroy( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl) +{ + cancel(impl); + base_destroy(impl); +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::move_construct( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + channel_service<Mutex>::implementation_type< + Traits, Signatures...>& other_impl) +{ + impl.max_buffer_size_ = other_impl.max_buffer_size_; + impl.receive_state_ = other_impl.receive_state_; + other_impl.receive_state_ = block; + impl.send_state_ = other_impl.send_state_; + other_impl.send_state_ = other_impl.max_buffer_size_ ? buffer : block; + impl.buffer_move_from(other_impl); + + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::move_assign( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + channel_service& other_service, + channel_service<Mutex>::implementation_type< + Traits, Signatures...>& other_impl) +{ + cancel(impl); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.max_buffer_size_ = other_impl.max_buffer_size_; + impl.receive_state_ = other_impl.receive_state_; + other_impl.receive_state_ = block; + impl.send_state_ = other_impl.send_state_; + other_impl.send_state_ = other_impl.max_buffer_size_ ? buffer : block; + impl.buffer_move_from(other_impl); + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +template <typename Mutex> +inline void channel_service<Mutex>::base_destroy( + channel_service<Mutex>::base_implementation_type& impl) +{ + // Remove implementation from linked list of all implementations. + asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +template <typename Mutex> +inline std::size_t channel_service<Mutex>::capacity( + const channel_service<Mutex>::base_implementation_type& impl) + const noexcept +{ + typename Mutex::scoped_lock lock(impl.mutex_); + + return impl.max_buffer_size_; +} + +template <typename Mutex> +inline bool channel_service<Mutex>::is_open( + const channel_service<Mutex>::base_implementation_type& impl) + const noexcept +{ + typename Mutex::scoped_lock lock(impl.mutex_); + + return impl.send_state_ != closed; +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::reset( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl) +{ + cancel(impl); + + typename Mutex::scoped_lock lock(impl.mutex_); + + impl.receive_state_ = block; + impl.send_state_ = impl.max_buffer_size_ ? buffer : block; + impl.buffer_clear(); +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::close( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl) +{ + typedef typename implementation_type<Traits, + Signatures...>::traits_type traits_type; + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + if (impl.receive_state_ == block) + { + while (channel_operation* op = impl.waiters_.front()) + { + impl.waiters_.pop(); + traits_type::invoke_receive_closed( + post_receive<payload_type, + typename traits_type::receive_closed_signature>( + static_cast<channel_receive<payload_type>*>(op))); + } + } + + impl.send_state_ = closed; + if (impl.receive_state_ != buffer) + impl.receive_state_ = closed; +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::cancel( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl) +{ + typedef typename implementation_type<Traits, + Signatures...>::traits_type traits_type; + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + while (channel_operation* op = impl.waiters_.front()) + { + if (impl.send_state_ == block) + { + impl.waiters_.pop(); + static_cast<channel_send<payload_type>*>(op)->cancel(); + } + else + { + impl.waiters_.pop(); + traits_type::invoke_receive_cancelled( + post_receive<payload_type, + typename traits_type::receive_cancelled_signature>( + static_cast<channel_receive<payload_type>*>(op))); + } + } + + if (impl.receive_state_ == waiter) + impl.receive_state_ = block; + if (impl.send_state_ == waiter) + impl.send_state_ = impl.max_buffer_size_ ? buffer : block; +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::cancel_by_key( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + void* cancellation_key) +{ + typedef typename implementation_type<Traits, + Signatures...>::traits_type traits_type; + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + asio::detail::op_queue<channel_operation> other_ops; + while (channel_operation* op = impl.waiters_.front()) + { + if (op->cancellation_key_ == cancellation_key) + { + if (impl.send_state_ == block) + { + impl.waiters_.pop(); + static_cast<channel_send<payload_type>*>(op)->cancel(); + } + else + { + impl.waiters_.pop(); + traits_type::invoke_receive_cancelled( + post_receive<payload_type, + typename traits_type::receive_cancelled_signature>( + static_cast<channel_receive<payload_type>*>(op))); + } + } + else + { + impl.waiters_.pop(); + other_ops.push(op); + } + } + impl.waiters_.push(other_ops); + + if (impl.waiters_.empty()) + { + if (impl.receive_state_ == waiter) + impl.receive_state_ = block; + if (impl.send_state_ == waiter) + impl.send_state_ = impl.max_buffer_size_ ? buffer : block; + } +} + +template <typename Mutex> +inline bool channel_service<Mutex>::ready( + const channel_service<Mutex>::base_implementation_type& impl) + const noexcept +{ + typename Mutex::scoped_lock lock(impl.mutex_); + + return impl.receive_state_ != block; +} + +template <typename Mutex> +template <typename Message, typename Traits, + typename... Signatures, typename... Args> +bool channel_service<Mutex>::try_send( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + bool via_dispatch, Args&&... args) +{ + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + switch (impl.send_state_) + { + case block: + { + return false; + } + case buffer: + { + impl.buffer_push(Message(0, static_cast<Args&&>(args)...)); + impl.receive_state_ = buffer; + if (impl.buffer_size() == impl.max_buffer_size_) + impl.send_state_ = block; + return true; + } + case waiter: + { + payload_type payload(Message(0, static_cast<Args&&>(args)...)); + channel_receive<payload_type>* receive_op = + static_cast<channel_receive<payload_type>*>(impl.waiters_.front()); + impl.waiters_.pop(); + if (impl.waiters_.empty()) + impl.send_state_ = impl.max_buffer_size_ ? buffer : block; + lock.unlock(); + if (via_dispatch) + receive_op->dispatch(static_cast<payload_type&&>(payload)); + else + receive_op->post(static_cast<payload_type&&>(payload)); + return true; + } + case closed: + default: + { + return false; + } + } +} + +template <typename Mutex> +template <typename Message, typename Traits, + typename... Signatures, typename... Args> +std::size_t channel_service<Mutex>::try_send_n( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + std::size_t count, bool via_dispatch, Args&&... args) +{ + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + if (count == 0) + return 0; + + switch (impl.send_state_) + { + case block: + return 0; + case buffer: + case waiter: + break; + case closed: + default: + return 0; + } + + payload_type payload(Message(0, static_cast<Args&&>(args)...)); + + for (std::size_t i = 0; i < count; ++i) + { + switch (impl.send_state_) + { + case block: + { + return i; + } + case buffer: + { + i += impl.buffer_push_n(count - i, + static_cast<payload_type&&>(payload)); + impl.receive_state_ = buffer; + if (impl.buffer_size() == impl.max_buffer_size_) + impl.send_state_ = block; + return i; + } + case waiter: + { + channel_receive<payload_type>* receive_op = + static_cast<channel_receive<payload_type>*>(impl.waiters_.front()); + impl.waiters_.pop(); + if (impl.waiters_.empty()) + impl.send_state_ = impl.max_buffer_size_ ? buffer : block; + lock.unlock(); + if (via_dispatch) + receive_op->dispatch(payload); + else + receive_op->post(payload); + break; + } + case closed: + default: + { + return i; + } + } + } + + return count; +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::start_send_op( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + channel_send<typename implementation_type< + Traits, Signatures...>::payload_type>* send_op) +{ + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + switch (impl.send_state_) + { + case block: + { + impl.waiters_.push(send_op); + if (impl.receive_state_ == block) + impl.receive_state_ = waiter; + return; + } + case buffer: + { + impl.buffer_push(send_op->get_payload()); + impl.receive_state_ = buffer; + if (impl.buffer_size() == impl.max_buffer_size_) + impl.send_state_ = block; + send_op->immediate(); + break; + } + case waiter: + { + channel_receive<payload_type>* receive_op = + static_cast<channel_receive<payload_type>*>(impl.waiters_.front()); + impl.waiters_.pop(); + if (impl.waiters_.empty()) + impl.send_state_ = impl.max_buffer_size_ ? buffer : block; + receive_op->post(send_op->get_payload()); + send_op->immediate(); + break; + } + case closed: + default: + { + send_op->close(); + break; + } + } +} + +template <typename Mutex> +template <typename Traits, typename... Signatures, typename Handler> +bool channel_service<Mutex>::try_receive( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + Handler&& handler) +{ + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + switch (impl.receive_state_) + { + case block: + { + return false; + } + case buffer: + { + payload_type payload(impl.buffer_front()); + if (channel_send<payload_type>* send_op = + static_cast<channel_send<payload_type>*>(impl.waiters_.front())) + { + impl.buffer_pop(); + impl.buffer_push(send_op->get_payload()); + impl.waiters_.pop(); + send_op->post(); + } + else + { + impl.buffer_pop(); + if (impl.buffer_size() == 0) + impl.receive_state_ = (impl.send_state_ == closed) ? closed : block; + impl.send_state_ = (impl.send_state_ == closed) ? closed : buffer; + } + lock.unlock(); + asio::detail::non_const_lvalue<Handler> handler2(handler); + channel_handler<payload_type, decay_t<Handler>>( + static_cast<payload_type&&>(payload), handler2.value)(); + return true; + } + case waiter: + { + channel_send<payload_type>* send_op = + static_cast<channel_send<payload_type>*>(impl.waiters_.front()); + payload_type payload = send_op->get_payload(); + impl.waiters_.pop(); + if (impl.waiters_.front() == 0) + impl.receive_state_ = (impl.send_state_ == closed) ? closed : block; + send_op->post(); + lock.unlock(); + asio::detail::non_const_lvalue<Handler> handler2(handler); + channel_handler<payload_type, decay_t<Handler>>( + static_cast<payload_type&&>(payload), handler2.value)(); + return true; + } + case closed: + default: + { + return false; + } + } +} + +template <typename Mutex> +template <typename Traits, typename... Signatures> +void channel_service<Mutex>::start_receive_op( + channel_service<Mutex>::implementation_type<Traits, Signatures...>& impl, + channel_receive<typename implementation_type< + Traits, Signatures...>::payload_type>* receive_op) +{ + typedef typename implementation_type<Traits, + Signatures...>::traits_type traits_type; + typedef typename implementation_type<Traits, + Signatures...>::payload_type payload_type; + + typename Mutex::scoped_lock lock(impl.mutex_); + + switch (impl.receive_state_) + { + case block: + { + impl.waiters_.push(receive_op); + if (impl.send_state_ != closed) + impl.send_state_ = waiter; + return; + } + case buffer: + { + payload_type payload( + static_cast<payload_type&&>(impl.buffer_front())); + if (channel_send<payload_type>* send_op = + static_cast<channel_send<payload_type>*>(impl.waiters_.front())) + { + impl.buffer_pop(); + impl.buffer_push(send_op->get_payload()); + impl.waiters_.pop(); + send_op->post(); + } + else + { + impl.buffer_pop(); + if (impl.buffer_size() == 0) + impl.receive_state_ = (impl.send_state_ == closed) ? closed : block; + impl.send_state_ = (impl.send_state_ == closed) ? closed : buffer; + } + receive_op->immediate(static_cast<payload_type&&>(payload)); + break; + } + case waiter: + { + channel_send<payload_type>* send_op = + static_cast<channel_send<payload_type>*>(impl.waiters_.front()); + payload_type payload = send_op->get_payload(); + impl.waiters_.pop(); + if (impl.waiters_.front() == 0) + impl.receive_state_ = (impl.send_state_ == closed) ? closed : block; + send_op->post(); + receive_op->immediate(static_cast<payload_type&&>(payload)); + break; + } + case closed: + default: + { + traits_type::invoke_receive_closed( + post_receive<payload_type, + typename traits_type::receive_closed_signature>(receive_op)); + break; + } + } +} + +} // namespace detail +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_DETAIL_IMPL_CHANNEL_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/experimental/detail/partial_promise.hpp b/3rdparty/asio/include/asio/experimental/detail/partial_promise.hpp new file mode 100644 index 00000000000..8495af2f0ba --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/detail/partial_promise.hpp @@ -0,0 +1,197 @@ +// +// experimental/detail/partial_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_DETAIL_PARTIAL_PROMISE_HPP +#define ASIO_EXPERIMENTAL_DETAIL_PARTIAL_PROMISE_HPP + +#include "asio/detail/config.hpp" +#include "asio/append.hpp" +#include "asio/awaitable.hpp" +#include "asio/experimental/coro_traits.hpp" + +#if defined(ASIO_HAS_STD_COROUTINE) +# include <coroutine> +#else // defined(ASIO_HAS_STD_COROUTINE) +# include <experimental/coroutine> +#endif // defined(ASIO_HAS_STD_COROUTINE) + +namespace asio { +namespace experimental { +namespace detail { + +#if defined(ASIO_HAS_STD_COROUTINE) + +using std::coroutine_handle; +using std::coroutine_traits; +using std::suspend_never; +using std::suspend_always; +using std::noop_coroutine; + +#else // defined(ASIO_HAS_STD_COROUTINE) + +using std::experimental::coroutine_handle; +using std::experimental::coroutine_traits; +using std::experimental::suspend_never; +using std::experimental::suspend_always; +using std::experimental::noop_coroutine; + +#endif // defined(ASIO_HAS_STD_COROUTINE) + +struct partial_coro +{ + coroutine_handle<void> handle{nullptr}; +}; + +template <typename Allocator> +struct partial_promise_base +{ + template <typename Executor, typename Token, typename... Args> + void* operator new(const std::size_t size, Executor&, Token& tk, Args&...) + { + return allocate_coroutine<Allocator>(size, get_associated_allocator(tk)); + } + + void operator delete(void* raw, const std::size_t size) + { + deallocate_coroutine<Allocator>(raw, size); + } +}; + +template <> +struct partial_promise_base<std::allocator<void>> +{ +}; + +template <typename Allocator> +struct partial_promise : partial_promise_base<Allocator> +{ + auto initial_suspend() noexcept + { + return asio::detail::suspend_always{}; + } + + auto final_suspend() noexcept + { + struct awaitable_t + { + partial_promise *p; + + constexpr bool await_ready() noexcept { return true; } + + auto await_suspend(asio::detail::coroutine_handle<>) noexcept + { + p->get_return_object().handle.destroy(); + } + + constexpr void await_resume() noexcept {} + }; + + return awaitable_t{this}; + } + + void return_void() {} + + partial_coro get_return_object() + { + return partial_coro{coroutine_handle<partial_promise>::from_promise(*this)}; + } + + void unhandled_exception() + { + assert(false); + } +}; + + + +}; // namespace detail +} // namespace experimental +} // namespace asio + +#if defined(ASIO_HAS_STD_COROUTINE) + +namespace std { + +template <typename Executor, typename Completion, typename... Args> +struct coroutine_traits< + asio::experimental::detail::partial_coro, + Executor, Completion, Args...> +{ + using promise_type = + asio::experimental::detail::partial_promise< + asio::associated_allocator_t<Completion>>; +}; + +} // namespace std + +#else // defined(ASIO_HAS_STD_COROUTINE) + +namespace std { namespace experimental { + +template <typename Executor, typename Completion, typename... Args> +struct coroutine_traits< + asio::experimental::detail::partial_coro, + Executor, Completion, Args...> +{ + using promise_type = + asio::experimental::detail::partial_promise< + asio::associated_allocator_t<Completion>>; +}; + +}} // namespace std::experimental + +#endif // defined(ASIO_HAS_STD_COROUTINE) + +namespace asio { +namespace experimental { +namespace detail { + +template <execution::executor Executor, + typename CompletionToken, typename... Args> +partial_coro post_coroutine(Executor exec, + CompletionToken token, Args&&... args) noexcept +{ + post(exec, asio::append(std::move(token), std::move(args)...)); + co_return; +} + +template <detail::execution_context Context, + typename CompletionToken, typename... Args> +partial_coro post_coroutine(Context& ctx, + CompletionToken token, Args&&... args) noexcept +{ + post(ctx, asio::append(std::move(token), std::move(args)...)); + co_return; +} + +template <execution::executor Executor, + typename CompletionToken, typename... Args> +partial_coro dispatch_coroutine(Executor exec, + CompletionToken token, Args&&... args) noexcept +{ + dispatch(exec, asio::append(std::move(token), std::move(args)...)); + co_return; +} + +template <detail::execution_context Context, + typename CompletionToken, typename... Args> +partial_coro dispatch_coroutine(Context& ctx, + CompletionToken token, Args &&... args) noexcept +{ + dispatch(ctx, asio::append(std::move(token), std::move(args)...)); + co_return; +} + +} // namespace detail +} // namespace experimental +} // namespace asio + +#endif // ASIO_EXPERIMENTAL_DETAIL_PARTIAL_PROMISE_HPP diff --git a/3rdparty/asio/include/asio/experimental/impl/as_single.hpp b/3rdparty/asio/include/asio/experimental/impl/as_single.hpp new file mode 100644 index 00000000000..d183cf5679e --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/as_single.hpp @@ -0,0 +1,176 @@ +// +// experimental/impl/as_single.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_EXPERIMENTAL_AS_SINGLE_HPP +#define ASIO_IMPL_EXPERIMENTAL_AS_SINGLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <tuple> +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +// Class to adapt a as_single_t as a completion handler. +template <typename Handler> +class as_single_handler +{ +public: + typedef void result_type; + + template <typename CompletionToken> + as_single_handler(as_single_t<CompletionToken> e) + : handler_(static_cast<CompletionToken&&>(e.token_)) + { + } + + template <typename RedirectedHandler> + as_single_handler(RedirectedHandler&& h) + : handler_(static_cast<RedirectedHandler&&>(h)) + { + } + + void operator()() + { + static_cast<Handler&&>(handler_)(); + } + + template <typename Arg> + void operator()(Arg&& arg) + { + static_cast<Handler&&>(handler_)(static_cast<Arg&&>(arg)); + } + + template <typename... Args> + void operator()(Args&&... args) + { + static_cast<Handler&&>(handler_)( + std::make_tuple(static_cast<Args&&>(args)...)); + } + +//private: + Handler handler_; +}; + +template <typename Handler> +inline bool asio_handler_is_continuation( + as_single_handler<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Signature> +struct as_single_signature +{ + typedef Signature type; +}; + +template <typename R> +struct as_single_signature<R()> +{ + typedef R type(); +}; + +template <typename R, typename Arg> +struct as_single_signature<R(Arg)> +{ + typedef R type(Arg); +}; + +template <typename R, typename... Args> +struct as_single_signature<R(Args...)> +{ + typedef R type(std::tuple<decay_t<Args>...>); +}; + +} // namespace detail +} // namespace experimental + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename Signature> +struct async_result<experimental::as_single_t<CompletionToken>, Signature> +{ + template <typename Initiation> + struct init_wrapper + { + init_wrapper(Initiation init) + : initiation_(static_cast<Initiation&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + experimental::detail::as_single_handler<decay_t<Handler>>( + static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<CompletionToken, + typename experimental::detail::as_single_signature<Signature>::type>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<Args&&>(args)...)) + { + return async_initiate<CompletionToken, + typename experimental::detail::as_single_signature<Signature>::type>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<Args&&>(args)...); + } +}; + +template <template <typename, typename> class Associator, + typename Handler, typename DefaultCandidate> +struct associator<Associator, + experimental::detail::as_single_handler<Handler>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const experimental::detail::as_single_handler<Handler>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const experimental::detail::as_single_handler<Handler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_EXPERIMENTAL_AS_SINGLE_HPP diff --git a/3rdparty/asio/include/asio/experimental/impl/channel_error.ipp b/3rdparty/asio/include/asio/experimental/impl/channel_error.ipp new file mode 100644 index 00000000000..3f4b9829774 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/channel_error.ipp @@ -0,0 +1,61 @@ +// +// experimental/impl/channel_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_CHANNEL_ERROR_IPP +#define ASIO_EXPERIMENTAL_IMPL_CHANNEL_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/experimental/channel_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace error { +namespace detail { + +class channel_category : public asio::error_category +{ +public: + const char* name() const noexcept + { + return "asio.channel"; + } + + std::string message(int value) const + { + switch (value) + { + case channel_closed: return "Channel closed"; + case channel_cancelled: return "Channel cancelled"; + default: return "asio.channel error"; + } + } +}; + +} // namespace detail + +const asio::error_category& get_channel_category() +{ + static detail::channel_category instance; + return instance; +} + +} // namespace error +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_CHANNEL_ERROR_IPP diff --git a/3rdparty/asio/include/asio/experimental/impl/co_composed.hpp b/3rdparty/asio/include/asio/experimental/impl/co_composed.hpp new file mode 100644 index 00000000000..3eef2e2ee2c --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/co_composed.hpp @@ -0,0 +1,1174 @@ +// +// experimental/impl/co_composed.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP +#define ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <new> +#include <tuple> +#include <variant> +#include "asio/associated_cancellation_slot.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/cancellation_state.hpp" +#include "asio/detail/composed_work.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" + +#if defined(ASIO_HAS_STD_COROUTINE) +# include <coroutine> +#else // defined(ASIO_HAS_STD_COROUTINE) +# include <experimental/coroutine> +#endif // defined(ASIO_HAS_STD_COROUTINE) + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) +# include "asio/detail/source_location.hpp" +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +#if defined(ASIO_HAS_STD_COROUTINE) +using std::coroutine_handle; +using std::suspend_always; +using std::suspend_never; +#else // defined(ASIO_HAS_STD_COROUTINE) +using std::experimental::coroutine_handle; +using std::experimental::suspend_always; +using std::experimental::suspend_never; +#endif // defined(ASIO_HAS_STD_COROUTINE) + +using asio::detail::composed_io_executors; +using asio::detail::composed_work; +using asio::detail::composed_work_guard; +using asio::detail::get_composed_io_executor; +using asio::detail::make_composed_io_executors; +using asio::detail::recycling_allocator; +using asio::detail::throw_error; + +template <typename Executors, typename Handler, typename Return> +class co_composed_state; + +template <typename Executors, typename Handler, typename Return> +class co_composed_handler_base; + +template <typename Executors, typename Handler, typename Return> +class co_composed_promise; + +template <completion_signature... Signatures> +class co_composed_returns +{ +}; + +struct co_composed_on_suspend +{ + void (*fn_)(void*) = nullptr; + void* arg_ = nullptr; +}; + +template <typename... T> +struct co_composed_completion : std::tuple<T&&...> +{ + template <typename... U> + co_composed_completion(U&&... u) noexcept + : std::tuple<T&&...>(std::forward<U>(u)...) + { + } +}; + +template <typename Executors, typename Handler, + typename Return, typename Signature> +class co_composed_state_return_overload; + +template <typename Executors, typename Handler, + typename Return, typename R, typename... Args> +class co_composed_state_return_overload< + Executors, Handler, Return, R(Args...)> +{ +public: + using derived_type = co_composed_state<Executors, Handler, Return>; + using promise_type = co_composed_promise<Executors, Handler, Return>; + using return_type = std::tuple<Args...>; + + void on_cancellation_complete_with(Args... args) + { + derived_type& state = *static_cast<derived_type*>(this); + state.return_value_ = std::make_tuple(std::move(args)...); + state.cancellation_on_suspend_fn( + [](void* p) + { + auto& promise = *static_cast<promise_type*>(p); + + co_composed_handler_base<Executors, Handler, + Return> composed_handler(promise); + + Handler handler(std::move(promise.state().handler_)); + return_type result( + std::move(std::get<return_type>(promise.state().return_value_))); + + co_composed_handler_base<Executors, Handler, + Return>(std::move(composed_handler)); + + std::apply(std::move(handler), std::move(result)); + }); + } +}; + +template <typename Executors, typename Handler, typename Return> +class co_composed_state_return; + +template <typename Executors, typename Handler, typename... Signatures> +class co_composed_state_return< + Executors, Handler, co_composed_returns<Signatures...>> + : public co_composed_state_return_overload<Executors, + Handler, co_composed_returns<Signatures...>, Signatures>... +{ +public: + using co_composed_state_return_overload<Executors, + Handler, co_composed_returns<Signatures...>, + Signatures>::on_cancellation_complete_with...; + +private: + template <typename, typename, typename, typename> + friend class co_composed_promise_return_overload; + template <typename, typename, typename, typename> + friend class co_composed_state_return_overload; + + std::variant<std::monostate, + typename co_composed_state_return_overload< + Executors, Handler, co_composed_returns<Signatures...>, + Signatures>::return_type...> return_value_; +}; + +template <typename Executors, typename Handler, + typename Return, typename... Signatures> +struct co_composed_state_default_cancellation_on_suspend_impl; + +template <typename Executors, typename Handler, typename Return> +struct co_composed_state_default_cancellation_on_suspend_impl< + Executors, Handler, Return> +{ + static constexpr void (*fn())(void*) + { + return nullptr; + } +}; + +template <typename Executors, typename Handler, typename Return, + typename R, typename... Args, typename... Signatures> +struct co_composed_state_default_cancellation_on_suspend_impl< + Executors, Handler, Return, R(Args...), Signatures...> +{ + static constexpr void (*fn())(void*) + { + return co_composed_state_default_cancellation_on_suspend_impl< + Executors, Handler, Return, Signatures...>::fn(); + } +}; + +template <typename Executors, typename Handler, typename Return, + typename R, typename... Args, typename... Signatures> +struct co_composed_state_default_cancellation_on_suspend_impl<Executors, + Handler, Return, R(asio::error_code, Args...), Signatures...> +{ + using promise_type = co_composed_promise<Executors, Handler, Return>; + using return_type = std::tuple<asio::error_code, Args...>; + + static constexpr void (*fn())(void*) + { + if constexpr ((is_constructible<Args>::value && ...)) + { + return [](void* p) + { + auto& promise = *static_cast<promise_type*>(p); + + co_composed_handler_base<Executors, Handler, + Return> composed_handler(promise); + + Handler handler(std::move(promise.state().handler_)); + + co_composed_handler_base<Executors, Handler, + Return>(std::move(composed_handler)); + + std::move(handler)( + asio::error_code(asio::error::operation_aborted), + Args{}...); + }; + } + else + { + return co_composed_state_default_cancellation_on_suspend_impl< + Executors, Handler, Return, Signatures...>::fn(); + } + } +}; + +template <typename Executors, typename Handler, typename Return, + typename R, typename... Args, typename... Signatures> +struct co_composed_state_default_cancellation_on_suspend_impl<Executors, + Handler, Return, R(std::exception_ptr, Args...), Signatures...> +{ + using promise_type = co_composed_promise<Executors, Handler, Return>; + using return_type = std::tuple<std::exception_ptr, Args...>; + + static constexpr void (*fn())(void*) + { + if constexpr ((is_constructible<Args>::value && ...)) + { + return [](void* p) + { + auto& promise = *static_cast<promise_type*>(p); + + co_composed_handler_base<Executors, Handler, + Return> composed_handler(promise); + + Handler handler(std::move(promise.state().handler_)); + + co_composed_handler_base<Executors, Handler, + Return>(std::move(composed_handler)); + + std::move(handler)( + std::make_exception_ptr( + asio::system_error( + asio::error::operation_aborted, "co_await")), + Args{}...); + }; + } + else + { + return co_composed_state_default_cancellation_on_suspend_impl< + Executors, Handler, Return, Signatures...>::fn(); + } + } +}; + +template <typename Executors, typename Handler, typename Return> +struct co_composed_state_default_cancellation_on_suspend; + +template <typename Executors, typename Handler, typename... Signatures> +struct co_composed_state_default_cancellation_on_suspend< + Executors, Handler, co_composed_returns<Signatures...>> + : co_composed_state_default_cancellation_on_suspend_impl<Executors, + Handler, co_composed_returns<Signatures...>, Signatures...> +{ +}; + +template <typename Executors, typename Handler, typename Return> +class co_composed_state_cancellation +{ +public: + using cancellation_slot_type = cancellation_slot; + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return cancellation_state_.slot(); + } + + cancellation_state get_cancellation_state() const noexcept + { + return cancellation_state_; + } + + void reset_cancellation_state() + { + cancellation_state_ = cancellation_state( + (get_associated_cancellation_slot)( + static_cast<co_composed_state<Executors, Handler, Return>*>( + this)->handler())); + } + + template <typename Filter> + void reset_cancellation_state(Filter filter) + { + cancellation_state_ = cancellation_state( + (get_associated_cancellation_slot)( + static_cast<co_composed_state<Executors, Handler, Return>*>( + this)->handler()), filter, filter); + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(InFilter&& in_filter, OutFilter&& out_filter) + { + cancellation_state_ = cancellation_state( + (get_associated_cancellation_slot)( + static_cast<co_composed_state<Executors, Handler, Return>*>( + this)->handler()), + std::forward<InFilter>(in_filter), + std::forward<OutFilter>(out_filter)); + } + + cancellation_type_t cancelled() const noexcept + { + return cancellation_state_.cancelled(); + } + + void clear_cancellation_slot() noexcept + { + cancellation_state_.slot().clear(); + } + + [[nodiscard]] bool throw_if_cancelled() const noexcept + { + return throw_if_cancelled_; + } + + void throw_if_cancelled(bool b) noexcept + { + throw_if_cancelled_ = b; + } + + [[nodiscard]] bool complete_if_cancelled() const noexcept + { + return complete_if_cancelled_; + } + + void complete_if_cancelled(bool b) noexcept + { + complete_if_cancelled_ = b; + } + +private: + template <typename, typename, typename> + friend class co_composed_promise; + template <typename, typename, typename, typename> + friend class co_composed_state_return_overload; + + void cancellation_on_suspend_fn(void (*fn)(void*)) + { + cancellation_on_suspend_fn_ = fn; + } + + void check_for_cancellation_on_transform() + { + if (throw_if_cancelled_ && !!cancelled()) + throw_error(asio::error::operation_aborted, "co_await"); + } + + bool check_for_cancellation_on_suspend( + co_composed_promise<Executors, Handler, Return>& promise) noexcept + { + if (complete_if_cancelled_ && !!cancelled() && cancellation_on_suspend_fn_) + { + promise.state().work_.reset(); + promise.state().on_suspend_->fn_ = cancellation_on_suspend_fn_; + promise.state().on_suspend_->arg_ = &promise; + return false; + } + return true; + } + + cancellation_state cancellation_state_; + void (*cancellation_on_suspend_fn_)(void*) = + co_composed_state_default_cancellation_on_suspend< + Executors, Handler, Return>::fn(); + bool throw_if_cancelled_ = false; + bool complete_if_cancelled_ = true; +}; + +template <typename Executors, typename Handler, typename Return> + requires is_same< + typename associated_cancellation_slot< + Handler, cancellation_slot + >::asio_associated_cancellation_slot_is_unspecialised, + void>::value +class co_composed_state_cancellation<Executors, Handler, Return> +{ +public: + void reset_cancellation_state() + { + } + + template <typename Filter> + void reset_cancellation_state(Filter) + { + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(InFilter&&, OutFilter&&) + { + } + + cancellation_type_t cancelled() const noexcept + { + return cancellation_type::none; + } + + void clear_cancellation_slot() noexcept + { + } + + [[nodiscard]] bool throw_if_cancelled() const noexcept + { + return false; + } + + void throw_if_cancelled(bool) noexcept + { + } + + [[nodiscard]] bool complete_if_cancelled() const noexcept + { + return false; + } + + void complete_if_cancelled(bool) noexcept + { + } + +private: + template <typename, typename, typename> + friend class co_composed_promise; + template <typename, typename, typename, typename> + friend class co_composed_state_return_overload; + + void cancellation_on_suspend_fn(void (*)(void*)) + { + } + + void check_for_cancellation_on_transform() noexcept + { + } + + bool check_for_cancellation_on_suspend( + co_composed_promise<Executors, Handler, Return>&) noexcept + { + return true; + } +}; + +template <typename Executors, typename Handler, typename Return> +class co_composed_state + : public co_composed_state_return<Executors, Handler, Return>, + public co_composed_state_cancellation<Executors, Handler, Return> +{ +public: + using io_executor_type = typename composed_work_guard< + typename composed_work<Executors>::head_type>::executor_type; + + template <typename H> + co_composed_state(composed_io_executors<Executors>&& executors, + H&& h, co_composed_on_suspend& on_suspend) + : work_(std::move(executors)), + handler_(std::forward<H>(h)), + on_suspend_(&on_suspend) + { + this->reset_cancellation_state(enable_terminal_cancellation()); + } + + io_executor_type get_io_executor() const noexcept + { + return work_.head_.get_executor(); + } + + template <typename... Args> + [[nodiscard]] co_composed_completion<Args...> complete(Args&&... args) + requires requires { declval<Handler>()(std::forward<Args>(args)...); } + { + return co_composed_completion<Args...>(std::forward<Args>(args)...); + } + + const Handler& handler() const noexcept + { + return handler_; + } + +private: + template <typename, typename, typename> + friend class co_composed_handler_base; + template <typename, typename, typename> + friend class co_composed_promise; + template <typename, typename, typename, typename> + friend class co_composed_promise_return_overload; + template <typename, typename, typename> + friend class co_composed_state_cancellation; + template <typename, typename, typename, typename> + friend class co_composed_state_return_overload; + template <typename, typename, typename, typename...> + friend struct co_composed_state_default_cancellation_on_suspend_impl; + + composed_work<Executors> work_; + Handler handler_; + co_composed_on_suspend* on_suspend_; +}; + +template <typename Executors, typename Handler, typename Return> +class co_composed_handler_cancellation +{ +public: + using cancellation_slot_type = cancellation_slot; + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return static_cast< + const co_composed_handler_base<Executors, Handler, Return>*>( + this)->promise().state().get_cancellation_slot(); + } +}; + +template <typename Executors, typename Handler, typename Return> + requires is_same< + typename associated_cancellation_slot< + Handler, cancellation_slot + >::asio_associated_cancellation_slot_is_unspecialised, + void>::value +class co_composed_handler_cancellation<Executors, Handler, Return> +{ +}; + +template <typename Executors, typename Handler, typename Return> +class co_composed_handler_base : + public co_composed_handler_cancellation<Executors, Handler, Return> +{ +public: + co_composed_handler_base( + co_composed_promise<Executors, Handler, Return>& p) noexcept + : p_(&p) + { + } + + co_composed_handler_base(co_composed_handler_base&& other) noexcept + : p_(std::exchange(other.p_, nullptr)) + { + } + + ~co_composed_handler_base() + { + if (p_) [[unlikely]] + p_->destroy(); + } + + co_composed_promise<Executors, Handler, Return>& promise() const noexcept + { + return *p_; + } + +protected: + void resume(void* result) + { + co_composed_on_suspend on_suspend{}; + std::exchange(p_, nullptr)->resume(p_, result, on_suspend); + if (on_suspend.fn_) + on_suspend.fn_(on_suspend.arg_); + } + +private: + co_composed_promise<Executors, Handler, Return>* p_; +}; + +template <typename Executors, typename Handler, + typename Return, typename Signature> +class co_composed_handler; + +template <typename Executors, typename Handler, + typename Return, typename R, typename... Args> +class co_composed_handler<Executors, Handler, Return, R(Args...)> + : public co_composed_handler_base<Executors, Handler, Return> +{ +public: + using co_composed_handler_base<Executors, + Handler, Return>::co_composed_handler_base; + + using result_type = std::tuple<decay_t<Args>...>; + + template <typename... T> + void operator()(T&&... args) + { + result_type result(std::forward<T>(args)...); + this->resume(&result); + } + + static auto on_resume(void* result) + { + auto& args = *static_cast<result_type*>(result); + if constexpr (sizeof...(Args) == 0) + return; + else if constexpr (sizeof...(Args) == 1) + return std::move(std::get<0>(args)); + else + return std::move(args); + } +}; + +template <typename Executors, typename Handler, + typename Return, typename R, typename... Args> +class co_composed_handler<Executors, Handler, + Return, R(asio::error_code, Args...)> + : public co_composed_handler_base<Executors, Handler, Return> +{ +public: + using co_composed_handler_base<Executors, + Handler, Return>::co_composed_handler_base; + + using args_type = std::tuple<decay_t<Args>...>; + using result_type = std::tuple<asio::error_code, args_type>; + + template <typename... T> + void operator()(const asio::error_code& ec, T&&... args) + { + result_type result(ec, args_type(std::forward<T>(args)...)); + this->resume(&result); + } + + static auto on_resume(void* result) + { + auto& [ec, args] = *static_cast<result_type*>(result); + throw_error(ec); + if constexpr (sizeof...(Args) == 0) + return; + else if constexpr (sizeof...(Args) == 1) + return std::move(std::get<0>(args)); + else + return std::move(args); + } +}; + +template <typename Executors, typename Handler, + typename Return, typename R, typename... Args> +class co_composed_handler<Executors, Handler, + Return, R(std::exception_ptr, Args...)> + : public co_composed_handler_base<Executors, Handler, Return> +{ +public: + using co_composed_handler_base<Executors, + Handler, Return>::co_composed_handler_base; + + using args_type = std::tuple<decay_t<Args>...>; + using result_type = std::tuple<std::exception_ptr, args_type>; + + template <typename... T> + void operator()(std::exception_ptr ex, T&&... args) + { + result_type result(std::move(ex), args_type(std::forward<T>(args)...)); + this->resume(&result); + } + + static auto on_resume(void* result) + { + auto& [ex, args] = *static_cast<result_type*>(result); + if (ex) + std::rethrow_exception(ex); + if constexpr (sizeof...(Args) == 0) + return; + else if constexpr (sizeof...(Args) == 1) + return std::move(std::get<0>(args)); + else + return std::move(args); + } +}; + +template <typename Executors, typename Handler, typename Return> +class co_composed_promise_return; + +template <typename Executors, typename Handler> +class co_composed_promise_return<Executors, Handler, co_composed_returns<>> +{ +public: + auto final_suspend() noexcept + { + return suspend_never(); + } + + void return_void() noexcept + { + } +}; + +template <typename Executors, typename Handler, + typename Return, typename Signature> +class co_composed_promise_return_overload; + +template <typename Executors, typename Handler, + typename Return, typename R, typename... Args> +class co_composed_promise_return_overload< + Executors, Handler, Return, R(Args...)> +{ +public: + using derived_type = co_composed_promise<Executors, Handler, Return>; + using return_type = std::tuple<Args...>; + + void return_value(std::tuple<Args...>&& value) + { + derived_type& promise = *static_cast<derived_type*>(this); + promise.state().return_value_ = std::move(value); + promise.state().work_.reset(); + promise.state().on_suspend_->arg_ = this; + promise.state().on_suspend_->fn_ = + [](void* p) + { + auto& promise = *static_cast<derived_type*>(p); + + co_composed_handler_base<Executors, Handler, + Return> composed_handler(promise); + + Handler handler(std::move(promise.state().handler_)); + return_type result( + std::move(std::get<return_type>(promise.state().return_value_))); + + co_composed_handler_base<Executors, Handler, + Return>(std::move(composed_handler)); + + std::apply(std::move(handler), std::move(result)); + }; + } +}; + +template <typename Executors, typename Handler, typename... Signatures> +class co_composed_promise_return<Executors, + Handler, co_composed_returns<Signatures...>> + : public co_composed_promise_return_overload<Executors, + Handler, co_composed_returns<Signatures...>, Signatures>... +{ +public: + auto final_suspend() noexcept + { + return suspend_always(); + } + + using co_composed_promise_return_overload<Executors, Handler, + co_composed_returns<Signatures...>, Signatures>::return_value...; + +private: + template <typename, typename, typename, typename> + friend class co_composed_promise_return_overload; +}; + +template <typename Executors, typename Handler, typename Return> +class co_composed_promise + : public co_composed_promise_return<Executors, Handler, Return> +{ +public: + template <typename... Args> + void* operator new(std::size_t size, + co_composed_state<Executors, Handler, Return>& state, Args&&...) + { + block_allocator_type allocator( + (get_associated_allocator)(state.handler_, + recycling_allocator<void>())); + + block* base_ptr = std::allocator_traits<block_allocator_type>::allocate( + allocator, blocks(sizeof(allocator_type)) + blocks(size)); + + new (static_cast<void*>(base_ptr)) allocator_type(std::move(allocator)); + + return base_ptr + blocks(sizeof(allocator_type)); + } + + template <typename C, typename... Args> + void* operator new(std::size_t size, C&&, + co_composed_state<Executors, Handler, Return>& state, Args&&...) + { + return co_composed_promise::operator new(size, state); + } + + void operator delete(void* ptr, std::size_t size) + { + block* base_ptr = static_cast<block*>(ptr) - blocks(sizeof(allocator_type)); + + allocator_type* allocator_ptr = std::launder( + static_cast<allocator_type*>(static_cast<void*>(base_ptr))); + + block_allocator_type block_allocator(std::move(*allocator_ptr)); + allocator_ptr->~allocator_type(); + + std::allocator_traits<block_allocator_type>::deallocate(block_allocator, + base_ptr, blocks(sizeof(allocator_type)) + blocks(size)); + } + + template <typename... Args> + co_composed_promise( + co_composed_state<Executors, Handler, Return>& state, Args&&...) + : state_(state) + { + } + + template <typename C, typename... Args> + co_composed_promise(C&&, + co_composed_state<Executors, Handler, Return>& state, Args&&...) + : state_(state) + { + } + + void destroy() noexcept + { + coroutine_handle<co_composed_promise>::from_promise(*this).destroy(); + } + + void resume(co_composed_promise*& owner, void* result, + co_composed_on_suspend& on_suspend) + { + state_.on_suspend_ = &on_suspend; + state_.clear_cancellation_slot(); + owner_ = &owner; + result_ = result; + coroutine_handle<co_composed_promise>::from_promise(*this).resume(); + } + + co_composed_state<Executors, Handler, Return>& state() noexcept + { + return state_; + } + + void get_return_object() noexcept + { + } + + auto initial_suspend() noexcept + { + return suspend_never(); + } + + void unhandled_exception() + { + if (owner_) + *owner_ = this; + throw; + } + + template <async_operation Op> + auto await_transform(Op&& op +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , asio::detail::source_location location + = asio::detail::source_location::current() +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + ) + { + class [[nodiscard]] awaitable + { + public: + awaitable(Op&& op, co_composed_promise& promise +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , const asio::detail::source_location& location +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + ) + : op_(std::forward<Op>(op)), + promise_(promise) +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , location_(location) +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + { + } + + constexpr bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<co_composed_promise>) + { + if (promise_.state_.check_for_cancellation_on_suspend(promise_)) + { + promise_.state_.on_suspend_->arg_ = this; + promise_.state_.on_suspend_->fn_ = + [](void* p) + { +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + ASIO_HANDLER_LOCATION(( + static_cast<awaitable*>(p)->location_.file_name(), + static_cast<awaitable*>(p)->location_.line(), + static_cast<awaitable*>(p)->location_.function_name())); +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + std::forward<Op>(static_cast<awaitable*>(p)->op_)( + co_composed_handler<Executors, Handler, + Return, completion_signature_of_t<Op>>( + static_cast<awaitable*>(p)->promise_)); + }; + } + } + + auto await_resume() + { + return co_composed_handler<Executors, Handler, Return, + completion_signature_of_t<Op>>::on_resume(promise_.result_); + } + + private: + Op&& op_; + co_composed_promise& promise_; +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + asio::detail::source_location location_; +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + }; + + state_.check_for_cancellation_on_transform(); + return awaitable{std::forward<Op>(op), *this +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , location +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + }; + } + + template <typename... Args> + auto yield_value(co_composed_completion<Args...>&& result) + { + class [[nodiscard]] awaitable + { + public: + awaitable(co_composed_completion<Args...>&& result, + co_composed_promise& promise) + : result_(std::move(result)), + promise_(promise) + { + } + + constexpr bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<co_composed_promise>) + { + promise_.state_.work_.reset(); + promise_.state_.on_suspend_->arg_ = this; + promise_.state_.on_suspend_->fn_ = + [](void* p) + { + awaitable& a = *static_cast<awaitable*>(p); + + co_composed_handler_base<Executors, Handler, + Return> composed_handler(a.promise_); + + Handler handler(std::move(a.promise_.state_.handler_)); + std::tuple<decay_t<Args>...> result( + std::move(static_cast<std::tuple<Args&&...>>(a.result_))); + + co_composed_handler_base<Executors, Handler, + Return>(std::move(composed_handler)); + + std::apply(std::move(handler), std::move(result)); + }; + } + + void await_resume() noexcept + { + } + + private: + co_composed_completion<Args...> result_; + co_composed_promise& promise_; + }; + + return awaitable{std::move(result), *this}; + } + +private: + using allocator_type = + associated_allocator_t<Handler, recycling_allocator<void>>; + + union block + { + std::max_align_t max_align; + alignas(allocator_type) char pad[alignof(allocator_type)]; + }; + + using block_allocator_type = + typename std::allocator_traits<allocator_type> + ::template rebind_alloc<block>; + + static constexpr std::size_t blocks(std::size_t size) + { + return (size + sizeof(block) - 1) / sizeof(block); + } + + co_composed_state<Executors, Handler, Return>& state_; + co_composed_promise** owner_ = nullptr; + void* result_ = nullptr; +}; + +template <typename Implementation, typename Executors, typename... Signatures> +class initiate_co_composed +{ +public: + using executor_type = typename composed_io_executors<Executors>::head_type; + + template <typename I> + initiate_co_composed(I&& impl, composed_io_executors<Executors>&& executors) + : implementation_(std::forward<I>(impl)), + executors_(std::move(executors)) + { + } + + executor_type get_executor() const noexcept + { + return executors_.head_; + } + + template <typename Handler, typename... InitArgs> + void operator()(Handler&& handler, InitArgs&&... init_args) const & + { + using handler_type = decay_t<Handler>; + using returns_type = co_composed_returns<Signatures...>; + co_composed_on_suspend on_suspend{}; + implementation_( + co_composed_state<Executors, handler_type, returns_type>( + executors_, std::forward<Handler>(handler), on_suspend), + std::forward<InitArgs>(init_args)...); + if (on_suspend.fn_) + on_suspend.fn_(on_suspend.arg_); + } + + template <typename Handler, typename... InitArgs> + void operator()(Handler&& handler, InitArgs&&... init_args) && + { + using handler_type = decay_t<Handler>; + using returns_type = co_composed_returns<Signatures...>; + co_composed_on_suspend on_suspend{}; + std::move(implementation_)( + co_composed_state<Executors, handler_type, returns_type>( + std::move(executors_), std::forward<Handler>(handler), on_suspend), + std::forward<InitArgs>(init_args)...); + if (on_suspend.fn_) + on_suspend.fn_(on_suspend.arg_); + } + +private: + Implementation implementation_; + composed_io_executors<Executors> executors_; +}; + +template <typename... Signatures, typename Implementation, typename Executors> +inline initiate_co_composed<Implementation, Executors, Signatures...> +make_initiate_co_composed(Implementation&& implementation, + composed_io_executors<Executors>&& executors) +{ + return initiate_co_composed< + decay_t<Implementation>, Executors, Signatures...>( + std::forward<Implementation>(implementation), std::move(executors)); +} + +} // namespace detail + +template <completion_signature... Signatures, + typename Implementation, typename... IoObjectsOrExecutors> +inline auto co_composed(Implementation&& implementation, + IoObjectsOrExecutors&&... io_objects_or_executors) +{ + return detail::make_initiate_co_composed<Signatures...>( + std::forward<Implementation>(implementation), + detail::make_composed_io_executors( + detail::get_composed_io_executor( + std::forward<IoObjectsOrExecutors>( + io_objects_or_executors))...)); +} + +} // namespace experimental + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename Executors, typename Handler, typename Return, + typename Signature, typename DefaultCandidate> +struct associator<Associator, + experimental::detail::co_composed_handler< + Executors, Handler, Return, Signature>, + DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const experimental::detail::co_composed_handler< + Executors, Handler, Return, Signature>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get( + h.promise().state().handler()); + } + + static auto get( + const experimental::detail::co_composed_handler< + Executors, Handler, Return, Signature>& h, + const DefaultCandidate& c) noexcept + -> decltype( + Associator<Handler, DefaultCandidate>::get( + h.promise().state().handler(), c)) + { + return Associator<Handler, DefaultCandidate>::get( + h.promise().state().handler(), c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#if !defined(GENERATING_DOCUMENTATION) +# if defined(ASIO_HAS_STD_COROUTINE) +namespace std { +# else // defined(ASIO_HAS_STD_COROUTINE) +namespace std { namespace experimental { +# endif // defined(ASIO_HAS_STD_COROUTINE) + +template <typename C, typename Executors, + typename Handler, typename Return, typename... Args> +struct coroutine_traits<void, C&, + asio::experimental::detail::co_composed_state< + Executors, Handler, Return>, + Args...> +{ + using promise_type = + asio::experimental::detail::co_composed_promise< + Executors, Handler, Return>; +}; + +template <typename C, typename Executors, + typename Handler, typename Return, typename... Args> +struct coroutine_traits<void, C&&, + asio::experimental::detail::co_composed_state< + Executors, Handler, Return>, + Args...> +{ + using promise_type = + asio::experimental::detail::co_composed_promise< + Executors, Handler, Return>; +}; + +template <typename Executors, typename Handler, + typename Return, typename... Args> +struct coroutine_traits<void, + asio::experimental::detail::co_composed_state< + Executors, Handler, Return>, + Args...> +{ + using promise_type = + asio::experimental::detail::co_composed_promise< + Executors, Handler, Return>; +}; + +# if defined(ASIO_HAS_STD_COROUTINE) +} // namespace std +# else // defined(ASIO_HAS_STD_COROUTINE) +}} // namespace std::experimental +# endif // defined(ASIO_HAS_STD_COROUTINE) +#endif // !defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_EXPERIMENTAL_CO_COMPOSED_HPP diff --git a/3rdparty/asio/include/asio/experimental/impl/coro.hpp b/3rdparty/asio/include/asio/experimental/impl/coro.hpp new file mode 100644 index 00000000000..872d1a0255c --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/coro.hpp @@ -0,0 +1,1222 @@ +// +// experimental/impl/coro.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_CORO_HPP +#define ASIO_EXPERIMENTAL_IMPL_CORO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/append.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/bind_allocator.hpp" +#include "asio/deferred.hpp" +#include "asio/experimental/detail/coro_completion_handler.hpp" +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +template <typename Yield, typename Return, + typename Executor, typename Allocator> +struct coro; + +namespace detail { + +struct coro_cancellation_source +{ + cancellation_slot slot; + cancellation_state state; + bool throw_if_cancelled_ = true; + + void reset_cancellation_state() + { + state = cancellation_state(slot); + } + + template <typename Filter> + void reset_cancellation_state(Filter&& filter) + { + state = cancellation_state(slot, static_cast<Filter&&>(filter)); + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(InFilter&& in_filter, + OutFilter&& out_filter) + { + state = cancellation_state(slot, + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)); + } + + bool throw_if_cancelled() const + { + return throw_if_cancelled_; + } + + void throw_if_cancelled(bool value) + { + throw_if_cancelled_ = value; + } +}; + +template <typename Signature, typename Return, + typename Executor, typename Allocator> +struct coro_promise; + +template <typename T> +struct is_noexcept : std::false_type +{ +}; + +template <typename Return, typename... Args> +struct is_noexcept<Return(Args...)> : std::false_type +{ +}; + +template <typename Return, typename... Args> +struct is_noexcept<Return(Args...) noexcept> : std::true_type +{ +}; + +template <typename T> +constexpr bool is_noexcept_v = is_noexcept<T>::value; + +template <typename T> +struct coro_error; + +template <> +struct coro_error<asio::error_code> +{ + static asio::error_code invalid() + { + return asio::error::fault; + } + + static asio::error_code cancelled() + { + return asio::error::operation_aborted; + } + + static asio::error_code interrupted() + { + return asio::error::interrupted; + } + + static asio::error_code done() + { + return asio::error::broken_pipe; + } +}; + +template <> +struct coro_error<std::exception_ptr> +{ + static std::exception_ptr invalid() + { + return std::make_exception_ptr( + asio::system_error( + coro_error<asio::error_code>::invalid())); + } + + static std::exception_ptr cancelled() + { + return std::make_exception_ptr( + asio::system_error( + coro_error<asio::error_code>::cancelled())); + } + + static std::exception_ptr interrupted() + { + return std::make_exception_ptr( + asio::system_error( + coro_error<asio::error_code>::interrupted())); + } + + static std::exception_ptr done() + { + return std::make_exception_ptr( + asio::system_error( + coro_error<asio::error_code>::done())); + } +}; + +template <typename T, typename Coroutine > +struct coro_with_arg +{ + using coro_t = Coroutine; + T value; + coro_t& coro; + + struct awaitable_t + { + T value; + coro_t& coro; + + constexpr static bool await_ready() { return false; } + + template <typename Y, typename R, typename E, typename A> + auto await_suspend(coroutine_handle<coro_promise<Y, R, E, A>> h) + -> coroutine_handle<> + { + auto& hp = h.promise(); + + if constexpr (!coro_promise<Y, R, E, A>::is_noexcept) + { + if ((hp.cancel->state.cancelled() != cancellation_type::none) + && hp.cancel->throw_if_cancelled_) + { + asio::detail::throw_error( + asio::error::operation_aborted, "coro-cancelled"); + } + } + + if (hp.get_executor() == coro.get_executor()) + { + coro.coro_->awaited_from = h; + coro.coro_->reset_error(); + coro.coro_->input_ = std::move(value); + coro.coro_->cancel = hp.cancel; + return coro.coro_->get_handle(); + } + else + { + coro.coro_->awaited_from = + dispatch_coroutine( + asio::prefer(hp.get_executor(), + execution::outstanding_work.tracked), + [h]() mutable { h.resume(); }).handle; + + coro.coro_->reset_error(); + coro.coro_->input_ = std::move(value); + + struct cancel_handler + { + using src = std::pair<cancellation_signal, + detail::coro_cancellation_source>; + + std::shared_ptr<src> st = std::make_shared<src>(); + + cancel_handler(E e, coro_t& coro) : e(e), coro_(coro.coro_) + { + st->second.state = + cancellation_state(st->second.slot = st->first.slot()); + } + + E e; + typename coro_t::promise_type* coro_; + + void operator()(cancellation_type ct) + { + asio::dispatch(e, [ct, st = st]() mutable + { + auto & [sig, state] = *st; + sig.emit(ct); + }); + } + }; + + if (hp.cancel->state.slot().is_connected()) + { + hp.cancel->state.slot().template emplace<cancel_handler>( + coro.get_executor(), coro); + } + + auto hh = detail::coroutine_handle< + typename coro_t::promise_type>::from_promise(*coro.coro_); + + return dispatch_coroutine( + coro.coro_->get_executor(), [hh]() mutable { hh.resume(); }).handle; + } + } + + auto await_resume() -> typename coro_t::result_type + { + coro.coro_->cancel = nullptr; + coro.coro_->rethrow_if(); + return std::move(coro.coro_->result_); + } + }; + + template <typename CompletionToken> + auto async_resume(CompletionToken&& token) && + { + return coro.async_resume(std::move(value), + std::forward<CompletionToken>(token)); + } + + auto operator co_await() && + { + return awaitable_t{std::move(value), coro}; + } +}; + +template <bool IsNoexcept> +struct coro_promise_error; + +template <> +struct coro_promise_error<false> +{ + std::exception_ptr error_; + + void reset_error() + { + error_ = std::exception_ptr{}; + } + + void unhandled_exception() + { + error_ = std::current_exception(); + } + + void rethrow_if() + { + if (error_) + std::rethrow_exception(error_); + } +}; + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# if defined(__clang__) +# pragma GCC diagnostic ignored "-Wexceptions" +# else +# pragma GCC diagnostic ignored "-Wterminate" +# endif +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning (disable:4297) +#endif + +template <> +struct coro_promise_error<true> +{ + void reset_error() + { + } + + void unhandled_exception() noexcept + { + throw; + } + + void rethrow_if() + { + } +}; + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif + +template <typename T = void> +struct yield_input +{ + T& value; + coroutine_handle<> awaited_from{noop_coroutine()}; + + bool await_ready() const noexcept + { + return false; + } + + template <typename U> + coroutine_handle<> await_suspend(coroutine_handle<U>) noexcept + { + return std::exchange(awaited_from, noop_coroutine()); + } + + T await_resume() const noexcept + { + return std::move(value); + } +}; + +template <> +struct yield_input<void> +{ + coroutine_handle<> awaited_from{noop_coroutine()}; + + bool await_ready() const noexcept + { + return false; + } + + auto await_suspend(coroutine_handle<>) noexcept + { + return std::exchange(awaited_from, noop_coroutine()); + } + + constexpr void await_resume() const noexcept + { + } +}; + +struct coro_awaited_from +{ + coroutine_handle<> awaited_from{noop_coroutine()}; + + auto final_suspend() noexcept + { + struct suspendor + { + coroutine_handle<> awaited_from; + + constexpr static bool await_ready() noexcept + { + return false; + } + + auto await_suspend(coroutine_handle<>) noexcept + { + return std::exchange(awaited_from, noop_coroutine()); + } + + constexpr static void await_resume() noexcept + { + } + }; + + return suspendor{std::exchange(awaited_from, noop_coroutine())}; + } + + ~coro_awaited_from() + { + awaited_from.resume(); + }//must be on the right executor +}; + +template <typename Yield, typename Input, typename Return> +struct coro_promise_exchange : coro_awaited_from +{ + using result_type = coro_result_t<Yield, Return>; + + result_type result_; + Input input_; + + auto yield_value(Yield&& y) + { + result_ = std::move(y); + return yield_input<Input>{std::move(input_), + std::exchange(awaited_from, noop_coroutine())}; + } + + auto yield_value(const Yield& y) + { + result_ = y; + return yield_input<Input>{std::move(input_), + std::exchange(awaited_from, noop_coroutine())}; + } + + void return_value(const Return& r) + { + result_ = r; + } + + void return_value(Return&& r) + { + result_ = std::move(r); + } +}; + +template <typename YieldReturn> +struct coro_promise_exchange<YieldReturn, void, YieldReturn> : coro_awaited_from +{ + using result_type = coro_result_t<YieldReturn, YieldReturn>; + + result_type result_; + + auto yield_value(const YieldReturn& y) + { + result_ = y; + return yield_input<void>{std::exchange(awaited_from, noop_coroutine())}; + } + + auto yield_value(YieldReturn&& y) + { + result_ = std::move(y); + return yield_input<void>{std::exchange(awaited_from, noop_coroutine())}; + } + + void return_value(const YieldReturn& r) + { + result_ = r; + } + + void return_value(YieldReturn&& r) + { + result_ = std::move(r); + } +}; + +template <typename Yield, typename Return> +struct coro_promise_exchange<Yield, void, Return> : coro_awaited_from +{ + using result_type = coro_result_t<Yield, Return>; + + result_type result_; + + auto yield_value(const Yield& y) + { + result_.template emplace<0>(y); + return yield_input<void>{std::exchange(awaited_from, noop_coroutine())}; + } + + auto yield_value(Yield&& y) + { + result_.template emplace<0>(std::move(y)); + return yield_input<void>{std::exchange(awaited_from, noop_coroutine())}; + } + + void return_value(const Return& r) + { + result_.template emplace<1>(r); + } + + void return_value(Return&& r) + { + result_.template emplace<1>(std::move(r)); + } +}; + +template <typename Yield, typename Input> +struct coro_promise_exchange<Yield, Input, void> : coro_awaited_from +{ + using result_type = coro_result_t<Yield, void>; + + result_type result_; + Input input_; + + auto yield_value(Yield&& y) + { + result_ = std::move(y); + return yield_input<Input>{input_, + std::exchange(awaited_from, noop_coroutine())}; + } + + auto yield_value(const Yield& y) + { + result_ = y; + return yield_input<Input>{input_, + std::exchange(awaited_from, noop_coroutine())}; + } + + void return_void() + { + result_.reset(); + } +}; + +template <typename Return> +struct coro_promise_exchange<void, void, Return> : coro_awaited_from +{ + using result_type = coro_result_t<void, Return>; + + result_type result_; + + void yield_value(); + + void return_value(const Return& r) + { + result_ = r; + } + + void return_value(Return&& r) + { + result_ = std::move(r); + } +}; + +template <> +struct coro_promise_exchange<void, void, void> : coro_awaited_from +{ + void return_void() {} + + void yield_value(); +}; + +template <typename Yield> +struct coro_promise_exchange<Yield, void, void> : coro_awaited_from +{ + using result_type = coro_result_t<Yield, void>; + + result_type result_; + + auto yield_value(const Yield& y) + { + result_ = y; + return yield_input<void>{std::exchange(awaited_from, noop_coroutine())}; + } + + auto yield_value(Yield&& y) + { + result_ = std::move(y); + return yield_input<void>{std::exchange(awaited_from, noop_coroutine())}; + } + + void return_void() + { + result_.reset(); + } +}; + +template <typename Yield, typename Return, + typename Executor, typename Allocator> +struct coro_promise final : + coro_promise_allocator<Allocator>, + coro_promise_error<coro_traits<Yield, Return, Executor>::is_noexcept>, + coro_promise_exchange< + typename coro_traits<Yield, Return, Executor>::yield_type, + typename coro_traits<Yield, Return, Executor>::input_type, + typename coro_traits<Yield, Return, Executor>::return_type> +{ + using coro_type = coro<Yield, Return, Executor, Allocator>; + + auto handle() + { + return coroutine_handle<coro_promise>::from_promise(this); + } + + using executor_type = Executor; + + executor_type executor_; + + std::optional<coro_cancellation_source> cancel_source; + coro_cancellation_source * cancel; + + using cancellation_slot_type = asio::cancellation_slot; + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return cancel ? cancel->slot : cancellation_slot_type{}; + } + + using allocator_type = + typename std::allocator_traits<associated_allocator_t<Executor>>:: + template rebind_alloc<std::byte>; + using traits = coro_traits<Yield, Return, Executor>; + + using input_type = typename traits::input_type; + using yield_type = typename traits::yield_type; + using return_type = typename traits::return_type; + using error_type = typename traits::error_type; + using result_type = typename traits::result_type; + constexpr static bool is_noexcept = traits::is_noexcept; + + auto get_executor() const -> Executor + { + return executor_; + } + + auto get_handle() + { + return coroutine_handle<coro_promise>::from_promise(*this); + } + + template <typename... Args> + coro_promise(Executor executor, Args&&... args) noexcept + : coro_promise_allocator<Allocator>( + executor, std::forward<Args>(args)...), + executor_(std::move(executor)) + { + } + + template <typename First, typename... Args> + coro_promise(First&& f, Executor executor, Args&&... args) noexcept + : coro_promise_allocator<Allocator>( + f, executor, std::forward<Args>(args)...), + executor_(std::move(executor)) + { + } + + template <typename First, detail::execution_context Context, typename... Args> + coro_promise(First&& f, Context&& ctx, Args&&... args) noexcept + : coro_promise_allocator<Allocator>( + f, ctx, std::forward<Args>(args)...), + executor_(ctx.get_executor()) + { + } + + template <detail::execution_context Context, typename... Args> + coro_promise(Context&& ctx, Args&&... args) noexcept + : coro_promise_allocator<Allocator>( + ctx, std::forward<Args>(args)...), + executor_(ctx.get_executor()) + { + } + + auto get_return_object() + { + return coro<Yield, Return, Executor, Allocator>{this}; + } + + auto initial_suspend() noexcept + { + return suspend_always{}; + } + + using coro_promise_exchange< + typename coro_traits<Yield, Return, Executor>::yield_type, + typename coro_traits<Yield, Return, Executor>::input_type, + typename coro_traits<Yield, Return, Executor>::return_type>::yield_value; + + auto await_transform(this_coro::executor_t) const + { + struct exec_helper + { + const executor_type& value; + + constexpr static bool await_ready() noexcept + { + return true; + } + + constexpr static void await_suspend(coroutine_handle<>) noexcept + { + } + + executor_type await_resume() const noexcept + { + return value; + } + }; + + return exec_helper{executor_}; + } + + auto await_transform(this_coro::cancellation_state_t) const + { + struct exec_helper + { + const asio::cancellation_state& value; + + constexpr static bool await_ready() noexcept + { + return true; + } + + constexpr static void await_suspend(coroutine_handle<>) noexcept + { + } + + asio::cancellation_state await_resume() const noexcept + { + return value; + } + }; + assert(cancel); + return exec_helper{cancel->state}; + } + + // This await transformation resets the associated cancellation state. + auto await_transform(this_coro::reset_cancellation_state_0_t) noexcept + { + struct result + { + detail::coro_cancellation_source * src_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() const + { + return src_->reset_cancellation_state(); + } + }; + + return result{cancel}; + } + + // This await transformation resets the associated cancellation state. + template <typename Filter> + auto await_transform( + this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept + { + struct result + { + detail::coro_cancellation_source* src_; + Filter filter_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + return src_->reset_cancellation_state( + static_cast<Filter&&>(filter_)); + } + }; + + return result{cancel, static_cast<Filter&&>(reset.filter)}; + } + + // This await transformation resets the associated cancellation state. + template <typename InFilter, typename OutFilter> + auto await_transform( + this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset) + noexcept + { + struct result + { + detail::coro_cancellation_source* src_; + InFilter in_filter_; + OutFilter out_filter_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + return src_->reset_cancellation_state( + static_cast<InFilter&&>(in_filter_), + static_cast<OutFilter&&>(out_filter_)); + } + }; + + return result{cancel, + static_cast<InFilter&&>(reset.in_filter), + static_cast<OutFilter&&>(reset.out_filter)}; + } + + // This await transformation determines whether cancellation is propagated as + // an exception. + auto await_transform(this_coro::throw_if_cancelled_0_t) noexcept + requires (!is_noexcept) + { + struct result + { + detail::coro_cancellation_source* src_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + return src_->throw_if_cancelled(); + } + }; + + return result{cancel}; + } + + // This await transformation sets whether cancellation is propagated as an + // exception. + auto await_transform( + this_coro::throw_if_cancelled_1_t throw_if_cancelled) noexcept + requires (!is_noexcept) + { + struct result + { + detail::coro_cancellation_source* src_; + bool value_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + src_->throw_if_cancelled(value_); + } + }; + + return result{cancel, throw_if_cancelled.value}; + } + + template <typename Yield_, typename Return_, + typename Executor_, typename Allocator_> + auto await_transform(coro<Yield_, Return_, Executor_, Allocator_>& kr) + -> decltype(auto) + { + return kr; + } + + template <typename Yield_, typename Return_, + typename Executor_, typename Allocator_> + auto await_transform(coro<Yield_, Return_, Executor_, Allocator_>&& kr) + { + return std::move(kr); + } + + template <typename T_, typename Coroutine > + auto await_transform(coro_with_arg<T_, Coroutine>&& kr) -> decltype(auto) + { + return std::move(kr); + } + + template <typename T_> + requires requires(T_ t) {{ t.async_wait(deferred) }; } + auto await_transform(T_& t) -> decltype(auto) + { + return await_transform(t.async_wait(deferred)); + } + + template <typename Op> + auto await_transform(Op&& op, + constraint_t<is_async_operation<Op>::value> = 0) + { + if ((cancel->state.cancelled() != cancellation_type::none) + && cancel->throw_if_cancelled_) + { + asio::detail::throw_error( + asio::error::operation_aborted, "coro-cancelled"); + } + using signature = completion_signature_of_t<Op>; + using result_type = detail::coro_completion_handler_type_t<signature>; + using handler_type = + typename detail::coro_completion_handler_type<signature>::template + completion_handler<coro_promise>; + + struct aw_t + { + Op op; + std::optional<result_type> result; + + constexpr static bool await_ready() + { + return false; + } + + void await_suspend(coroutine_handle<coro_promise> h) + { + std::move(op)(handler_type{h, result}); + } + + auto await_resume() + { + if constexpr (is_noexcept) + { + if constexpr (std::tuple_size_v<result_type> == 0u) + return; + else if constexpr (std::tuple_size_v<result_type> == 1u) + return std::get<0>(std::move(result).value()); + else + return std::move(result).value(); + } + else + return detail::coro_interpret_result(std::move(result).value()); + } + }; + + return aw_t{std::move(op), {}}; + } +}; + +} // namespace detail + +template <typename Yield, typename Return, + typename Executor, typename Allocator> +struct coro<Yield, Return, Executor, Allocator>::awaitable_t +{ + coro& coro_; + + constexpr static bool await_ready() { return false; } + + template <typename Y, typename R, typename E, typename A> + auto await_suspend( + detail::coroutine_handle<detail::coro_promise<Y, R, E, A>> h) + -> detail::coroutine_handle<> + { + auto& hp = h.promise(); + + if constexpr (!detail::coro_promise<Y, R, E, A>::is_noexcept) + { + if ((hp.cancel->state.cancelled() != cancellation_type::none) + && hp.cancel->throw_if_cancelled_) + { + asio::detail::throw_error( + asio::error::operation_aborted, "coro-cancelled"); + } + } + + if (hp.get_executor() == coro_.get_executor()) + { + coro_.coro_->awaited_from = h; + coro_.coro_->cancel = hp.cancel; + coro_.coro_->reset_error(); + + return coro_.coro_->get_handle(); + } + else + { + coro_.coro_->awaited_from = detail::dispatch_coroutine( + asio::prefer(hp.get_executor(), + execution::outstanding_work.tracked), + [h]() mutable + { + h.resume(); + }).handle; + + coro_.coro_->reset_error(); + + struct cancel_handler + { + std::shared_ptr<std::pair<cancellation_signal, + detail::coro_cancellation_source>> st = std::make_shared< + std::pair<cancellation_signal, detail::coro_cancellation_source>>(); + + cancel_handler(E e, coro& coro) : e(e), coro_(coro.coro_) + { + st->second.state = cancellation_state( + st->second.slot = st->first.slot()); + } + + E e; + typename coro::promise_type* coro_; + + void operator()(cancellation_type ct) + { + asio::dispatch(e, + [ct, st = st]() mutable + { + auto & [sig, state] = *st; + sig.emit(ct); + }); + } + }; + + if (hp.cancel->state.slot().is_connected()) + { + hp.cancel->state.slot().template emplace<cancel_handler>( + coro_.get_executor(), coro_); + } + + auto hh = detail::coroutine_handle< + detail::coro_promise<Yield, Return, Executor, Allocator>>::from_promise( + *coro_.coro_); + + return detail::dispatch_coroutine( + coro_.coro_->get_executor(), + [hh]() mutable { hh.resume(); }).handle; + } + } + + auto await_resume() -> result_type + { + coro_.coro_->cancel = nullptr; + coro_.coro_->rethrow_if(); + if constexpr (!std::is_void_v<result_type>) + return std::move(coro_.coro_->result_); + } +}; + +template <typename Yield, typename Return, + typename Executor, typename Allocator> +struct coro<Yield, Return, Executor, Allocator>::initiate_async_resume +{ + typedef Executor executor_type; + typedef Allocator allocator_type; + typedef asio::cancellation_slot cancellation_slot_type; + + explicit initiate_async_resume(coro* self) + : coro_(self->coro_) + { + } + + executor_type get_executor() const noexcept + { + return coro_->get_executor(); + } + + allocator_type get_allocator() const noexcept + { + return coro_->get_allocator(); + } + + template <typename E, typename WaitHandler> + auto handle(E exec, WaitHandler&& handler, + std::true_type /* error is noexcept */, + std::true_type /* result is void */) //noexcept + { + return [this, the_coro = coro_, + h = std::forward<WaitHandler>(handler), + exec = std::move(exec)]() mutable + { + assert(the_coro); + + auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro); + assert(ch && !ch.done()); + + the_coro->awaited_from = post_coroutine(std::move(exec), std::move(h)); + the_coro->reset_error(); + ch.resume(); + }; + } + + template <typename E, typename WaitHandler> + requires (!std::is_void_v<result_type>) + auto handle(E exec, WaitHandler&& handler, + std::true_type /* error is noexcept */, + std::false_type /* result is void */) //noexcept + { + return [the_coro = coro_, + h = std::forward<WaitHandler>(handler), + exec = std::move(exec)]() mutable + { + assert(the_coro); + + auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro); + assert(ch && !ch.done()); + + the_coro->awaited_from = detail::post_coroutine( + exec, std::move(h), the_coro->result_).handle; + the_coro->reset_error(); + ch.resume(); + }; + } + + template <typename E, typename WaitHandler> + auto handle(E exec, WaitHandler&& handler, + std::false_type /* error is noexcept */, + std::true_type /* result is void */) + { + return [the_coro = coro_, + h = std::forward<WaitHandler>(handler), + exec = std::move(exec)]() mutable + { + if (!the_coro) + return asio::post(exec, + asio::append(std::move(h), + detail::coro_error<error_type>::invalid())); + + auto ch = detail::coroutine_handle<promise_type>::from_promise(*the_coro); + if (!ch) + return asio::post(exec, + asio::append(std::move(h), + detail::coro_error<error_type>::invalid())); + else if (ch.done()) + return asio::post(exec, + asio::append(std::move(h), + detail::coro_error<error_type>::done())); + else + { + the_coro->awaited_from = detail::post_coroutine( + exec, std::move(h), the_coro->error_).handle; + the_coro->reset_error(); + ch.resume(); + } + }; + } + + template <typename E, typename WaitHandler> + auto handle(E exec, WaitHandler&& handler, + std::false_type /* error is noexcept */, + std::false_type /* result is void */) + { + return [the_coro = coro_, + h = std::forward<WaitHandler>(handler), + exec = std::move(exec)]() mutable + { + if (!the_coro) + return asio::post(exec, + asio::append(std::move(h), + detail::coro_error<error_type>::invalid(), result_type{})); + + auto ch = + detail::coroutine_handle<promise_type>::from_promise(*the_coro); + if (!ch) + return asio::post(exec, + asio::append(std::move(h), + detail::coro_error<error_type>::invalid(), result_type{})); + else if (ch.done()) + return asio::post(exec, + asio::append(std::move(h), + detail::coro_error<error_type>::done(), result_type{})); + else + { + the_coro->awaited_from = detail::post_coroutine( + exec, std::move(h), the_coro->error_, the_coro->result_).handle; + the_coro->reset_error(); + ch.resume(); + } + }; + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler) + { + const auto exec = asio::prefer( + get_associated_executor(handler, get_executor()), + execution::outstanding_work.tracked); + + coro_->cancel = &coro_->cancel_source.emplace(); + coro_->cancel->state = cancellation_state( + coro_->cancel->slot = get_associated_cancellation_slot(handler)); + asio::dispatch(get_executor(), + handle(exec, std::forward<WaitHandler>(handler), + std::integral_constant<bool, is_noexcept>{}, + std::is_void<result_type>{})); + } + + template <typename WaitHandler, typename Input> + void operator()(WaitHandler&& handler, Input&& input) + { + const auto exec = asio::prefer( + get_associated_executor(handler, get_executor()), + execution::outstanding_work.tracked); + + coro_->cancel = &coro_->cancel_source.emplace(); + coro_->cancel->state = cancellation_state( + coro_->cancel->slot = get_associated_cancellation_slot(handler)); + asio::dispatch(get_executor(), + [h = handle(exec, std::forward<WaitHandler>(handler), + std::integral_constant<bool, is_noexcept>{}, + std::is_void<result_type>{}), + in = std::forward<Input>(input), the_coro = coro_]() mutable + { + the_coro->input_ = std::move(in); + std::move(h)(); + }); + } + +private: + typename coro::promise_type* coro_; +}; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_CORO_HPP diff --git a/3rdparty/asio/include/asio/experimental/impl/parallel_group.hpp b/3rdparty/asio/include/asio/experimental/impl/parallel_group.hpp new file mode 100644 index 00000000000..75e8a151876 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/parallel_group.hpp @@ -0,0 +1,788 @@ +// +// experimental/impl/parallel_group.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_EXPERIMENTAL_PARALLEL_GROUP_HPP +#define ASIO_IMPL_EXPERIMENTAL_PARALLEL_GROUP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <atomic> +#include <deque> +#include <memory> +#include <new> +#include <tuple> +#include "asio/associated_cancellation_slot.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/dispatch.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +// Stores the result from an individual asynchronous operation. +template <typename T, typename = void> +struct parallel_group_op_result +{ +public: + parallel_group_op_result() + : has_value_(false) + { + } + + parallel_group_op_result(parallel_group_op_result&& other) + : has_value_(other.has_value_) + { + if (has_value_) + new (&u_.value_) T(std::move(other.get())); + } + + ~parallel_group_op_result() + { + if (has_value_) + u_.value_.~T(); + } + + T& get() noexcept + { + return u_.value_; + } + + template <typename... Args> + void emplace(Args&&... args) + { + new (&u_.value_) T(std::forward<Args>(args)...); + has_value_ = true; + } + +private: + union u + { + u() {} + ~u() {} + char c_; + T value_; + } u_; + bool has_value_; +}; + +// Proxy completion handler for the group of parallel operatations. Unpacks and +// concatenates the individual operations' results, and invokes the user's +// completion handler. +template <typename Handler, typename... Ops> +struct parallel_group_completion_handler +{ + typedef decay_t< + prefer_result_t< + associated_executor_t<Handler>, + execution::outstanding_work_t::tracked_t + > + > executor_type; + + parallel_group_completion_handler(Handler&& h) + : handler_(std::move(h)), + executor_( + asio::prefer( + asio::get_associated_executor(handler_), + execution::outstanding_work.tracked)) + { + } + + executor_type get_executor() const noexcept + { + return executor_; + } + + void operator()() + { + this->invoke(asio::detail::make_index_sequence<sizeof...(Ops)>()); + } + + template <std::size_t... I> + void invoke(asio::detail::index_sequence<I...>) + { + this->invoke(std::tuple_cat(std::move(std::get<I>(args_).get())...)); + } + + template <typename... Args> + void invoke(std::tuple<Args...>&& args) + { + this->invoke(std::move(args), + asio::detail::index_sequence_for<Args...>()); + } + + template <typename... Args, std::size_t... I> + void invoke(std::tuple<Args...>&& args, + asio::detail::index_sequence<I...>) + { + std::move(handler_)(completion_order_, std::move(std::get<I>(args))...); + } + + Handler handler_; + executor_type executor_; + std::array<std::size_t, sizeof...(Ops)> completion_order_{}; + std::tuple< + parallel_group_op_result< + typename parallel_op_signature_as_tuple< + completion_signature_of_t<Ops> + >::type + >... + > args_{}; +}; + +// Shared state for the parallel group. +template <typename Condition, typename Handler, typename... Ops> +struct parallel_group_state +{ + parallel_group_state(Condition&& c, Handler&& h) + : cancellation_condition_(std::move(c)), + handler_(std::move(h)) + { + } + + // The number of operations that have completed so far. Used to determine the + // order of completion. + std::atomic<unsigned int> completed_{0}; + + // The non-none cancellation type that resulted from a cancellation condition. + // Stored here for use by the group's initiating function. + std::atomic<cancellation_type_t> cancel_type_{cancellation_type::none}; + + // The number of cancellations that have been requested, either on completion + // of the operations within the group, or via the cancellation slot for the + // group operation. Initially set to the number of operations to prevent + // cancellation signals from being emitted until after all of the group's + // operations' initiating functions have completed. + std::atomic<unsigned int> cancellations_requested_{sizeof...(Ops)}; + + // The number of operations that are yet to complete. Used to determine when + // it is safe to invoke the user's completion handler. + std::atomic<unsigned int> outstanding_{sizeof...(Ops)}; + + // The cancellation signals for each operation in the group. + asio::cancellation_signal cancellation_signals_[sizeof...(Ops)]; + + // The cancellation condition is used to determine whether the results from an + // individual operation warrant a cancellation request for the whole group. + Condition cancellation_condition_; + + // The proxy handler to be invoked once all operations in the group complete. + parallel_group_completion_handler<Handler, Ops...> handler_; +}; + +// Handler for an individual operation within the parallel group. +template <std::size_t I, typename Condition, typename Handler, typename... Ops> +struct parallel_group_op_handler +{ + typedef asio::cancellation_slot cancellation_slot_type; + + parallel_group_op_handler( + std::shared_ptr<parallel_group_state<Condition, Handler, Ops...>> state) + : state_(std::move(state)) + { + } + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return state_->cancellation_signals_[I].slot(); + } + + template <typename... Args> + void operator()(Args... args) + { + // Capture this operation into the completion order. + state_->handler_.completion_order_[state_->completed_++] = I; + + // Determine whether the results of this operation require cancellation of + // the whole group. + cancellation_type_t cancel_type = state_->cancellation_condition_(args...); + + // Capture the result of the operation into the proxy completion handler. + std::get<I>(state_->handler_.args_).emplace(std::move(args)...); + + if (cancel_type != cancellation_type::none) + { + // Save the type for potential use by the group's initiating function. + state_->cancel_type_ = cancel_type; + + // If we are the first operation to request cancellation, emit a signal + // for each operation in the group. + if (state_->cancellations_requested_++ == 0) + for (std::size_t i = 0; i < sizeof...(Ops); ++i) + if (i != I) + state_->cancellation_signals_[i].emit(cancel_type); + } + + // If this is the last outstanding operation, invoke the user's handler. + if (--state_->outstanding_ == 0) + asio::dispatch(std::move(state_->handler_)); + } + + std::shared_ptr<parallel_group_state<Condition, Handler, Ops...>> state_; +}; + +// Handler for an individual operation within the parallel group that has an +// explicitly specified executor. +template <typename Executor, std::size_t I, + typename Condition, typename Handler, typename... Ops> +struct parallel_group_op_handler_with_executor : + parallel_group_op_handler<I, Condition, Handler, Ops...> +{ + typedef parallel_group_op_handler<I, Condition, Handler, Ops...> base_type; + typedef asio::cancellation_slot cancellation_slot_type; + typedef Executor executor_type; + + parallel_group_op_handler_with_executor( + std::shared_ptr<parallel_group_state<Condition, Handler, Ops...>> state, + executor_type ex) + : parallel_group_op_handler<I, Condition, Handler, Ops...>(std::move(state)) + { + cancel_proxy_ = + &this->state_->cancellation_signals_[I].slot().template + emplace<cancel_proxy>(this->state_, std::move(ex)); + } + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return cancel_proxy_->signal_.slot(); + } + + executor_type get_executor() const noexcept + { + return cancel_proxy_->executor_; + } + + // Proxy handler that forwards the emitted signal to the correct executor. + struct cancel_proxy + { + cancel_proxy( + std::shared_ptr<parallel_group_state< + Condition, Handler, Ops...>> state, + executor_type ex) + : state_(std::move(state)), + executor_(std::move(ex)) + { + } + + void operator()(cancellation_type_t type) + { + if (auto state = state_.lock()) + { + asio::cancellation_signal* sig = &signal_; + asio::dispatch(executor_, + [state, sig, type]{ sig->emit(type); }); + } + } + + std::weak_ptr<parallel_group_state<Condition, Handler, Ops...>> state_; + asio::cancellation_signal signal_; + executor_type executor_; + }; + + cancel_proxy* cancel_proxy_; +}; + +// Helper to launch an operation using the correct executor, if any. +template <std::size_t I, typename Op, typename = void> +struct parallel_group_op_launcher +{ + template <typename Condition, typename Handler, typename... Ops> + static void launch(Op& op, + const std::shared_ptr<parallel_group_state< + Condition, Handler, Ops...>>& state) + { + typedef associated_executor_t<Op> ex_type; + ex_type ex = asio::get_associated_executor(op); + std::move(op)( + parallel_group_op_handler_with_executor<ex_type, I, + Condition, Handler, Ops...>(state, std::move(ex))); + } +}; + +// Specialised launcher for operations that specify no executor. +template <std::size_t I, typename Op> +struct parallel_group_op_launcher<I, Op, + enable_if_t< + is_same< + typename associated_executor< + Op>::asio_associated_executor_is_unspecialised, + void + >::value + >> +{ + template <typename Condition, typename Handler, typename... Ops> + static void launch(Op& op, + const std::shared_ptr<parallel_group_state< + Condition, Handler, Ops...>>& state) + { + std::move(op)( + parallel_group_op_handler<I, Condition, Handler, Ops...>(state)); + } +}; + +template <typename Condition, typename Handler, typename... Ops> +struct parallel_group_cancellation_handler +{ + parallel_group_cancellation_handler( + std::shared_ptr<parallel_group_state<Condition, Handler, Ops...>> state) + : state_(std::move(state)) + { + } + + void operator()(cancellation_type_t cancel_type) + { + // If we are the first place to request cancellation, i.e. no operation has + // yet completed and requested cancellation, emit a signal for each + // operation in the group. + if (cancel_type != cancellation_type::none) + if (auto state = state_.lock()) + if (state->cancellations_requested_++ == 0) + for (std::size_t i = 0; i < sizeof...(Ops); ++i) + state->cancellation_signals_[i].emit(cancel_type); + } + + std::weak_ptr<parallel_group_state<Condition, Handler, Ops...>> state_; +}; + +template <typename Condition, typename Handler, + typename... Ops, std::size_t... I> +void parallel_group_launch(Condition cancellation_condition, Handler handler, + std::tuple<Ops...>& ops, asio::detail::index_sequence<I...>) +{ + // Get the user's completion handler's cancellation slot, so that we can allow + // cancellation of the entire group. + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // Create the shared state for the operation. + typedef parallel_group_state<Condition, Handler, Ops...> state_type; + std::shared_ptr<state_type> state = std::allocate_shared<state_type>( + asio::detail::recycling_allocator<state_type, + asio::detail::thread_info_base::parallel_group_tag>(), + std::move(cancellation_condition), std::move(handler)); + + // Initiate each individual operation in the group. + int fold[] = { 0, + ( parallel_group_op_launcher<I, Ops>::launch(std::get<I>(ops), state), + 0 )... + }; + (void)fold; + + // Check if any of the operations has already requested cancellation, and if + // so, emit a signal for each operation in the group. + if ((state->cancellations_requested_ -= sizeof...(Ops)) > 0) + for (auto& signal : state->cancellation_signals_) + signal.emit(state->cancel_type_); + + // Register a handler with the user's completion handler's cancellation slot. + if (slot.is_connected()) + slot.template emplace< + parallel_group_cancellation_handler< + Condition, Handler, Ops...>>(state); +} + +// Proxy completion handler for the ranged group of parallel operatations. +// Unpacks and recombines the individual operations' results, and invokes the +// user's completion handler. +template <typename Handler, typename Op, typename Allocator> +struct ranged_parallel_group_completion_handler +{ + typedef decay_t< + prefer_result_t< + associated_executor_t<Handler>, + execution::outstanding_work_t::tracked_t + > + > executor_type; + + typedef typename parallel_op_signature_as_tuple< + completion_signature_of_t<Op> + >::type op_tuple_type; + + typedef parallel_group_op_result<op_tuple_type> op_result_type; + + ranged_parallel_group_completion_handler(Handler&& h, + std::size_t size, const Allocator& allocator) + : handler_(std::move(h)), + executor_( + asio::prefer( + asio::get_associated_executor(handler_), + execution::outstanding_work.tracked)), + allocator_(allocator), + completion_order_(size, 0, + ASIO_REBIND_ALLOC(Allocator, std::size_t)(allocator)), + args_(ASIO_REBIND_ALLOC(Allocator, op_result_type)(allocator)) + { + for (std::size_t i = 0; i < size; ++i) + args_.emplace_back(); + } + + executor_type get_executor() const noexcept + { + return executor_; + } + + void operator()() + { + this->invoke( + asio::detail::make_index_sequence< + std::tuple_size<op_tuple_type>::value>()); + } + + template <std::size_t... I> + void invoke(asio::detail::index_sequence<I...>) + { + typedef typename parallel_op_signature_as_tuple< + typename ranged_parallel_group_signature< + completion_signature_of_t<Op>, + Allocator + >::raw_type + >::type vectors_type; + + // Construct all result vectors using the supplied allocator. + vectors_type vectors{ + typename std::tuple_element<I, vectors_type>::type( + ASIO_REBIND_ALLOC(Allocator, int)(allocator_))...}; + + // Reserve sufficient space in each of the result vectors. + int reserve_fold[] = { 0, + ( std::get<I>(vectors).reserve(completion_order_.size()), + 0 )... + }; + (void)reserve_fold; + + // Copy the results from all operations into the result vectors. + for (std::size_t idx = 0; idx < completion_order_.size(); ++idx) + { + int pushback_fold[] = { 0, + ( std::get<I>(vectors).push_back( + std::move(std::get<I>(args_[idx].get()))), + 0 )... + }; + (void)pushback_fold; + } + + std::move(handler_)(std::move(completion_order_), + std::move(std::get<I>(vectors))...); + } + + Handler handler_; + executor_type executor_; + Allocator allocator_; + std::vector<std::size_t, + ASIO_REBIND_ALLOC(Allocator, std::size_t)> completion_order_; + std::deque<op_result_type, + ASIO_REBIND_ALLOC(Allocator, op_result_type)> args_; +}; + +// Shared state for the parallel group. +template <typename Condition, typename Handler, typename Op, typename Allocator> +struct ranged_parallel_group_state +{ + ranged_parallel_group_state(Condition&& c, Handler&& h, + std::size_t size, const Allocator& allocator) + : cancellations_requested_(size), + outstanding_(size), + cancellation_signals_( + ASIO_REBIND_ALLOC(Allocator, + asio::cancellation_signal)(allocator)), + cancellation_condition_(std::move(c)), + handler_(std::move(h), size, allocator) + { + for (std::size_t i = 0; i < size; ++i) + cancellation_signals_.emplace_back(); + } + + // The number of operations that have completed so far. Used to determine the + // order of completion. + std::atomic<unsigned int> completed_{0}; + + // The non-none cancellation type that resulted from a cancellation condition. + // Stored here for use by the group's initiating function. + std::atomic<cancellation_type_t> cancel_type_{cancellation_type::none}; + + // The number of cancellations that have been requested, either on completion + // of the operations within the group, or via the cancellation slot for the + // group operation. Initially set to the number of operations to prevent + // cancellation signals from being emitted until after all of the group's + // operations' initiating functions have completed. + std::atomic<unsigned int> cancellations_requested_; + + // The number of operations that are yet to complete. Used to determine when + // it is safe to invoke the user's completion handler. + std::atomic<unsigned int> outstanding_; + + // The cancellation signals for each operation in the group. + std::deque<asio::cancellation_signal, + ASIO_REBIND_ALLOC(Allocator, asio::cancellation_signal)> + cancellation_signals_; + + // The cancellation condition is used to determine whether the results from an + // individual operation warrant a cancellation request for the whole group. + Condition cancellation_condition_; + + // The proxy handler to be invoked once all operations in the group complete. + ranged_parallel_group_completion_handler<Handler, Op, Allocator> handler_; +}; + +// Handler for an individual operation within the parallel group. +template <typename Condition, typename Handler, typename Op, typename Allocator> +struct ranged_parallel_group_op_handler +{ + typedef asio::cancellation_slot cancellation_slot_type; + + ranged_parallel_group_op_handler( + std::shared_ptr<ranged_parallel_group_state< + Condition, Handler, Op, Allocator>> state, + std::size_t idx) + : state_(std::move(state)), + idx_(idx) + { + } + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return state_->cancellation_signals_[idx_].slot(); + } + + template <typename... Args> + void operator()(Args... args) + { + // Capture this operation into the completion order. + state_->handler_.completion_order_[state_->completed_++] = idx_; + + // Determine whether the results of this operation require cancellation of + // the whole group. + cancellation_type_t cancel_type = state_->cancellation_condition_(args...); + + // Capture the result of the operation into the proxy completion handler. + state_->handler_.args_[idx_].emplace(std::move(args)...); + + if (cancel_type != cancellation_type::none) + { + // Save the type for potential use by the group's initiating function. + state_->cancel_type_ = cancel_type; + + // If we are the first operation to request cancellation, emit a signal + // for each operation in the group. + if (state_->cancellations_requested_++ == 0) + for (std::size_t i = 0; i < state_->cancellation_signals_.size(); ++i) + if (i != idx_) + state_->cancellation_signals_[i].emit(cancel_type); + } + + // If this is the last outstanding operation, invoke the user's handler. + if (--state_->outstanding_ == 0) + asio::dispatch(std::move(state_->handler_)); + } + + std::shared_ptr<ranged_parallel_group_state< + Condition, Handler, Op, Allocator>> state_; + std::size_t idx_; +}; + +// Handler for an individual operation within the parallel group that has an +// explicitly specified executor. +template <typename Executor, typename Condition, + typename Handler, typename Op, typename Allocator> +struct ranged_parallel_group_op_handler_with_executor : + ranged_parallel_group_op_handler<Condition, Handler, Op, Allocator> +{ + typedef ranged_parallel_group_op_handler< + Condition, Handler, Op, Allocator> base_type; + typedef asio::cancellation_slot cancellation_slot_type; + typedef Executor executor_type; + + ranged_parallel_group_op_handler_with_executor( + std::shared_ptr<ranged_parallel_group_state< + Condition, Handler, Op, Allocator>> state, + executor_type ex, std::size_t idx) + : ranged_parallel_group_op_handler<Condition, Handler, Op, Allocator>( + std::move(state), idx) + { + cancel_proxy_ = + &this->state_->cancellation_signals_[idx].slot().template + emplace<cancel_proxy>(this->state_, std::move(ex)); + } + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return cancel_proxy_->signal_.slot(); + } + + executor_type get_executor() const noexcept + { + return cancel_proxy_->executor_; + } + + // Proxy handler that forwards the emitted signal to the correct executor. + struct cancel_proxy + { + cancel_proxy( + std::shared_ptr<ranged_parallel_group_state< + Condition, Handler, Op, Allocator>> state, + executor_type ex) + : state_(std::move(state)), + executor_(std::move(ex)) + { + } + + void operator()(cancellation_type_t type) + { + if (auto state = state_.lock()) + { + asio::cancellation_signal* sig = &signal_; + asio::dispatch(executor_, + [state, sig, type]{ sig->emit(type); }); + } + } + + std::weak_ptr<ranged_parallel_group_state< + Condition, Handler, Op, Allocator>> state_; + asio::cancellation_signal signal_; + executor_type executor_; + }; + + cancel_proxy* cancel_proxy_; +}; + +template <typename Condition, typename Handler, typename Op, typename Allocator> +struct ranged_parallel_group_cancellation_handler +{ + ranged_parallel_group_cancellation_handler( + std::shared_ptr<ranged_parallel_group_state< + Condition, Handler, Op, Allocator>> state) + : state_(std::move(state)) + { + } + + void operator()(cancellation_type_t cancel_type) + { + // If we are the first place to request cancellation, i.e. no operation has + // yet completed and requested cancellation, emit a signal for each + // operation in the group. + if (cancel_type != cancellation_type::none) + if (auto state = state_.lock()) + if (state->cancellations_requested_++ == 0) + for (std::size_t i = 0; i < state->cancellation_signals_.size(); ++i) + state->cancellation_signals_[i].emit(cancel_type); + } + + std::weak_ptr<ranged_parallel_group_state< + Condition, Handler, Op, Allocator>> state_; +}; + +template <typename Condition, typename Handler, + typename Range, typename Allocator> +void ranged_parallel_group_launch(Condition cancellation_condition, + Handler handler, Range&& range, const Allocator& allocator) +{ + // Get the user's completion handler's cancellation slot, so that we can allow + // cancellation of the entire group. + associated_cancellation_slot_t<Handler> slot + = asio::get_associated_cancellation_slot(handler); + + // The type of the asynchronous operation. + typedef decay_t<decltype(*declval<typename Range::iterator>())> op_type; + + // Create the shared state for the operation. + typedef ranged_parallel_group_state<Condition, + Handler, op_type, Allocator> state_type; + std::shared_ptr<state_type> state = std::allocate_shared<state_type>( + asio::detail::recycling_allocator<state_type, + asio::detail::thread_info_base::parallel_group_tag>(), + std::move(cancellation_condition), + std::move(handler), range.size(), allocator); + + std::size_t idx = 0; + for (auto&& op : std::forward<Range>(range)) + { + typedef associated_executor_t<op_type> ex_type; + ex_type ex = asio::get_associated_executor(op); + std::move(op)( + ranged_parallel_group_op_handler_with_executor< + ex_type, Condition, Handler, op_type, Allocator>( + state, std::move(ex), idx++)); + } + + // Check if any of the operations has already requested cancellation, and if + // so, emit a signal for each operation in the group. + if ((state->cancellations_requested_ -= range.size()) > 0) + for (auto& signal : state->cancellation_signals_) + signal.emit(state->cancel_type_); + + // Register a handler with the user's completion handler's cancellation slot. + if (slot.is_connected()) + slot.template emplace< + ranged_parallel_group_cancellation_handler< + Condition, Handler, op_type, Allocator>>(state); +} + +} // namespace detail +} // namespace experimental + +template <template <typename, typename> class Associator, + typename Handler, typename... Ops, typename DefaultCandidate> +struct associator<Associator, + experimental::detail::parallel_group_completion_handler<Handler, Ops...>, + DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const experimental::detail::parallel_group_completion_handler< + Handler, Ops...>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get( + const experimental::detail::parallel_group_completion_handler< + Handler, Ops...>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +template <template <typename, typename> class Associator, typename Handler, + typename Op, typename Allocator, typename DefaultCandidate> +struct associator<Associator, + experimental::detail::ranged_parallel_group_completion_handler< + Handler, Op, Allocator>, + DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const experimental::detail::ranged_parallel_group_completion_handler< + Handler, Op, Allocator>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get( + const experimental::detail::ranged_parallel_group_completion_handler< + Handler, Op, Allocator>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_EXPERIMENTAL_PARALLEL_GROUP_HPP 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 diff --git a/3rdparty/asio/include/asio/experimental/impl/use_coro.hpp b/3rdparty/asio/include/asio/experimental/impl/use_coro.hpp new file mode 100644 index 00000000000..ab5a2e68959 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/use_coro.hpp @@ -0,0 +1,214 @@ +// +// experimental/impl/use_coro.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_USE_CORO_HPP +#define ASIO_EXPERIMENTAL_IMPL_USE_CORO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/deferred.hpp" +#include "asio/experimental/coro.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Allocator, typename R> +struct async_result<experimental::use_coro_t<Allocator>, R()> +{ + template <typename Initiation, typename... InitArgs> + static auto initiate_impl(Initiation initiation, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void() noexcept, void, + asio::associated_executor_t<Initiation>, Allocator> + { + co_await deferred_async_operation<R(), Initiation, InitArgs...>( + deferred_init_tag{}, std::move(initiation), std::move(args)...); + } + + template <typename... InitArgs> + static auto initiate_impl(asio::detail::initiation_archetype<R()>, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), void, + asio::any_io_executor, Allocator>; + + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation initiation, + experimental::use_coro_t<Allocator> tk, InitArgs&&... args) + { + return initiate_impl(std::move(initiation), std::allocator_arg, + tk.get_allocator(), std::forward<InitArgs>(args)...); + } +}; + +template <typename Allocator, typename R> +struct async_result< + experimental::use_coro_t<Allocator>, R(asio::error_code)> +{ + template <typename Initiation, typename... InitArgs> + static auto initiate_impl(Initiation initiation, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void() noexcept, void, + asio::associated_executor_t<Initiation>, Allocator> + { + co_await deferred_async_operation< + R(asio::error_code), Initiation, InitArgs...>( + deferred_init_tag{}, std::move(initiation), std::move(args)...); + } + + template <typename... InitArgs> + static auto initiate_impl( + asio::detail::initiation_archetype<R(asio::error_code)>, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), void, + asio::any_io_executor, Allocator>; + + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation initiation, + experimental::use_coro_t<Allocator> tk, InitArgs&&... args) + { + return initiate_impl(std::move(initiation), std::allocator_arg, + tk.get_allocator(), std::forward<InitArgs>(args)...); + } +}; + +template <typename Allocator, typename R> +struct async_result< + experimental::use_coro_t<Allocator>, R(std::exception_ptr)> +{ + template <typename Initiation, typename... InitArgs> + static auto initiate_impl(Initiation initiation, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), void, + asio::associated_executor_t<Initiation>, Allocator> + { + co_await deferred_async_operation< + R(std::exception_ptr), Initiation, InitArgs...>( + deferred_init_tag{}, std::move(initiation), std::move(args)...); + } + + template <typename... InitArgs> + static auto initiate_impl( + asio::detail::initiation_archetype<R(std::exception_ptr)>, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), void, + asio::any_io_executor, Allocator>; + + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation initiation, + experimental::use_coro_t<Allocator> tk, InitArgs&&... args) + { + return initiate_impl(std::move(initiation), std::allocator_arg, + tk.get_allocator(), std::forward<InitArgs>(args)...); + } +}; + +template <typename Allocator, typename R, typename T> +struct async_result<experimental::use_coro_t<Allocator>, R(T)> +{ + + template <typename Initiation, typename... InitArgs> + static auto initiate_impl(Initiation initiation, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void() noexcept, T, + asio::associated_executor_t<Initiation>, Allocator> + { + co_return co_await deferred_async_operation<R(T), Initiation, InitArgs...>( + deferred_init_tag{}, std::move(initiation), std::move(args)...); + } + + template <typename... InitArgs> + static auto initiate_impl(asio::detail::initiation_archetype<R(T)>, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void() noexcept, T, + asio::any_io_executor, Allocator>; + + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation initiation, + experimental::use_coro_t<Allocator> tk, InitArgs&&... args) + { + return initiate_impl(std::move(initiation), std::allocator_arg, + tk.get_allocator(), std::forward<InitArgs>(args)...); + } +}; + +template <typename Allocator, typename R, typename T> +struct async_result< + experimental::use_coro_t<Allocator>, R(asio::error_code, T)> +{ + template <typename Initiation, typename... InitArgs> + static auto initiate_impl(Initiation initiation, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), T, + asio::associated_executor_t<Initiation>, Allocator> + { + co_return co_await deferred_async_operation< + R(asio::error_code, T), Initiation, InitArgs...>( + deferred_init_tag{}, std::move(initiation), std::move(args)...); + } + + template <typename... InitArgs> + static auto initiate_impl( + asio::detail::initiation_archetype< + R(asio::error_code, T)>, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), T, asio::any_io_executor, Allocator>; + + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation initiation, + experimental::use_coro_t<Allocator> tk, InitArgs&&... args) + { + return initiate_impl(std::move(initiation), std::allocator_arg, + tk.get_allocator(), std::forward<InitArgs>(args)...); + } +}; + +template <typename Allocator, typename R, typename T> +struct async_result< + experimental::use_coro_t<Allocator>, R(std::exception_ptr, T)> +{ + template <typename Initiation, typename... InitArgs> + static auto initiate_impl(Initiation initiation, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), T, + asio::associated_executor_t<Initiation>, Allocator> + { + co_return co_await deferred_async_operation< + R(std::exception_ptr, T), Initiation, InitArgs...>( + deferred_init_tag{}, std::move(initiation), std::move(args)...); + } + + template <typename... InitArgs> + static auto initiate_impl( + asio::detail::initiation_archetype<R(std::exception_ptr, T)>, + std::allocator_arg_t, Allocator, InitArgs... args) + -> experimental::coro<void(), T, asio::any_io_executor, Allocator>; + + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation initiation, + experimental::use_coro_t<Allocator> tk, InitArgs&&... args) + { + return initiate_impl(std::move(initiation), std::allocator_arg, + tk.get_allocator(), std::forward<InitArgs>(args)...); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_USE_CORO_HPP diff --git a/3rdparty/asio/include/asio/experimental/impl/use_promise.hpp b/3rdparty/asio/include/asio/experimental/impl/use_promise.hpp new file mode 100644 index 00000000000..259edb394bf --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/impl/use_promise.hpp @@ -0,0 +1,66 @@ +// +// experimental/impl/use_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_USE_PROMISE_HPP +#define ASIO_EXPERIMENTAL_IMPL_USE_PROMISE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <memory> +#include "asio/async_result.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +template <typename Allocator> +struct use_promise_t; + +namespace detail { + +template<typename Signature, typename Executor, typename Allocator> +struct promise_handler; + +} // namespace detail +} // namespace experimental + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Allocator, typename R, typename... Args> +struct async_result<experimental::use_promise_t<Allocator>, R(Args...)> +{ + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation initiation, + experimental::use_promise_t<Allocator> up, InitArgs... args) + -> experimental::promise<void(decay_t<Args>...), + asio::associated_executor_t<Initiation>, Allocator> + { + using handler_type = experimental::detail::promise_handler< + void(decay_t<Args>...), + asio::associated_executor_t<Initiation>, Allocator>; + + handler_type ht{up.get_allocator(), get_associated_executor(initiation)}; + std::move(initiation)(ht, std::move(args)...); + return ht.make_promise(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_IMPL_USE_PROMISE_HPP diff --git a/3rdparty/asio/include/asio/experimental/parallel_group.hpp b/3rdparty/asio/include/asio/experimental/parallel_group.hpp new file mode 100644 index 00000000000..967fc8802db --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/parallel_group.hpp @@ -0,0 +1,457 @@ +// +// experimental/parallel_group.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_PARALLEL_GROUP_HPP +#define ASIO_EXPERIMENTAL_PARALLEL_GROUP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <vector> +#include "asio/async_result.hpp" +#include "asio/detail/array.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/utility.hpp" +#include "asio/experimental/cancellation_condition.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { +namespace detail { + +// Helper trait for getting a tuple from a completion signature. + +template <typename Signature> +struct parallel_op_signature_as_tuple; + +template <typename R, typename... Args> +struct parallel_op_signature_as_tuple<R(Args...)> +{ + typedef std::tuple<decay_t<Args>...> type; +}; + +// Helper trait for concatenating completion signatures. + +template <std::size_t N, typename Offsets, typename... Signatures> +struct parallel_group_signature; + +template <std::size_t N, typename R0, typename... Args0> +struct parallel_group_signature<N, R0(Args0...)> +{ + typedef asio::detail::array<std::size_t, N> order_type; + typedef R0 raw_type(Args0...); + typedef R0 type(order_type, Args0...); +}; + +template <std::size_t N, + typename R0, typename... Args0, + typename R1, typename... Args1> +struct parallel_group_signature<N, R0(Args0...), R1(Args1...)> +{ + typedef asio::detail::array<std::size_t, N> order_type; + typedef R0 raw_type(Args0..., Args1...); + typedef R0 type(order_type, Args0..., Args1...); +}; + +template <std::size_t N, typename Sig0, + typename Sig1, typename... SigN> +struct parallel_group_signature<N, Sig0, Sig1, SigN...> +{ + typedef asio::detail::array<std::size_t, N> order_type; + typedef typename parallel_group_signature<N, + typename parallel_group_signature<N, Sig0, Sig1>::raw_type, + SigN...>::raw_type raw_type; + typedef typename parallel_group_signature<N, + typename parallel_group_signature<N, Sig0, Sig1>::raw_type, + SigN...>::type type; +}; + +template <typename Condition, typename Handler, + typename... Ops, std::size_t... I> +void parallel_group_launch(Condition cancellation_condition, Handler handler, + std::tuple<Ops...>& ops, asio::detail::index_sequence<I...>); + +// Helper trait for determining ranged parallel group completion signatures. + +template <typename Signature, typename Allocator> +struct ranged_parallel_group_signature; + +template <typename R, typename... Args, typename Allocator> +struct ranged_parallel_group_signature<R(Args...), Allocator> +{ + typedef std::vector<std::size_t, + ASIO_REBIND_ALLOC(Allocator, std::size_t)> order_type; + typedef R raw_type( + std::vector<Args, ASIO_REBIND_ALLOC(Allocator, Args)>...); + typedef R type(order_type, + std::vector<Args, ASIO_REBIND_ALLOC(Allocator, Args)>...); +}; + +template <typename Condition, typename Handler, + typename Range, typename Allocator> +void ranged_parallel_group_launch(Condition cancellation_condition, + Handler handler, Range&& range, const Allocator& allocator); + +char (¶llel_group_has_iterator_helper(...))[2]; + +template <typename T> +char parallel_group_has_iterator_helper(T*, typename T::iterator* = 0); + +template <typename T> +struct parallel_group_has_iterator_typedef +{ + enum { value = (sizeof((parallel_group_has_iterator_helper)((T*)(0))) == 1) }; +}; + +} // namespace detail + +/// Type trait used to determine whether a type is a range of asynchronous +/// operations that can be used with with @c make_parallel_group. +template <typename T> +struct is_async_operation_range +{ +#if defined(GENERATING_DOCUMENTATION) + /// The value member is true if the type may be used as a range of + /// asynchronous operations. + static const bool value; +#else + enum + { + value = detail::parallel_group_has_iterator_typedef<T>::value + }; +#endif +}; + +/// A group of asynchronous operations that may be launched in parallel. +/** + * See the documentation for asio::experimental::make_parallel_group for + * a usage example. + */ +template <typename... Ops> +class parallel_group +{ +private: + struct initiate_async_wait + { + template <typename Handler, typename Condition> + void operator()(Handler&& h, Condition&& c, std::tuple<Ops...>&& ops) const + { + detail::parallel_group_launch( + std::forward<Condition>(c), std::forward<Handler>(h), + ops, asio::detail::index_sequence_for<Ops...>()); + } + }; + + std::tuple<Ops...> ops_; + +public: + /// Constructor. + explicit parallel_group(Ops... ops) + : ops_(std::move(ops)...) + { + } + + /// The completion signature for the group of operations. + typedef typename detail::parallel_group_signature<sizeof...(Ops), + completion_signature_of_t<Ops>...>::type signature; + + /// Initiate an asynchronous wait for the group of operations. + /** + * Launches the group and asynchronously waits for completion. + * + * @param cancellation_condition A function object, called on completion of + * an operation within the group, that is used to determine whether to cancel + * the remaining operations. The function object is passed the arguments of + * the completed operation's handler. To trigger cancellation of the remaining + * operations, it must return a asio::cancellation_type value other + * than <tt>asio::cancellation_type::none</tt>. + * + * @param token A @ref completion_token whose signature is comprised of + * a @c std::array<std::size_t, N> indicating the completion order of the + * operations, followed by all operations' completion handler arguments. + * + * The library provides the following @c cancellation_condition types: + * + * @li asio::experimental::wait_for_all + * @li asio::experimental::wait_for_one + * @li asio::experimental::wait_for_one_error + * @li asio::experimental::wait_for_one_success + */ + template <typename CancellationCondition, + ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken> + auto async_wait(CancellationCondition cancellation_condition, + CompletionToken&& token) + -> decltype( + asio::async_initiate<CompletionToken, signature>( + declval<initiate_async_wait>(), token, + std::move(cancellation_condition), std::move(ops_))) + { + return asio::async_initiate<CompletionToken, signature>( + initiate_async_wait(), token, + std::move(cancellation_condition), std::move(ops_)); + } +}; + +/// Create a group of operations that may be launched in parallel. +/** + * For example: + * @code asio::experimental::make_parallel_group( + * [&](auto token) + * { + * return in.async_read_some(asio::buffer(data), token); + * }, + * [&](auto token) + * { + * return timer.async_wait(token); + * } + * ).async_wait( + * asio::experimental::wait_for_all(), + * []( + * std::array<std::size_t, 2> completion_order, + * std::error_code ec1, std::size_t n1, + * std::error_code ec2 + * ) + * { + * switch (completion_order[0]) + * { + * case 0: + * { + * std::cout << "descriptor finished: " << ec1 << ", " << n1 << "\n"; + * } + * break; + * case 1: + * { + * std::cout << "timer finished: " << ec2 << "\n"; + * } + * break; + * } + * } + * ); + * @endcode + */ +template <typename... Ops> +ASIO_NODISCARD inline parallel_group<Ops...> +make_parallel_group(Ops... ops) +{ + return parallel_group<Ops...>(std::move(ops)...); +} + +/// A range-based group of asynchronous operations that may be launched in +/// parallel. +/** + * See the documentation for asio::experimental::make_parallel_group for + * a usage example. + */ +template <typename Range, typename Allocator = std::allocator<void>> +class ranged_parallel_group +{ +private: + struct initiate_async_wait + { + template <typename Handler, typename Condition> + void operator()(Handler&& h, Condition&& c, + Range&& range, const Allocator& allocator) const + { + detail::ranged_parallel_group_launch(std::move(c), + std::move(h), std::forward<Range>(range), allocator); + } + }; + + Range range_; + Allocator allocator_; + +public: + /// Constructor. + explicit ranged_parallel_group(Range range, + const Allocator& allocator = Allocator()) + : range_(std::move(range)), + allocator_(allocator) + { + } + + /// The completion signature for the group of operations. + typedef typename detail::ranged_parallel_group_signature< + completion_signature_of_t< + decay_t<decltype(*std::declval<typename Range::iterator>())>>, + Allocator>::type signature; + + /// Initiate an asynchronous wait for the group of operations. + /** + * Launches the group and asynchronously waits for completion. + * + * @param cancellation_condition A function object, called on completion of + * an operation within the group, that is used to determine whether to cancel + * the remaining operations. The function object is passed the arguments of + * the completed operation's handler. To trigger cancellation of the remaining + * operations, it must return a asio::cancellation_type value other + * than <tt>asio::cancellation_type::none</tt>. + * + * @param token A @ref completion_token whose signature is comprised of + * a @c std::vector<std::size_t, Allocator> indicating the completion order of + * the operations, followed by a vector for each of the completion signature's + * arguments. + * + * The library provides the following @c cancellation_condition types: + * + * @li asio::experimental::wait_for_all + * @li asio::experimental::wait_for_one + * @li asio::experimental::wait_for_one_error + * @li asio::experimental::wait_for_one_success + */ + template <typename CancellationCondition, + ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken> + auto async_wait(CancellationCondition cancellation_condition, + CompletionToken&& token) + -> decltype( + asio::async_initiate<CompletionToken, signature>( + declval<initiate_async_wait>(), token, + std::move(cancellation_condition), + std::move(range_), allocator_)) + { + return asio::async_initiate<CompletionToken, signature>( + initiate_async_wait(), token, + std::move(cancellation_condition), + std::move(range_), allocator_); + } +}; + +/// Create a group of operations that may be launched in parallel. +/** + * @param range A range containing the operations to be launched. + * + * For example: + * @code + * using op_type = decltype( + * socket1.async_read_some( + * asio::buffer(data1), + * asio::deferred + * ) + * ); + * + * std::vector<op_type> ops; + * + * ops.push_back( + * socket1.async_read_some( + * asio::buffer(data1), + * asio::deferred + * ) + * ); + * + * ops.push_back( + * socket2.async_read_some( + * asio::buffer(data2), + * asio::deferred + * ) + * ); + * + * asio::experimental::make_parallel_group(ops).async_wait( + * asio::experimental::wait_for_all(), + * []( + * std::vector<std::size_t> completion_order, + * std::vector<std::error_code> e, + * std::vector<std::size_t> n + * ) + * { + * for (std::size_t i = 0; i < completion_order.size(); ++i) + * { + * std::size_t idx = completion_order[i]; + * std::cout << "socket " << idx << " finished: "; + * std::cout << e[idx] << ", " << n[idx] << "\n"; + * } + * } + * ); + * @endcode + */ +template <typename Range> +ASIO_NODISCARD inline ranged_parallel_group<decay_t<Range>> +make_parallel_group(Range&& range, + constraint_t< + is_async_operation_range<decay_t<Range>>::value + > = 0) +{ + return ranged_parallel_group<decay_t<Range>>(std::forward<Range>(range)); +} + +/// Create a group of operations that may be launched in parallel. +/** + * @param allocator Specifies the allocator to be used with the result vectors. + * + * @param range A range containing the operations to be launched. + * + * For example: + * @code + * using op_type = decltype( + * socket1.async_read_some( + * asio::buffer(data1), + * asio::deferred + * ) + * ); + * + * std::vector<op_type> ops; + * + * ops.push_back( + * socket1.async_read_some( + * asio::buffer(data1), + * asio::deferred + * ) + * ); + * + * ops.push_back( + * socket2.async_read_some( + * asio::buffer(data2), + * asio::deferred + * ) + * ); + * + * asio::experimental::make_parallel_group( + * std::allocator_arg_t, + * my_allocator, + * ops + * ).async_wait( + * asio::experimental::wait_for_all(), + * []( + * std::vector<std::size_t> completion_order, + * std::vector<std::error_code> e, + * std::vector<std::size_t> n + * ) + * { + * for (std::size_t i = 0; i < completion_order.size(); ++i) + * { + * std::size_t idx = completion_order[i]; + * std::cout << "socket " << idx << " finished: "; + * std::cout << e[idx] << ", " << n[idx] << "\n"; + * } + * } + * ); + * @endcode + */ +template <typename Allocator, typename Range> +ASIO_NODISCARD inline ranged_parallel_group<decay_t<Range>, Allocator> +make_parallel_group(allocator_arg_t, const Allocator& allocator, Range&& range, + constraint_t< + is_async_operation_range<decay_t<Range>>::value + > = 0) +{ + return ranged_parallel_group<decay_t<Range>, Allocator>( + std::forward<Range>(range), allocator); +} + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/parallel_group.hpp" + +#endif // ASIO_EXPERIMENTAL_PARALLEL_GROUP_HPP diff --git a/3rdparty/asio/include/asio/experimental/prepend.hpp b/3rdparty/asio/include/asio/experimental/prepend.hpp new file mode 100644 index 00000000000..503981f776f --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/prepend.hpp @@ -0,0 +1,36 @@ +// +// experimental/prepend.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_PREPEND_HPP +#define ASIO_EXPERIMENTAL_PREPEND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/prepend.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +#if !defined(ASIO_NO_DEPRECATED) +using asio::prepend_t; +using asio::prepend; +#endif // !defined(ASIO_NO_DEPRECATED) + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_PREPEND_HPP diff --git a/3rdparty/asio/include/asio/experimental/promise.hpp b/3rdparty/asio/include/asio/experimental/promise.hpp new file mode 100644 index 00000000000..2bcf66b4e30 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/promise.hpp @@ -0,0 +1,224 @@ +// +// experimental/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_PROMISE_HPP +#define ASIO_EXPERIMENTAL_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/detail/type_traits.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/associated_executor.hpp" +#include "asio/bind_executor.hpp" +#include "asio/cancellation_signal.hpp" +#include "asio/dispatch.hpp" +#include "asio/experimental/impl/promise.hpp" +#include "asio/post.hpp" + +#include <algorithm> + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +template <typename T> +struct is_promise : std::false_type {}; + +template <typename ... Ts> +struct is_promise<promise<Ts...>> : std::true_type {}; + +template <typename T> +constexpr bool is_promise_v = is_promise<T>::value; + +template <typename ... Ts> +struct promise_value_type +{ + using type = std::tuple<Ts...>; +}; + +template <typename T> +struct promise_value_type<T> +{ + using type = T; +}; + +template <> +struct promise_value_type<> +{ + using type = std::tuple<>; +}; + +#if defined(GENERATING_DOCUMENTATION) +/// A disposable handle for an eager operation. +/** + * @tparam Signature The signature of the operation. + * + * @tparam Executor The executor to be used by the promise (taken from the + * operation). + * + * @tparam Allocator The allocator used for the promise. Can be set through + * use_allocator. + * + * A promise can be used to initiate an asynchronous option that can be + * completed later. If the promise gets destroyed before completion, the + * operation gets a cancel signal and the result is ignored. + * + * A promise fulfills the requirements of async_operation. + * + * @par Examples + * Reading and writing from one coroutine. + * @code + * awaitable<void> read_write_some(asio::ip::tcp::socket & sock, + * asio::mutable_buffer read_buf, asio::const_buffer to_write) + * { + * auto p = asio::async_read(read_buf, asio::use_awaitable); + * co_await asio::async_write_some(to_write, asio::deferred); + * co_await p; + * } + * @endcode + */ +template<typename Signature = void(), + typename Executor = asio::any_io_executor, + typename Allocator = std::allocator<void>> +struct promise +#else +template <typename ... Ts, typename Executor, typename Allocator> +struct promise<void(Ts...), Executor, Allocator> +#endif // defined(GENERATING_DOCUMENTATION) +{ + /// The value that's returned by the promise. + using value_type = typename promise_value_type<Ts...>::type; + + /// Cancel the promise. Usually done through the destructor. + void cancel(cancellation_type level = cancellation_type::all) + { + if (impl_ && !impl_->done) + { + asio::dispatch(impl_->executor, + [level, impl = impl_]{ impl->cancel.emit(level); }); + } + } + + /// Check if the promise is completed already. + bool completed() const noexcept + { + return impl_ && impl_->done; + } + + /// Wait for the promise to become ready. + template <ASIO_COMPLETION_TOKEN_FOR(void(Ts...)) CompletionToken> + inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(Ts...)) + operator()(CompletionToken&& token) + { + assert(impl_); + + return async_initiate<CompletionToken, void(Ts...)>( + initiate_async_wait{impl_}, token); + } + + promise() = delete; + promise(const promise& ) = delete; + promise(promise&& ) noexcept = default; + + /// Destruct the promise and cancel the operation. + /** + * It is safe to destruct a promise of a promise that didn't complete. + */ + ~promise() { cancel(); } + + +private: +#if !defined(GENERATING_DOCUMENTATION) + template <typename, typename, typename> friend struct promise; + friend struct detail::promise_handler<void(Ts...), Executor, Allocator>; +#endif // !defined(GENERATING_DOCUMENTATION) + + std::shared_ptr<detail::promise_impl< + void(Ts...), Executor, Allocator>> impl_; + + promise( + std::shared_ptr<detail::promise_impl< + void(Ts...), Executor, Allocator>> impl) + : impl_(impl) + { + } + + struct initiate_async_wait + { + std::shared_ptr<detail::promise_impl< + void(Ts...), Executor, Allocator>> self_; + + template <typename WaitHandler> + void operator()(WaitHandler&& handler) const + { + const auto alloc = get_associated_allocator( + handler, self_->get_allocator()); + + auto cancel = get_associated_cancellation_slot(handler); + + if (self_->done) + { + auto exec = asio::get_associated_executor( + handler, self_->get_executor()); + + asio::post(exec, + [self = std::move(self_), + handler = std::forward<WaitHandler>(handler)]() mutable + { + self->apply(std::move(handler)); + }); + } + else + { + if (cancel.is_connected()) + { + struct cancel_handler + { + std::weak_ptr<detail::promise_impl< + void(Ts...), Executor, Allocator>> self; + + cancel_handler( + std::weak_ptr<detail::promise_impl< + void(Ts...), Executor, Allocator>> self) + : self(std::move(self)) + { + } + + void operator()(cancellation_type level) const + { + if (auto p = self.lock()) + { + p->cancel.emit(level); + p->cancel_(); + } + } + }; + cancel.template emplace<cancel_handler>(self_); + } + + self_->set_completion(alloc, std::forward<WaitHandler>(handler)); + } + } + }; +}; + +} // namespace experimental + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_EXPERIMENTAL_PROMISE_HPP diff --git a/3rdparty/asio/include/asio/experimental/use_coro.hpp b/3rdparty/asio/include/asio/experimental/use_coro.hpp new file mode 100644 index 00000000000..d9e0544106c --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/use_coro.hpp @@ -0,0 +1,189 @@ +// +// experimental/use_coro.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_USE_CORO_HPP +#define ASIO_EXPERIMENTAL_USE_CORO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <memory> +#include "asio/deferred.hpp" +#include "asio/detail/source_location.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class any_io_executor; + +namespace experimental { + +/// A @ref completion_token that creates another coro for the task completion. +/** + * The @c use_coro_t class, with its value @c use_coro, is used to represent an + * operation that can be awaited by the current resumable coroutine. This + * completion token may be passed as a handler to an asynchronous operation. + * For example: + * + * @code coro<void> my_coroutine(tcp::socket my_socket) + * { + * std::size_t n = co_await my_socket.async_read_some(buffer, use_coro); + * ... + * } @endcode + * + * When used with co_await, the initiating function (@c async_read_some in the + * above example) suspends the current coroutine. The coroutine is resumed when + * the asynchronous operation completes, and the result of the operation is + * returned. + * + * Note that this token is not the most efficient (use @c asio::deferred + * for that) but does provide type erasure, as it will always return a @c coro. + */ +template <typename Allocator = std::allocator<void>> +struct use_coro_t +{ + + /// The allocator type. The allocator is used when constructing the + /// @c std::promise object for a given asynchronous operation. + typedef Allocator allocator_type; + + /// Default constructor. + constexpr use_coro_t( + allocator_type allocator = allocator_type{} +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , asio::detail::source_location location = + asio::detail::source_location::current() +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + ) + : allocator_(allocator) +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , file_name_(location.file_name()), + line_(location.line()), + function_name_(location.function_name()) +# else // defined(ASIO_HAS_SOURCE_LOCATION) + , file_name_(0), + line_(0), + function_name_(0) +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + { + } + + + /// Specify an alternate allocator. + template <typename OtherAllocator> + use_coro_t<OtherAllocator> rebind(const OtherAllocator& allocator) const + { + return use_future_t<OtherAllocator>(allocator); + } + + /// Obtain allocator. + allocator_type get_allocator() const + { + return allocator_; + } + + /// Constructor used to specify file name, line, and function name. + constexpr use_coro_t(const char* file_name, + int line, const char* function_name, + allocator_type allocator = allocator_type{}) : +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + file_name_(file_name), + line_(line), + function_name_(function_name), +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + allocator_(allocator) + { +#if !defined(ASIO_ENABLE_HANDLER_TRACKING) + (void)file_name; + (void)line; + (void)function_name; +#endif // !defined(ASIO_ENABLE_HANDLER_TRACKING) + } + + /// Adapts an executor to add the @c use_coro_t completion token as the + /// default. + template <typename InnerExecutor> + struct executor_with_default : InnerExecutor + { + /// Specify @c use_coro_t as the default completion token type. + typedef use_coro_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + template <typename InnerExecutor1> + executor_with_default(const InnerExecutor1& ex, + constraint_t< + conditional_t< + !is_same<InnerExecutor1, executor_with_default>::value, + is_convertible<InnerExecutor1, InnerExecutor>, + false_type + >::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c use_coro_t as its + /// default completion token type. + template <typename T> + using as_default_on_t = typename T::template rebind_executor< + executor_with_default<typename T::executor_type>>::other; + + /// Function helper to adapt an I/O object to use @c use_coro_t as its + /// default completion token type. + template <typename T> + static typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other(static_cast<T&&>(object)); + } + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + const char* file_name_; + int line_; + const char* function_name_; +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +private: + Allocator allocator_; +}; + +/// A @ref completion_token object that represents the currently executing +/// resumable coroutine. +/** + * See the documentation for asio::use_coro_t for a usage example. + */ +#if defined(GENERATING_DOCUMENTATION) +constexpr use_coro_t<> use_coro; +#else +constexpr use_coro_t<> use_coro(0, 0, 0); +#endif + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/use_coro.hpp" +#include "asio/experimental/coro.hpp" + +#endif // ASIO_EXPERIMENTAL_USE_CORO_HPP diff --git a/3rdparty/asio/include/asio/experimental/use_promise.hpp b/3rdparty/asio/include/asio/experimental/use_promise.hpp new file mode 100644 index 00000000000..cf19aca59d5 --- /dev/null +++ b/3rdparty/asio/include/asio/experimental/use_promise.hpp @@ -0,0 +1,111 @@ +// +// experimental/use_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_USE_PROMISE_HPP +#define ASIO_EXPERIMENTAL_USE_PROMISE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <memory> +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace experimental { + +template <typename Allocator = std::allocator<void>> +struct use_promise_t +{ + /// The allocator type. The allocator is used when constructing the + /// @c promise object for a given asynchronous operation. + typedef Allocator allocator_type; + + /// Construct using default-constructed allocator. + constexpr use_promise_t() + { + } + + /// Construct using specified allocator. + explicit use_promise_t(const Allocator& allocator) + : allocator_(allocator) + { + } + + /// Obtain allocator. + allocator_type get_allocator() const noexcept + { + return allocator_; + } + + /// Adapts an executor to add the @c use_promise_t completion token as the + /// default. + template <typename InnerExecutor> + struct executor_with_default : InnerExecutor + { + /// Specify @c use_promise_t as the default completion token type. + typedef use_promise_t<Allocator> default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + executor_with_default(const InnerExecutor& ex) noexcept + : InnerExecutor(ex) + { + } + + /// Convert the specified executor to the inner executor type, then use + /// that to construct the adapted executor. + template <typename OtherExecutor> + executor_with_default(const OtherExecutor& ex, + constraint_t< + is_convertible<OtherExecutor, InnerExecutor>::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Function helper to adapt an I/O object to use @c use_promise_t as its + /// default completion token type. + template <typename T> + static typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other(static_cast<T&&>(object)); + } + + /// Specify an alternate allocator. + template <typename OtherAllocator> + use_promise_t<OtherAllocator> rebind(const OtherAllocator& allocator) const + { + return use_promise_t<OtherAllocator>(allocator); + } + +private: + Allocator allocator_; +}; + +constexpr use_promise_t<> use_promise; + +} // namespace experimental +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/experimental/impl/use_promise.hpp" + +#endif // ASIO_EXPERIMENTAL_USE_CORO_HPP diff --git a/3rdparty/asio/include/asio/file_base.hpp b/3rdparty/asio/include/asio/file_base.hpp new file mode 100644 index 00000000000..5e8ac4f2ed5 --- /dev/null +++ b/3rdparty/asio/include/asio/file_base.hpp @@ -0,0 +1,166 @@ +// +// file_base.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_FILE_BASE_HPP +#define ASIO_FILE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + || defined(GENERATING_DOCUMENTATION) + +#if !defined(ASIO_WINDOWS) +# include <fcntl.h> +#endif // !defined(ASIO_WINDOWS) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// The file_base class is used as a base for the basic_stream_file and +/// basic_random_access_file class templates so that we have a common place to +/// define flags. +class file_base +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// A bitmask type (C++ Std [lib.bitmask.types]). + typedef unspecified flags; + + /// Open the file for reading. + static const flags read_only = implementation_defined; + + /// Open the file for writing. + static const flags write_only = implementation_defined; + + /// Open the file for reading and writing. + static const flags read_write = implementation_defined; + + /// Open the file in append mode. + static const flags append = implementation_defined; + + /// Create the file if it does not exist. + static const flags create = implementation_defined; + + /// Ensure a new file is created. Must be combined with @c create. + static const flags exclusive = implementation_defined; + + /// Open the file with any existing contents truncated. + static const flags truncate = implementation_defined; + + /// Open the file so that write operations automatically synchronise the file + /// data and metadata to disk. + static const flags sync_all_on_write = implementation_defined; +#else + enum flags + { +#if defined(ASIO_WINDOWS) + read_only = 1, + write_only = 2, + read_write = 4, + append = 8, + create = 16, + exclusive = 32, + truncate = 64, + sync_all_on_write = 128 +#else // defined(ASIO_WINDOWS) + read_only = O_RDONLY, + write_only = O_WRONLY, + read_write = O_RDWR, + append = O_APPEND, + create = O_CREAT, + exclusive = O_EXCL, + truncate = O_TRUNC, + sync_all_on_write = O_SYNC +#endif // defined(ASIO_WINDOWS) + }; + + // Implement bitmask operations as shown in C++ Std [lib.bitmask.types]. + + friend flags operator&(flags x, flags y) + { + return static_cast<flags>( + static_cast<unsigned int>(x) & static_cast<unsigned int>(y)); + } + + friend flags operator|(flags x, flags y) + { + return static_cast<flags>( + static_cast<unsigned int>(x) | static_cast<unsigned int>(y)); + } + + friend flags operator^(flags x, flags y) + { + return static_cast<flags>( + static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y)); + } + + friend flags operator~(flags x) + { + return static_cast<flags>(~static_cast<unsigned int>(x)); + } + + friend flags& operator&=(flags& x, flags y) + { + x = x & y; + return x; + } + + friend flags& operator|=(flags& x, flags y) + { + x = x | y; + return x; + } + + friend flags& operator^=(flags& x, flags y) + { + x = x ^ y; + return x; + } +#endif + + /// Basis for seeking in a file. + enum seek_basis + { +#if defined(GENERATING_DOCUMENTATION) + /// Seek to an absolute position. + seek_set = implementation_defined, + + /// Seek to an offset relative to the current file position. + seek_cur = implementation_defined, + + /// Seek to an offset relative to the end of the file. + seek_end = implementation_defined +#else + seek_set = SEEK_SET, + seek_cur = SEEK_CUR, + seek_end = SEEK_END +#endif + }; + +protected: + /// Protected destructor to prevent deletion through this type. + ~file_base() + { + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_FILE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_FILE_BASE_HPP diff --git a/3rdparty/asio/include/asio/generic/basic_endpoint.hpp b/3rdparty/asio/include/asio/generic/basic_endpoint.hpp index 1faf4a174b5..e7e1f6d4103 100644 --- a/3rdparty/asio/include/asio/generic/basic_endpoint.hpp +++ b/3rdparty/asio/include/asio/generic/basic_endpoint.hpp @@ -2,7 +2,7 @@ // generic/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -54,7 +54,7 @@ public: #endif /// Default constructor. - basic_endpoint() + basic_endpoint() noexcept { } @@ -78,13 +78,11 @@ public: { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. basic_endpoint(basic_endpoint&& other) : impl_(other.impl_) { } -#endif // defined(ASIO_HAS_MOVE) /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) @@ -93,14 +91,12 @@ public: return *this; } -#if defined(ASIO_HAS_MOVE) /// Move-assign from another endpoint. basic_endpoint& operator=(basic_endpoint&& other) { impl_ = other.impl_; return *this; } -#endif // defined(ASIO_HAS_MOVE) /// The protocol associated with the endpoint. protocol_type protocol() const diff --git a/3rdparty/asio/include/asio/generic/datagram_protocol.hpp b/3rdparty/asio/include/asio/generic/datagram_protocol.hpp index 21a39de204f..6e81cd6a084 100644 --- a/3rdparty/asio/include/asio/generic/datagram_protocol.hpp +++ b/3rdparty/asio/include/asio/generic/datagram_protocol.hpp @@ -2,7 +2,7 @@ // generic/datagram_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -73,19 +73,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return ASIO_OS_DEF(SOCK_DGRAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return family_; } diff --git a/3rdparty/asio/include/asio/generic/detail/endpoint.hpp b/3rdparty/asio/include/asio/generic/detail/endpoint.hpp index 8de7b2aaed3..fdbcde92e5a 100644 --- a/3rdparty/asio/include/asio/generic/detail/endpoint.hpp +++ b/3rdparty/asio/include/asio/generic/detail/endpoint.hpp @@ -2,7 +2,7 @@ // generic/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/generic/detail/impl/endpoint.ipp b/3rdparty/asio/include/asio/generic/detail/impl/endpoint.ipp index 1a66fb95665..3e88c21098b 100644 --- a/3rdparty/asio/include/asio/generic/detail/impl/endpoint.ipp +++ b/3rdparty/asio/include/asio/generic/detail/impl/endpoint.ipp @@ -2,7 +2,7 @@ // generic/detail/impl/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -94,7 +94,8 @@ void endpoint::init(const void* sock_addr, using namespace std; // For memset and memcpy. memset(&data_.generic, 0, sizeof(asio::detail::sockaddr_storage_type)); - memcpy(&data_.generic, sock_addr, sock_addr_size); + if (sock_addr_size > 0) + memcpy(&data_.generic, sock_addr, sock_addr_size); size_ = sock_addr_size; protocol_ = sock_protocol; diff --git a/3rdparty/asio/include/asio/generic/raw_protocol.hpp b/3rdparty/asio/include/asio/generic/raw_protocol.hpp index 9a7407335c5..fc81cdd1ee9 100644 --- a/3rdparty/asio/include/asio/generic/raw_protocol.hpp +++ b/3rdparty/asio/include/asio/generic/raw_protocol.hpp @@ -2,7 +2,7 @@ // generic/raw_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -73,19 +73,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return ASIO_OS_DEF(SOCK_RAW); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return family_; } diff --git a/3rdparty/asio/include/asio/generic/seq_packet_protocol.hpp b/3rdparty/asio/include/asio/generic/seq_packet_protocol.hpp index d01d9cb2baa..e0342a47836 100644 --- a/3rdparty/asio/include/asio/generic/seq_packet_protocol.hpp +++ b/3rdparty/asio/include/asio/generic/seq_packet_protocol.hpp @@ -2,7 +2,7 @@ // generic/seq_packet_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -72,19 +72,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return ASIO_OS_DEF(SOCK_SEQPACKET); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return family_; } diff --git a/3rdparty/asio/include/asio/generic/stream_protocol.hpp b/3rdparty/asio/include/asio/generic/stream_protocol.hpp index 6917c199c51..270006e60ed 100644 --- a/3rdparty/asio/include/asio/generic/stream_protocol.hpp +++ b/3rdparty/asio/include/asio/generic/stream_protocol.hpp @@ -2,7 +2,7 @@ // generic/stream_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -74,19 +74,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return ASIO_OS_DEF(SOCK_STREAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return family_; } diff --git a/3rdparty/asio/include/asio/handler_alloc_hook.hpp b/3rdparty/asio/include/asio/handler_alloc_hook.hpp deleted file mode 100644 index a05ad4cc097..00000000000 --- a/3rdparty/asio/include/asio/handler_alloc_hook.hpp +++ /dev/null @@ -1,81 +0,0 @@ -// -// handler_alloc_hook.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_HANDLER_ALLOC_HOOK_HPP -#define ASIO_HANDLER_ALLOC_HOOK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include <cstddef> - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default allocation function for handlers. -/** - * Asynchronous operations may need to allocate temporary objects. Since - * asynchronous operations have a handler function object, these temporary - * objects can be said to be associated with the handler. - * - * Implement asio_handler_allocate and asio_handler_deallocate for your own - * handlers to provide custom allocation for these temporary objects. - * - * The default implementation of these allocation hooks uses <tt>::operator - * new</tt> and <tt>::operator delete</tt>. - * - * @note All temporary objects associated with a handler will be deallocated - * before the upcall to the handler is performed. This allows the same memory to - * be reused for a subsequent asynchronous operation initiated by the handler. - * - * @par Example - * @code - * class my_handler; - * - * void* asio_handler_allocate(std::size_t size, my_handler* context) - * { - * return ::operator new(size); - * } - * - * void asio_handler_deallocate(void* pointer, std::size_t size, - * my_handler* context) - * { - * ::operator delete(pointer); - * } - * @endcode - */ -ASIO_DECL void* asio_handler_allocate( - std::size_t size, ...); - -/// Default deallocation function for handlers. -/** - * Implement asio_handler_allocate and asio_handler_deallocate for your own - * handlers to provide custom allocation for the associated temporary objects. - * - * The default implementation of these allocation hooks uses <tt>::operator - * new</tt> and <tt>::operator delete</tt>. - * - * @sa asio_handler_allocate. - */ -ASIO_DECL void asio_handler_deallocate( - void* pointer, std::size_t size, ...); - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#if defined(ASIO_HEADER_ONLY) -# include "asio/impl/handler_alloc_hook.ipp" -#endif // defined(ASIO_HEADER_ONLY) - -#endif // ASIO_HANDLER_ALLOC_HOOK_HPP diff --git a/3rdparty/asio/include/asio/handler_continuation_hook.hpp b/3rdparty/asio/include/asio/handler_continuation_hook.hpp index bea0cdc5ed8..8c5c65243de 100644 --- a/3rdparty/asio/include/asio/handler_continuation_hook.hpp +++ b/3rdparty/asio/include/asio/handler_continuation_hook.hpp @@ -2,7 +2,7 @@ // handler_continuation_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/handler_invoke_hook.hpp b/3rdparty/asio/include/asio/handler_invoke_hook.hpp deleted file mode 100644 index 65c0d08c9d5..00000000000 --- a/3rdparty/asio/include/asio/handler_invoke_hook.hpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// handler_invoke_hook.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_HANDLER_INVOKE_HOOK_HPP -#define ASIO_HANDLER_INVOKE_HOOK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/** @defgroup asio_handler_invoke asio::asio_handler_invoke - * - * @brief Default invoke function for handlers. - * - * Completion handlers for asynchronous operations are invoked by the - * io_context associated with the corresponding object (e.g. a socket or - * deadline_timer). Certain guarantees are made on when the handler may be - * invoked, in particular that a handler can only be invoked from a thread that - * is currently calling @c run() on the corresponding io_context object. - * Handlers may subsequently be invoked through other objects (such as - * io_context::strand objects) that provide additional guarantees. - * - * When asynchronous operations are composed from other asynchronous - * operations, all intermediate handlers should be invoked using the same - * method as the final handler. This is required to ensure that user-defined - * objects are not accessed in a way that may violate the guarantees. This - * hooking function ensures that the invoked method used for the final handler - * is accessible at each intermediate step. - * - * Implement asio_handler_invoke for your own handlers to specify a custom - * invocation strategy. - * - * This default implementation invokes the function object like so: - * @code function(); @endcode - * If necessary, the default implementation makes a copy of the function object - * so that the non-const operator() can be used. - * - * @par Example - * @code - * class my_handler; - * - * template <typename Function> - * void asio_handler_invoke(Function function, my_handler* context) - * { - * context->strand_.dispatch(function); - * } - * @endcode - */ -/*@{*/ - -/// Default handler invocation hook used for non-const function objects. -template <typename Function> -inline void asio_handler_invoke(Function& function, ...) -{ - function(); -} - -/// Default handler invocation hook used for const function objects. -template <typename Function> -inline void asio_handler_invoke(const Function& function, ...) -{ - Function tmp(function); - tmp(); -} - -/*@}*/ - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_HANDLER_INVOKE_HOOK_HPP diff --git a/3rdparty/asio/include/asio/handler_type.hpp b/3rdparty/asio/include/asio/handler_type.hpp deleted file mode 100644 index 49e71231f4d..00000000000 --- a/3rdparty/asio/include/asio/handler_type.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// handler_type.hpp -// ~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_HANDLER_TYPE_HPP -#define ASIO_HANDLER_TYPE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include "asio/detail/type_traits.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// (Deprecated: Use two-parameter version of async_result.) Default handler -/// type traits provided for all completion token types. -/** - * The handler_type traits class is used for determining the concrete handler - * type to be used for an asynchronous operation. It allows the handler type to - * be determined at the point where the specific completion handler signature - * is known. - * - * This template may be specialised for user-defined completion token types. - */ -template <typename CompletionToken, typename Signature, typename = void> -struct handler_type -{ - /// The handler type for the specific signature. - typedef typename conditional< - is_same<CompletionToken, typename decay<CompletionToken>::type>::value, - decay<CompletionToken>, - handler_type<typename decay<CompletionToken>::type, Signature> - >::type::type type; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_HANDLER_TYPE_HPP diff --git a/3rdparty/asio/include/asio/high_resolution_timer.hpp b/3rdparty/asio/include/asio/high_resolution_timer.hpp index dd9d4859802..50e8030a225 100644 --- a/3rdparty/asio/include/asio/high_resolution_timer.hpp +++ b/3rdparty/asio/include/asio/high_resolution_timer.hpp @@ -2,7 +2,7 @@ // high_resolution_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) - #include "asio/basic_waitable_timer.hpp" #include "asio/detail/chrono.hpp" @@ -39,6 +36,4 @@ typedef basic_waitable_timer< } // namespace asio -#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) - #endif // ASIO_HIGH_RESOLUTION_TIMER_HPP diff --git a/3rdparty/asio/include/asio/impl/any_completion_executor.ipp b/3rdparty/asio/include/asio/impl/any_completion_executor.ipp new file mode 100644 index 00000000000..fdad007dab1 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/any_completion_executor.ipp @@ -0,0 +1,126 @@ +// +// impl/any_completion_executor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_ANY_COMPLETION_EXECUTOR_IPP +#define ASIO_IMPL_ANY_COMPLETION_EXECUTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include "asio/any_completion_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +any_completion_executor::any_completion_executor() noexcept + : base_type() +{ +} + +any_completion_executor::any_completion_executor(nullptr_t) noexcept + : base_type(nullptr_t()) +{ +} + +any_completion_executor::any_completion_executor( + const any_completion_executor& e) noexcept + : base_type(static_cast<const base_type&>(e)) +{ +} + +any_completion_executor::any_completion_executor(std::nothrow_t, + const any_completion_executor& e) noexcept + : base_type(static_cast<const base_type&>(e)) +{ +} + +any_completion_executor::any_completion_executor( + any_completion_executor&& e) noexcept + : base_type(static_cast<base_type&&>(e)) +{ +} + +any_completion_executor::any_completion_executor(std::nothrow_t, + any_completion_executor&& e) noexcept + : base_type(static_cast<base_type&&>(e)) +{ +} + +any_completion_executor& any_completion_executor::operator=( + const any_completion_executor& e) noexcept +{ + base_type::operator=(static_cast<const base_type&>(e)); + return *this; +} + +any_completion_executor& any_completion_executor::operator=( + any_completion_executor&& e) noexcept +{ + base_type::operator=(static_cast<base_type&&>(e)); + return *this; +} + +any_completion_executor& any_completion_executor::operator=(nullptr_t) +{ + base_type::operator=(nullptr_t()); + return *this; +} + +any_completion_executor::~any_completion_executor() +{ +} + +void any_completion_executor::swap( + any_completion_executor& other) noexcept +{ + static_cast<base_type&>(*this).swap(static_cast<base_type&>(other)); +} + +template <> +any_completion_executor any_completion_executor::prefer( + const execution::outstanding_work_t::tracked_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +template <> +any_completion_executor any_completion_executor::prefer( + const execution::outstanding_work_t::untracked_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +template <> +any_completion_executor any_completion_executor::prefer( + const execution::relationship_t::fork_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +template <> +any_completion_executor any_completion_executor::prefer( + const execution::relationship_t::continuation_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#endif // ASIO_IMPL_ANY_COMPLETION_EXECUTOR_IPP diff --git a/3rdparty/asio/include/asio/impl/any_io_executor.ipp b/3rdparty/asio/include/asio/impl/any_io_executor.ipp new file mode 100644 index 00000000000..338ad4d3ae2 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/any_io_executor.ipp @@ -0,0 +1,134 @@ +// +// impl/any_io_executor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_ANY_IO_EXECUTOR_IPP +#define ASIO_IMPL_ANY_IO_EXECUTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include "asio/any_io_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +any_io_executor::any_io_executor() noexcept + : base_type() +{ +} + +any_io_executor::any_io_executor(nullptr_t) noexcept + : base_type(nullptr_t()) +{ +} + +any_io_executor::any_io_executor(const any_io_executor& e) noexcept + : base_type(static_cast<const base_type&>(e)) +{ +} + +any_io_executor::any_io_executor(std::nothrow_t, + const any_io_executor& e) noexcept + : base_type(static_cast<const base_type&>(e)) +{ +} + +any_io_executor::any_io_executor(any_io_executor&& e) noexcept + : base_type(static_cast<base_type&&>(e)) +{ +} + +any_io_executor::any_io_executor(std::nothrow_t, any_io_executor&& e) noexcept + : base_type(static_cast<base_type&&>(e)) +{ +} + +any_io_executor& any_io_executor::operator=(const any_io_executor& e) noexcept +{ + base_type::operator=(static_cast<const base_type&>(e)); + return *this; +} + +any_io_executor& any_io_executor::operator=(any_io_executor&& e) noexcept +{ + base_type::operator=(static_cast<base_type&&>(e)); + return *this; +} + +any_io_executor& any_io_executor::operator=(nullptr_t) +{ + base_type::operator=(nullptr_t()); + return *this; +} + +any_io_executor::~any_io_executor() +{ +} + +void any_io_executor::swap(any_io_executor& other) noexcept +{ + static_cast<base_type&>(*this).swap(static_cast<base_type&>(other)); +} + +template <> +any_io_executor any_io_executor::require( + const execution::blocking_t::never_t& p, int) const +{ + return static_cast<const base_type&>(*this).require(p); +} + +template <> +any_io_executor any_io_executor::prefer( + const execution::blocking_t::possibly_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +template <> +any_io_executor any_io_executor::prefer( + const execution::outstanding_work_t::tracked_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +template <> +any_io_executor any_io_executor::prefer( + const execution::outstanding_work_t::untracked_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +template <> +any_io_executor any_io_executor::prefer( + const execution::relationship_t::fork_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +template <> +any_io_executor any_io_executor::prefer( + const execution::relationship_t::continuation_t& p, int) const +{ + return static_cast<const base_type&>(*this).prefer(p); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#endif // ASIO_IMPL_ANY_IO_EXECUTOR_IPP diff --git a/3rdparty/asio/include/asio/impl/append.hpp b/3rdparty/asio/include/asio/impl/append.hpp new file mode 100644 index 00000000000..cfa54191fcd --- /dev/null +++ b/3rdparty/asio/include/asio/impl/append.hpp @@ -0,0 +1,162 @@ +// +// impl/append.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_APPEND_HPP +#define ASIO_IMPL_APPEND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/utility.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Class to adapt an append_t as a completion handler. +template <typename Handler, typename... Values> +class append_handler +{ +public: + typedef void result_type; + + template <typename H> + append_handler(H&& handler, std::tuple<Values...> values) + : handler_(static_cast<H&&>(handler)), + values_(static_cast<std::tuple<Values...>&&>(values)) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + this->invoke( + index_sequence_for<Values...>{}, + static_cast<Args&&>(args)...); + } + + template <std::size_t... I, typename... Args> + void invoke(index_sequence<I...>, Args&&... args) + { + static_cast<Handler&&>(handler_)( + static_cast<Args&&>(args)..., + static_cast<Values&&>(std::get<I>(values_))...); + } + +//private: + Handler handler_; + std::tuple<Values...> values_; +}; + +template <typename Handler> +inline bool asio_handler_is_continuation( + append_handler<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Signature, typename... Values> +struct append_signature; + +template <typename R, typename... Args, typename... Values> +struct append_signature<R(Args...), Values...> +{ + typedef R type(decay_t<Args>..., Values...); +}; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename... Values, typename Signature> +struct async_result<append_t<CompletionToken, Values...>, Signature> + : async_result<CompletionToken, + typename detail::append_signature< + Signature, Values...>::type> +{ + typedef typename detail::append_signature< + Signature, Values...>::type signature; + + template <typename Initiation> + struct init_wrapper + { + init_wrapper(Initiation init) + : initiation_(static_cast<Initiation&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, + std::tuple<Values...> values, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + detail::append_handler<decay_t<Handler>, Values...>( + static_cast<Handler&&>(handler), + static_cast<std::tuple<Values...>&&>(values)), + static_cast<Args&&>(args)...); + } + + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<CompletionToken, signature>( + declval<init_wrapper<decay_t<Initiation>>>(), + token.token_, + static_cast<std::tuple<Values...>&&>(token.values_), + static_cast<Args&&>(args)...)) + { + return async_initiate<CompletionToken, signature>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, + static_cast<std::tuple<Values...>&&>(token.values_), + static_cast<Args&&>(args)...); + } +}; + +template <template <typename, typename> class Associator, + typename Handler, typename... Values, typename DefaultCandidate> +struct associator<Associator, + detail::append_handler<Handler, Values...>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::append_handler<Handler, Values...>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const detail::append_handler<Handler, Values...>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_APPEND_HPP diff --git a/3rdparty/asio/include/asio/impl/as_tuple.hpp b/3rdparty/asio/include/asio/impl/as_tuple.hpp new file mode 100644 index 00000000000..6d47510b997 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/as_tuple.hpp @@ -0,0 +1,245 @@ +// +// impl/as_tuple.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_AS_TUPLE_HPP +#define ASIO_IMPL_AS_TUPLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <tuple> +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Class to adapt a as_tuple_t as a completion handler. +template <typename Handler> +class as_tuple_handler +{ +public: + typedef void result_type; + + template <typename CompletionToken> + as_tuple_handler(as_tuple_t<CompletionToken> e) + : handler_(static_cast<CompletionToken&&>(e.token_)) + { + } + + template <typename RedirectedHandler> + as_tuple_handler(RedirectedHandler&& h) + : handler_(static_cast<RedirectedHandler&&>(h)) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + static_cast<Handler&&>(handler_)( + std::make_tuple(static_cast<Args&&>(args)...)); + } + +//private: + Handler handler_; +}; + +template <typename Handler> +inline bool asio_handler_is_continuation( + as_tuple_handler<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Signature> +struct as_tuple_signature; + +template <typename R, typename... Args> +struct as_tuple_signature<R(Args...)> +{ + typedef R type(std::tuple<decay_t<Args>...>); +}; + +template <typename R, typename... Args> +struct as_tuple_signature<R(Args...) &> +{ + typedef R type(std::tuple<decay_t<Args>...>) &; +}; + +template <typename R, typename... Args> +struct as_tuple_signature<R(Args...) &&> +{ + typedef R type(std::tuple<decay_t<Args>...>) &&; +}; + +#if defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename R, typename... Args> +struct as_tuple_signature<R(Args...) noexcept> +{ + typedef R type(std::tuple<decay_t<Args>...>) noexcept; +}; + +template <typename R, typename... Args> +struct as_tuple_signature<R(Args...) & noexcept> +{ + typedef R type(std::tuple<decay_t<Args>...>) & noexcept; +}; + +template <typename R, typename... Args> +struct as_tuple_signature<R(Args...) && noexcept> +{ + typedef R type(std::tuple<decay_t<Args>...>) && noexcept; +}; + +#endif // defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename... Signatures> +struct async_result<as_tuple_t<CompletionToken>, Signatures...> + : async_result<CompletionToken, + typename detail::as_tuple_signature<Signatures>::type...> +{ + template <typename Initiation> + struct init_wrapper + { + init_wrapper(Initiation init) + : initiation_(static_cast<Initiation&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + detail::as_tuple_handler<decay_t<Handler>>( + static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate< + conditional_t< + is_const<remove_reference_t<RawCompletionToken>>::value, + const CompletionToken, CompletionToken>, + typename detail::as_tuple_signature<Signatures>::type...>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<Args&&>(args)...)) + { + return async_initiate< + conditional_t< + is_const<remove_reference_t<RawCompletionToken>>::value, + const CompletionToken, CompletionToken>, + typename detail::as_tuple_signature<Signatures>::type...>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<Args&&>(args)...); + } +}; + +#if defined(ASIO_MSVC) + +// Workaround for MSVC internal compiler error. + +template <typename CompletionToken, typename Signature> +struct async_result<as_tuple_t<CompletionToken>, Signature> + : async_result<CompletionToken, + typename detail::as_tuple_signature<Signature>::type> +{ + template <typename Initiation> + struct init_wrapper + { + init_wrapper(Initiation init) + : initiation_(static_cast<Initiation&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + detail::as_tuple_handler<decay_t<Handler>>( + static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate< + conditional_t< + is_const<remove_reference_t<RawCompletionToken>>::value, + const CompletionToken, CompletionToken>, + typename detail::as_tuple_signature<Signature>::type>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<Args&&>(args)...)) + { + return async_initiate< + conditional_t< + is_const<remove_reference_t<RawCompletionToken>>::value, + const CompletionToken, CompletionToken>, + typename detail::as_tuple_signature<Signature>::type>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<Args&&>(args)...); + } +}; + +#endif // defined(ASIO_MSVC) + +template <template <typename, typename> class Associator, + typename Handler, typename DefaultCandidate> +struct associator<Associator, + detail::as_tuple_handler<Handler>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::as_tuple_handler<Handler>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const detail::as_tuple_handler<Handler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_AS_TUPLE_HPP diff --git a/3rdparty/asio/include/asio/impl/awaitable.hpp b/3rdparty/asio/include/asio/impl/awaitable.hpp new file mode 100644 index 00000000000..c5ea2649171 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/awaitable.hpp @@ -0,0 +1,1196 @@ +// +// impl/awaitable.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_AWAITABLE_HPP +#define ASIO_IMPL_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <exception> +#include <new> +#include <tuple> +#include "asio/cancellation_signal.hpp" +#include "asio/cancellation_state.hpp" +#include "asio/detail/thread_context.hpp" +#include "asio/detail/thread_info_base.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/post.hpp" +#include "asio/system_error.hpp" +#include "asio/this_coro.hpp" + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) +# include "asio/detail/source_location.hpp" +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +struct awaitable_thread_has_context_switched {}; +template <typename, typename> class awaitable_async_op_handler; +template <typename, typename, typename> class awaitable_async_op; + +// An awaitable_thread represents a thread-of-execution that is composed of one +// or more "stack frames", with each frame represented by an awaitable_frame. +// All execution occurs in the context of the awaitable_thread's executor. An +// awaitable_thread continues to "pump" the stack frames by repeatedly resuming +// the top stack frame until the stack is empty, or until ownership of the +// stack is transferred to another awaitable_thread object. +// +// +------------------------------------+ +// | top_of_stack_ | +// | V +// +--------------+---+ +-----------------+ +// | | | | +// | awaitable_thread |<---------------------------+ awaitable_frame | +// | | attached_thread_ | | +// +--------------+---+ (Set only when +---+-------------+ +// | frames are being | +// | actively pumped | caller_ +// | by a thread, and | +// | then only for V +// | the top frame.) +-----------------+ +// | | | +// | | awaitable_frame | +// | | | +// | +---+-------------+ +// | | +// | | caller_ +// | : +// | : +// | | +// | V +// | +-----------------+ +// | bottom_of_stack_ | | +// +------------------------------->| awaitable_frame | +// | | +// +-----------------+ + +template <typename Executor> +class awaitable_frame_base +{ +public: +#if !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING) + void* operator new(std::size_t size) + { + return asio::detail::thread_info_base::allocate( + asio::detail::thread_info_base::awaitable_frame_tag(), + asio::detail::thread_context::top_of_thread_call_stack(), + size); + } + + void operator delete(void* pointer, std::size_t size) + { + asio::detail::thread_info_base::deallocate( + asio::detail::thread_info_base::awaitable_frame_tag(), + asio::detail::thread_context::top_of_thread_call_stack(), + pointer, size); + } +#endif // !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING) + + // The frame starts in a suspended state until the awaitable_thread object + // pumps the stack. + auto initial_suspend() noexcept + { + return suspend_always(); + } + + // On final suspension the frame is popped from the top of the stack. + auto final_suspend() noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + this->this_->pop_frame(); + } + + void await_resume() const noexcept + { + } + }; + + return result{this}; + } + + void set_except(std::exception_ptr e) noexcept + { + pending_exception_ = e; + } + + void set_error(const asio::error_code& ec) + { + this->set_except(std::make_exception_ptr(asio::system_error(ec))); + } + + void unhandled_exception() + { + set_except(std::current_exception()); + } + + void rethrow_exception() + { + if (pending_exception_) + { + std::exception_ptr ex = std::exchange(pending_exception_, nullptr); + std::rethrow_exception(ex); + } + } + + void clear_cancellation_slot() + { + this->attached_thread_->entry_point()->cancellation_state_.slot().clear(); + } + + template <typename T> + auto await_transform(awaitable<T, Executor> a) const + { + if (attached_thread_->entry_point()->throw_if_cancelled_) + if (!!attached_thread_->get_cancellation_state().cancelled()) + throw_error(asio::error::operation_aborted, "co_await"); + return a; + } + + template <typename Op> + auto await_transform(Op&& op, + constraint_t<is_async_operation<Op>::value> = 0 +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , detail::source_location location = detail::source_location::current() +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + ) + { + if (attached_thread_->entry_point()->throw_if_cancelled_) + if (!!attached_thread_->get_cancellation_state().cancelled()) + throw_error(asio::error::operation_aborted, "co_await"); + + return awaitable_async_op< + completion_signature_of_t<Op>, decay_t<Op>, Executor>{ + std::forward<Op>(op), this +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , location +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + }; + } + + // This await transformation obtains the associated executor of the thread of + // execution. + auto await_transform(this_coro::executor_t) noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() const noexcept + { + return this_->attached_thread_->get_executor(); + } + }; + + return result{this}; + } + + // This await transformation obtains the associated cancellation state of the + // thread of execution. + auto await_transform(this_coro::cancellation_state_t) noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() const noexcept + { + return this_->attached_thread_->get_cancellation_state(); + } + }; + + return result{this}; + } + + // This await transformation resets the associated cancellation state. + auto await_transform(this_coro::reset_cancellation_state_0_t) noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() const + { + return this_->attached_thread_->reset_cancellation_state(); + } + }; + + return result{this}; + } + + // This await transformation resets the associated cancellation state. + template <typename Filter> + auto await_transform( + this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept + { + struct result + { + awaitable_frame_base* this_; + Filter filter_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + return this_->attached_thread_->reset_cancellation_state( + static_cast<Filter&&>(filter_)); + } + }; + + return result{this, static_cast<Filter&&>(reset.filter)}; + } + + // This await transformation resets the associated cancellation state. + template <typename InFilter, typename OutFilter> + auto await_transform( + this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset) + noexcept + { + struct result + { + awaitable_frame_base* this_; + InFilter in_filter_; + OutFilter out_filter_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + return this_->attached_thread_->reset_cancellation_state( + static_cast<InFilter&&>(in_filter_), + static_cast<OutFilter&&>(out_filter_)); + } + }; + + return result{this, + static_cast<InFilter&&>(reset.in_filter), + static_cast<OutFilter&&>(reset.out_filter)}; + } + + // This await transformation determines whether cancellation is propagated as + // an exception. + auto await_transform(this_coro::throw_if_cancelled_0_t) + noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + return this_->attached_thread_->throw_if_cancelled(); + } + }; + + return result{this}; + } + + // This await transformation sets whether cancellation is propagated as an + // exception. + auto await_transform(this_coro::throw_if_cancelled_1_t throw_if_cancelled) + noexcept + { + struct result + { + awaitable_frame_base* this_; + bool value_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() + { + this_->attached_thread_->throw_if_cancelled(value_); + } + }; + + return result{this, throw_if_cancelled.value}; + } + + // This await transformation is used to run an async operation's initiation + // function object after the coroutine has been suspended. This ensures that + // immediate resumption of the coroutine in another thread does not cause a + // race condition. + template <typename Function> + auto await_transform(Function f, + enable_if_t< + is_convertible< + result_of_t<Function(awaitable_frame_base*)>, + awaitable_thread<Executor>* + >::value + >* = nullptr) + { + struct result + { + Function function_; + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + this_->after_suspend( + [](void* arg) + { + result* r = static_cast<result*>(arg); + r->function_(r->this_); + }, this); + } + + void await_resume() const noexcept + { + } + }; + + return result{std::move(f), this}; + } + + // Access the awaitable thread's has_context_switched_ flag. + auto await_transform(detail::awaitable_thread_has_context_switched) noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + bool& await_resume() const noexcept + { + return this_->attached_thread_->entry_point()->has_context_switched_; + } + }; + + return result{this}; + } + + void attach_thread(awaitable_thread<Executor>* handler) noexcept + { + attached_thread_ = handler; + } + + awaitable_thread<Executor>* detach_thread() noexcept + { + attached_thread_->entry_point()->has_context_switched_ = true; + return std::exchange(attached_thread_, nullptr); + } + + void push_frame(awaitable_frame_base<Executor>* caller) noexcept + { + caller_ = caller; + attached_thread_ = caller_->attached_thread_; + attached_thread_->entry_point()->top_of_stack_ = this; + caller_->attached_thread_ = nullptr; + } + + void pop_frame() noexcept + { + if (caller_) + caller_->attached_thread_ = attached_thread_; + attached_thread_->entry_point()->top_of_stack_ = caller_; + attached_thread_ = nullptr; + caller_ = nullptr; + } + + struct resume_context + { + void (*after_suspend_fn_)(void*) = nullptr; + void *after_suspend_arg_ = nullptr; + }; + + void resume() + { + resume_context context; + resume_context_ = &context; + coro_.resume(); + if (context.after_suspend_fn_) + context.after_suspend_fn_(context.after_suspend_arg_); + } + + void after_suspend(void (*fn)(void*), void* arg) + { + resume_context_->after_suspend_fn_ = fn; + resume_context_->after_suspend_arg_ = arg; + } + + void destroy() + { + coro_.destroy(); + } + +protected: + coroutine_handle<void> coro_ = nullptr; + awaitable_thread<Executor>* attached_thread_ = nullptr; + awaitable_frame_base<Executor>* caller_ = nullptr; + std::exception_ptr pending_exception_ = nullptr; + resume_context* resume_context_ = nullptr; +}; + +template <typename T, typename Executor> +class awaitable_frame + : public awaitable_frame_base<Executor> +{ +public: + awaitable_frame() noexcept + { + } + + awaitable_frame(awaitable_frame&& other) noexcept + : awaitable_frame_base<Executor>(std::move(other)) + { + } + + ~awaitable_frame() + { + if (has_result_) + std::launder(static_cast<T*>(static_cast<void*>(result_)))->~T(); + } + + awaitable<T, Executor> get_return_object() noexcept + { + this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this); + return awaitable<T, Executor>(this); + }; + + template <typename U> + void return_value(U&& u) + { + new (&result_) T(std::forward<U>(u)); + has_result_ = true; + } + + template <typename... Us> + void return_values(Us&&... us) + { + this->return_value(std::forward_as_tuple(std::forward<Us>(us)...)); + } + + T get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + return std::move(*std::launder( + static_cast<T*>(static_cast<void*>(result_)))); + } + +private: + alignas(T) unsigned char result_[sizeof(T)]; + bool has_result_ = false; +}; + +template <typename Executor> +class awaitable_frame<void, Executor> + : public awaitable_frame_base<Executor> +{ +public: + awaitable<void, Executor> get_return_object() + { + this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this); + return awaitable<void, Executor>(this); + }; + + void return_void() + { + } + + void get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + } +}; + +struct awaitable_thread_entry_point {}; + +template <typename Executor> +class awaitable_frame<awaitable_thread_entry_point, Executor> + : public awaitable_frame_base<Executor> +{ +public: + awaitable_frame() + : top_of_stack_(0), + has_executor_(false), + has_context_switched_(false), + throw_if_cancelled_(true) + { + } + + ~awaitable_frame() + { + if (has_executor_) + u_.executor_.~Executor(); + } + + awaitable<awaitable_thread_entry_point, Executor> get_return_object() + { + this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this); + return awaitable<awaitable_thread_entry_point, Executor>(this); + }; + + void return_void() + { + } + + void get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + } + +private: + template <typename> friend class awaitable_frame_base; + template <typename, typename> friend class awaitable_async_op_handler; + template <typename, typename> friend class awaitable_handler_base; + template <typename> friend class awaitable_thread; + + union u + { + u() {} + ~u() {} + char c_; + Executor executor_; + } u_; + + awaitable_frame_base<Executor>* top_of_stack_; + asio::cancellation_slot parent_cancellation_slot_; + asio::cancellation_state cancellation_state_; + bool has_executor_; + bool has_context_switched_; + bool throw_if_cancelled_; +}; + +template <typename Executor> +class awaitable_thread +{ +public: + typedef Executor executor_type; + typedef cancellation_slot cancellation_slot_type; + + // Construct from the entry point of a new thread of execution. + awaitable_thread(awaitable<awaitable_thread_entry_point, Executor> p, + const Executor& ex, cancellation_slot parent_cancel_slot, + cancellation_state cancel_state) + : bottom_of_stack_(std::move(p)) + { + bottom_of_stack_.frame_->top_of_stack_ = bottom_of_stack_.frame_; + new (&bottom_of_stack_.frame_->u_.executor_) Executor(ex); + bottom_of_stack_.frame_->has_executor_ = true; + bottom_of_stack_.frame_->parent_cancellation_slot_ = parent_cancel_slot; + bottom_of_stack_.frame_->cancellation_state_ = cancel_state; + } + + // Transfer ownership from another awaitable_thread. + awaitable_thread(awaitable_thread&& other) noexcept + : bottom_of_stack_(std::move(other.bottom_of_stack_)) + { + } + + // Clean up with a last ditch effort to ensure the thread is unwound within + // the context of the executor. + ~awaitable_thread() + { + if (bottom_of_stack_.valid()) + { + // Coroutine "stack unwinding" must be performed through the executor. + auto* bottom_frame = bottom_of_stack_.frame_; + (post)(bottom_frame->u_.executor_, + [a = std::move(bottom_of_stack_)]() mutable + { + (void)awaitable<awaitable_thread_entry_point, Executor>( + std::move(a)); + }); + } + } + + awaitable_frame<awaitable_thread_entry_point, Executor>* entry_point() + { + return bottom_of_stack_.frame_; + } + + executor_type get_executor() const noexcept + { + return bottom_of_stack_.frame_->u_.executor_; + } + + cancellation_state get_cancellation_state() const noexcept + { + return bottom_of_stack_.frame_->cancellation_state_; + } + + void reset_cancellation_state() + { + bottom_of_stack_.frame_->cancellation_state_ = + cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_); + } + + template <typename Filter> + void reset_cancellation_state(Filter&& filter) + { + bottom_of_stack_.frame_->cancellation_state_ = + cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_, + static_cast<Filter&&>(filter)); + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(InFilter&& in_filter, + OutFilter&& out_filter) + { + bottom_of_stack_.frame_->cancellation_state_ = + cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_, + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)); + } + + bool throw_if_cancelled() const + { + return bottom_of_stack_.frame_->throw_if_cancelled_; + } + + void throw_if_cancelled(bool value) + { + bottom_of_stack_.frame_->throw_if_cancelled_ = value; + } + + cancellation_slot_type get_cancellation_slot() const noexcept + { + return bottom_of_stack_.frame_->cancellation_state_.slot(); + } + + // Launch a new thread of execution. + void launch() + { + bottom_of_stack_.frame_->top_of_stack_->attach_thread(this); + pump(); + } + +protected: + template <typename> friend class awaitable_frame_base; + + // Repeatedly resume the top stack frame until the stack is empty or until it + // has been transferred to another resumable_thread object. + void pump() + { + do + bottom_of_stack_.frame_->top_of_stack_->resume(); + while (bottom_of_stack_.frame_ && bottom_of_stack_.frame_->top_of_stack_); + + if (bottom_of_stack_.frame_) + { + awaitable<awaitable_thread_entry_point, Executor> a( + std::move(bottom_of_stack_)); + a.frame_->rethrow_exception(); + } + } + + awaitable<awaitable_thread_entry_point, Executor> bottom_of_stack_; +}; + +template <typename Signature, typename Executor> +class awaitable_async_op_handler; + +template <typename R, typename Executor> +class awaitable_async_op_handler<R(), Executor> + : public awaitable_thread<Executor> +{ +public: + struct result_type {}; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type&) + : awaitable_thread<Executor>(std::move(*h)) + { + } + + void operator()() + { + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static void resume(result_type&) + { + } +}; + +template <typename R, typename Executor> +class awaitable_async_op_handler<R(asio::error_code), Executor> + : public awaitable_thread<Executor> +{ +public: + typedef asio::error_code* result_type; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + void operator()(asio::error_code ec) + { + result_ = &ec; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static void resume(result_type& result) + { + throw_error(*result); + } + +private: + result_type& result_; +}; + +template <typename R, typename Executor> +class awaitable_async_op_handler<R(std::exception_ptr), Executor> + : public awaitable_thread<Executor> +{ +public: + typedef std::exception_ptr* result_type; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + void operator()(std::exception_ptr ex) + { + result_ = &ex; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static void resume(result_type& result) + { + if (*result) + { + std::exception_ptr ex = std::exchange(*result, nullptr); + std::rethrow_exception(ex); + } + } + +private: + result_type& result_; +}; + +template <typename R, typename T, typename Executor> +class awaitable_async_op_handler<R(T), Executor> + : public awaitable_thread<Executor> +{ +public: + typedef T* result_type; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + void operator()(T result) + { + result_ = &result; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static T resume(result_type& result) + { + return std::move(*result); + } + +private: + result_type& result_; +}; + +template <typename R, typename T, typename Executor> +class awaitable_async_op_handler<R(asio::error_code, T), Executor> + : public awaitable_thread<Executor> +{ +public: + struct result_type + { + asio::error_code* ec_; + T* value_; + }; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + void operator()(asio::error_code ec, T value) + { + result_.ec_ = &ec; + result_.value_ = &value; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static T resume(result_type& result) + { + throw_error(*result.ec_); + return std::move(*result.value_); + } + +private: + result_type& result_; +}; + +template <typename R, typename T, typename Executor> +class awaitable_async_op_handler<R(std::exception_ptr, T), Executor> + : public awaitable_thread<Executor> +{ +public: + struct result_type + { + std::exception_ptr* ex_; + T* value_; + }; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + void operator()(std::exception_ptr ex, T value) + { + result_.ex_ = &ex; + result_.value_ = &value; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static T resume(result_type& result) + { + if (*result.ex_) + { + std::exception_ptr ex = std::exchange(*result.ex_, nullptr); + std::rethrow_exception(ex); + } + return std::move(*result.value_); + } + +private: + result_type& result_; +}; + +template <typename R, typename... Ts, typename Executor> +class awaitable_async_op_handler<R(Ts...), Executor> + : public awaitable_thread<Executor> +{ +public: + typedef std::tuple<Ts...>* result_type; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + std::tuple<Ts...> result(std::forward<Args>(args)...); + result_ = &result; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static std::tuple<Ts...> resume(result_type& result) + { + return std::move(*result); + } + +private: + result_type& result_; +}; + +template <typename R, typename... Ts, typename Executor> +class awaitable_async_op_handler<R(asio::error_code, Ts...), Executor> + : public awaitable_thread<Executor> +{ +public: + struct result_type + { + asio::error_code* ec_; + std::tuple<Ts...>* value_; + }; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + template <typename... Args> + void operator()(asio::error_code ec, Args&&... args) + { + result_.ec_ = &ec; + std::tuple<Ts...> value(std::forward<Args>(args)...); + result_.value_ = &value; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static std::tuple<Ts...> resume(result_type& result) + { + throw_error(*result.ec_); + return std::move(*result.value_); + } + +private: + result_type& result_; +}; + +template <typename R, typename... Ts, typename Executor> +class awaitable_async_op_handler<R(std::exception_ptr, Ts...), Executor> + : public awaitable_thread<Executor> +{ +public: + struct result_type + { + std::exception_ptr* ex_; + std::tuple<Ts...>* value_; + }; + + awaitable_async_op_handler( + awaitable_thread<Executor>* h, result_type& result) + : awaitable_thread<Executor>(std::move(*h)), + result_(result) + { + } + + template <typename... Args> + void operator()(std::exception_ptr ex, Args&&... args) + { + result_.ex_ = &ex; + std::tuple<Ts...> value(std::forward<Args>(args)...); + result_.value_ = &value; + this->entry_point()->top_of_stack_->attach_thread(this); + this->entry_point()->top_of_stack_->clear_cancellation_slot(); + this->pump(); + } + + static std::tuple<Ts...> resume(result_type& result) + { + if (*result.ex_) + { + std::exception_ptr ex = std::exchange(*result.ex_, nullptr); + std::rethrow_exception(ex); + } + return std::move(*result.value_); + } + +private: + result_type& result_; +}; + +template <typename Signature, typename Op, typename Executor> +class awaitable_async_op +{ +public: + typedef awaitable_async_op_handler<Signature, Executor> handler_type; + + awaitable_async_op(Op&& o, awaitable_frame_base<Executor>* frame +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , const detail::source_location& location +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + ) + : op_(std::forward<Op>(o)), + frame_(frame), + result_() +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + , location_(location) +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + { + } + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<void>) + { + frame_->after_suspend( + [](void* arg) + { + awaitable_async_op* self = static_cast<awaitable_async_op*>(arg); +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + ASIO_HANDLER_LOCATION((self->location_.file_name(), + self->location_.line(), self->location_.function_name())); +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + std::forward<Op&&>(self->op_)( + handler_type(self->frame_->detach_thread(), self->result_)); + }, this); + } + + auto await_resume() + { + return handler_type::resume(result_); + } + +private: + Op&& op_; + awaitable_frame_base<Executor>* frame_; + typename handler_type::result_type result_; +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + detail::source_location location_; +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) +}; + +} // namespace detail +} // namespace asio + +#if !defined(GENERATING_DOCUMENTATION) +# if defined(ASIO_HAS_STD_COROUTINE) + +namespace std { + +template <typename T, typename Executor, typename... Args> +struct coroutine_traits<asio::awaitable<T, Executor>, Args...> +{ + typedef asio::detail::awaitable_frame<T, Executor> promise_type; +}; + +} // namespace std + +# else // defined(ASIO_HAS_STD_COROUTINE) + +namespace std { namespace experimental { + +template <typename T, typename Executor, typename... Args> +struct coroutine_traits<asio::awaitable<T, Executor>, Args...> +{ + typedef asio::detail::awaitable_frame<T, Executor> promise_type; +}; + +}} // namespace std::experimental + +# endif // defined(ASIO_HAS_STD_COROUTINE) +#endif // !defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_AWAITABLE_HPP diff --git a/3rdparty/asio/include/asio/impl/buffered_read_stream.hpp b/3rdparty/asio/include/asio/impl/buffered_read_stream.hpp index c1a2e145490..9a1d78b465e 100644 --- a/3rdparty/asio/include/asio/impl/buffered_read_stream.hpp +++ b/3rdparty/asio/include/asio/impl/buffered_read_stream.hpp @@ -2,7 +2,7 @@ // impl/buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,12 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/associator.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" +#include "asio/detail/type_traits.hpp" #include "asio/detail/push_options.hpp" @@ -65,11 +64,10 @@ namespace detail std::size_t previous_size, ReadHandler& handler) : storage_(storage), previous_size_(previous_size), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) buffered_fill_handler(const buffered_fill_handler& other) : storage_(other.storage_), previous_size_(other.previous_size_), @@ -80,16 +78,15 @@ namespace detail buffered_fill_handler(buffered_fill_handler&& other) : storage_(other.storage_), previous_size_(other.previous_size_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()(const asio::error_code& ec, const std::size_t bytes_transferred) { storage_.resize(previous_size_ + bytes_transferred); - handler_(ec, bytes_transferred); + static_cast<ReadHandler&&>(handler_)(ec, bytes_transferred); } //private: @@ -99,22 +96,6 @@ namespace detail }; template <typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - buffered_fill_handler<ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - buffered_fill_handler<ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename ReadHandler> inline bool asio_handler_is_continuation( buffered_fill_handler<ReadHandler>* this_handler) { @@ -122,78 +103,88 @@ namespace detail this_handler->handler_); } - template <typename Function, typename ReadHandler> - inline void asio_handler_invoke(Function& function, - buffered_fill_handler<ReadHandler>* this_handler) + template <typename Stream> + class initiate_async_buffered_fill { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename remove_reference_t< + Stream>::lowest_layer_type::executor_type executor_type; - template <typename Function, typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - buffered_fill_handler<ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_buffered_fill( + remove_reference_t<Stream>& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const noexcept + { + return next_layer_.lowest_layer().get_executor(); + } + + template <typename ReadHandler> + void operator()(ReadHandler&& handler, + buffered_stream_storage* storage) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + std::size_t previous_size = storage->size(); + storage->resize(storage->capacity()); + next_layer_.async_read_some( + buffer( + storage->data() + previous_size, + storage->size() - previous_size), + buffered_fill_handler<decay_t<ReadHandler>>( + *storage, previous_size, handler2.value)); + } + + private: + remove_reference_t<Stream>& next_layer_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename ReadHandler, typename Allocator> -struct associated_allocator< - detail::buffered_fill_handler<ReadHandler>, Allocator> +template <template <typename, typename> class Associator, + typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::buffered_fill_handler<ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get(const detail::buffered_fill_handler<ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::buffered_fill_handler<ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename ReadHandler, typename Executor> -struct associated_executor< - detail::buffered_fill_handler<ReadHandler>, Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - - static type get(const detail::buffered_fill_handler<ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get(const detail::buffered_fill_handler<ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> -template <typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -buffered_read_stream<Stream>::async_fill( - ASIO_MOVE_ARG(ReadHandler) handler) +template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler> +inline auto buffered_read_stream<Stream>::async_fill(ReadHandler&& handler) + -> decltype( + async_initiate<ReadHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_fill<Stream>>(), + handler, declval<detail::buffered_stream_storage*>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - std::size_t previous_size = storage_.size(); - storage_.resize(storage_.capacity()); - next_layer_.async_read_some( - buffer( - storage_.data() + previous_size, - storage_.size() - previous_size), - detail::buffered_fill_handler<ASIO_HANDLER_TYPE( - ReadHandler, void (asio::error_code, std::size_t))>( - storage_, previous_size, init.completion_handler)); - - return init.result.get(); + return async_initiate<ReadHandler, + void (asio::error_code, std::size_t)>( + detail::initiate_async_buffered_fill<Stream>(next_layer_), + handler, &storage_); } template <typename Stream> @@ -201,7 +192,8 @@ template <typename MutableBufferSequence> std::size_t buffered_read_stream<Stream>::read_some( const MutableBufferSequence& buffers) { - if (asio::buffer_size(buffers) == 0) + using asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.empty()) @@ -217,7 +209,8 @@ std::size_t buffered_read_stream<Stream>::read_some( { ec = asio::error_code(); - if (asio::buffer_size(buffers) == 0) + using asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.empty() && !this->fill(ec)) @@ -236,39 +229,37 @@ namespace detail const MutableBufferSequence& buffers, ReadHandler& handler) : storage_(storage), buffers_(buffers), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - buffered_read_some_handler(const buffered_read_some_handler& other) - : storage_(other.storage_), - buffers_(other.buffers_), - handler_(other.handler_) - { - } + buffered_read_some_handler(const buffered_read_some_handler& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(other.handler_) + { + } - buffered_read_some_handler(buffered_read_some_handler&& other) - : storage_(other.storage_), - buffers_(other.buffers_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) - { - } -#endif // defined(ASIO_HAS_MOVE) + buffered_read_some_handler(buffered_read_some_handler&& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(static_cast<ReadHandler&&>(other.handler_)) + { + } void operator()(const asio::error_code& ec, std::size_t) { if (ec || storage_.empty()) { const std::size_t length = 0; - handler_(ec, length); + static_cast<ReadHandler&&>(handler_)(ec, length); } else { const std::size_t bytes_copied = asio::buffer_copy( buffers_, storage_.data(), storage_.size()); storage_.consume(bytes_copied); - handler_(ec, bytes_copied); + static_cast<ReadHandler&&>(handler_)(ec, bytes_copied); } } @@ -279,24 +270,6 @@ namespace detail }; template <typename MutableBufferSequence, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - buffered_read_some_handler< - MutableBufferSequence, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename MutableBufferSequence, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - buffered_read_some_handler< - MutableBufferSequence, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename MutableBufferSequence, typename ReadHandler> inline bool asio_handler_is_continuation( buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) @@ -305,97 +278,102 @@ namespace detail this_handler->handler_); } - template <typename Function, typename MutableBufferSequence, - typename ReadHandler> - inline void asio_handler_invoke(Function& function, - buffered_read_some_handler< - MutableBufferSequence, ReadHandler>* this_handler) + template <typename Stream> + class initiate_async_buffered_read_some { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename remove_reference_t< + Stream>::lowest_layer_type::executor_type executor_type; - template <typename Function, typename MutableBufferSequence, - typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - buffered_read_some_handler< - MutableBufferSequence, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_buffered_read_some( + remove_reference_t<Stream>& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const noexcept + { + return next_layer_.lowest_layer().get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + buffered_stream_storage* storage, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + using asio::buffer_size; + non_const_lvalue<ReadHandler> handler2(handler); + if (buffer_size(buffers) == 0 || !storage->empty()) + { + next_layer_.async_read_some(ASIO_MUTABLE_BUFFER(0, 0), + buffered_read_some_handler<MutableBufferSequence, + decay_t<ReadHandler>>( + *storage, buffers, handler2.value)); + } + else + { + initiate_async_buffered_fill<Stream>(this->next_layer_)( + buffered_read_some_handler<MutableBufferSequence, + decay_t<ReadHandler>>( + *storage, buffers, handler2.value), + storage); + } + } + + private: + remove_reference_t<Stream>& next_layer_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename MutableBufferSequence, - typename ReadHandler, typename Allocator> -struct associated_allocator< +template <template <typename, typename> class Associator, + typename MutableBufferSequence, typename ReadHandler, + typename DefaultCandidate> +struct associator<Associator, detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, - Allocator> + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get( + static typename Associator<ReadHandler, DefaultCandidate>::type get( const detail::buffered_read_some_handler< - MutableBufferSequence, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + MutableBufferSequence, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename MutableBufferSequence, - typename ReadHandler, typename Executor> -struct associated_executor< - detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, - Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - - static type get( + static auto get( const detail::buffered_read_some_handler< MutableBufferSequence, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> -template <typename MutableBufferSequence, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -buffered_read_stream<Stream>::async_read_some( - const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) +template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadHandler> +inline auto buffered_read_stream<Stream>::async_read_some( + const MutableBufferSequence& buffers, ReadHandler&& handler) + -> decltype( + async_initiate<ReadHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_read_some<Stream>>(), + handler, declval<detail::buffered_stream_storage*>(), buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - if (asio::buffer_size(buffers) == 0 || !storage_.empty()) - { - next_layer_.async_read_some(ASIO_MUTABLE_BUFFER(0, 0), - detail::buffered_read_some_handler< - MutableBufferSequence, ASIO_HANDLER_TYPE( - ReadHandler, void (asio::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - else - { - this->async_fill(detail::buffered_read_some_handler< - MutableBufferSequence, ASIO_HANDLER_TYPE( - ReadHandler, void (asio::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - - return init.result.get(); + return async_initiate<ReadHandler, + void (asio::error_code, std::size_t)>( + detail::initiate_async_buffered_read_some<Stream>(next_layer_), + handler, &storage_, buffers); } template <typename Stream> diff --git a/3rdparty/asio/include/asio/impl/buffered_write_stream.hpp b/3rdparty/asio/include/asio/impl/buffered_write_stream.hpp index 4ce6e5ebf04..5bf58278ca6 100644 --- a/3rdparty/asio/include/asio/impl/buffered_write_stream.hpp +++ b/3rdparty/asio/include/asio/impl/buffered_write_stream.hpp @@ -2,7 +2,7 @@ // impl/buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/associator.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/push_options.hpp" @@ -54,11 +52,10 @@ namespace detail buffered_flush_handler(detail::buffered_stream_storage& storage, WriteHandler& handler) : storage_(storage), - handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + handler_(static_cast<WriteHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) buffered_flush_handler(const buffered_flush_handler& other) : storage_(other.storage_), handler_(other.handler_) @@ -67,16 +64,15 @@ namespace detail buffered_flush_handler(buffered_flush_handler&& other) : storage_(other.storage_), - handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + handler_(static_cast<WriteHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()(const asio::error_code& ec, const std::size_t bytes_written) { storage_.consume(bytes_written); - handler_(ec, bytes_written); + static_cast<WriteHandler&&>(handler_)(ec, bytes_written); } //private: @@ -85,22 +81,6 @@ namespace detail }; template <typename WriteHandler> - inline void* asio_handler_allocate(std::size_t size, - buffered_flush_handler<WriteHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename WriteHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - buffered_flush_handler<WriteHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename WriteHandler> inline bool asio_handler_is_continuation( buffered_flush_handler<WriteHandler>* this_handler) { @@ -108,73 +88,83 @@ namespace detail this_handler->handler_); } - template <typename Function, typename WriteHandler> - inline void asio_handler_invoke(Function& function, - buffered_flush_handler<WriteHandler>* this_handler) + template <typename Stream> + class initiate_async_buffered_flush { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename remove_reference_t< + Stream>::lowest_layer_type::executor_type executor_type; - template <typename Function, typename WriteHandler> - inline void asio_handler_invoke(const Function& function, - buffered_flush_handler<WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_buffered_flush( + remove_reference_t<Stream>& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const noexcept + { + return next_layer_.lowest_layer().get_executor(); + } + + template <typename WriteHandler> + void operator()(WriteHandler&& handler, + buffered_stream_storage* storage) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + async_write(next_layer_, buffer(storage->data(), storage->size()), + buffered_flush_handler<decay_t<WriteHandler>>( + *storage, handler2.value)); + } + + private: + remove_reference_t<Stream>& next_layer_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename WriteHandler, typename Allocator> -struct associated_allocator< - detail::buffered_flush_handler<WriteHandler>, Allocator> +template <template <typename, typename> class Associator, + typename WriteHandler, typename DefaultCandidate> +struct associator<Associator, + detail::buffered_flush_handler<WriteHandler>, + DefaultCandidate> + : Associator<WriteHandler, DefaultCandidate> { - typedef typename associated_allocator<WriteHandler, Allocator>::type type; - - static type get(const detail::buffered_flush_handler<WriteHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<WriteHandler, DefaultCandidate>::type get( + const detail::buffered_flush_handler<WriteHandler>& h) noexcept { - return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename WriteHandler, typename Executor> -struct associated_executor< - detail::buffered_flush_handler<WriteHandler>, Executor> -{ - typedef typename associated_executor<WriteHandler, Executor>::type type; - static type get(const detail::buffered_flush_handler<WriteHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get(const detail::buffered_flush_handler<WriteHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> -template <typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -buffered_write_stream<Stream>::async_flush( - ASIO_MOVE_ARG(WriteHandler) handler) +template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler> +inline auto buffered_write_stream<Stream>::async_flush(WriteHandler&& handler) + -> decltype( + async_initiate<WriteHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_flush<Stream>>(), + handler, declval<detail::buffered_stream_storage*>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - async_write(next_layer_, buffer(storage_.data(), storage_.size()), - detail::buffered_flush_handler<ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - storage_, init.completion_handler)); - - return init.result.get(); + return async_initiate<WriteHandler, + void (asio::error_code, std::size_t)>( + detail::initiate_async_buffered_flush<Stream>(next_layer_), + handler, &storage_); } template <typename Stream> @@ -182,7 +172,8 @@ template <typename ConstBufferSequence> std::size_t buffered_write_stream<Stream>::write_some( const ConstBufferSequence& buffers) { - if (asio::buffer_size(buffers) == 0) + using asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.size() == storage_.capacity()) @@ -198,7 +189,8 @@ std::size_t buffered_write_stream<Stream>::write_some( { ec = asio::error_code(); - if (asio::buffer_size(buffers) == 0) + using asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.size() == storage_.capacity() && !flush(ec)) @@ -217,44 +209,43 @@ namespace detail const ConstBufferSequence& buffers, WriteHandler& handler) : storage_(storage), buffers_(buffers), - handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + handler_(static_cast<WriteHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - buffered_write_some_handler(const buffered_write_some_handler& other) - : storage_(other.storage_), - buffers_(other.buffers_), - handler_(other.handler_) - { - } + buffered_write_some_handler(const buffered_write_some_handler& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(other.handler_) + { + } - buffered_write_some_handler(buffered_write_some_handler&& other) - : storage_(other.storage_), - buffers_(other.buffers_), - handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(ASIO_HAS_MOVE) + buffered_write_some_handler(buffered_write_some_handler&& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(static_cast<WriteHandler&&>(other.handler_)) + { + } void operator()(const asio::error_code& ec, std::size_t) { if (ec) { const std::size_t length = 0; - handler_(ec, length); + static_cast<WriteHandler&&>(handler_)(ec, length); } else { + using asio::buffer_size; std::size_t orig_size = storage_.size(); std::size_t space_avail = storage_.capacity() - orig_size; - std::size_t bytes_avail = asio::buffer_size(buffers_); + std::size_t bytes_avail = buffer_size(buffers_); std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail; storage_.resize(orig_size + length); const std::size_t bytes_copied = asio::buffer_copy( storage_.data() + orig_size, buffers_, length); - handler_(ec, bytes_copied); + static_cast<WriteHandler&&>(handler_)(ec, bytes_copied); } } @@ -265,24 +256,6 @@ namespace detail }; template <typename ConstBufferSequence, typename WriteHandler> - inline void* asio_handler_allocate(std::size_t size, - buffered_write_some_handler< - ConstBufferSequence, WriteHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename ConstBufferSequence, typename WriteHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - buffered_write_some_handler< - ConstBufferSequence, WriteHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename ConstBufferSequence, typename WriteHandler> inline bool asio_handler_is_continuation( buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) @@ -291,98 +264,102 @@ namespace detail this_handler->handler_); } - template <typename Function, typename ConstBufferSequence, - typename WriteHandler> - inline void asio_handler_invoke(Function& function, - buffered_write_some_handler< - ConstBufferSequence, WriteHandler>* this_handler) + template <typename Stream> + class initiate_async_buffered_write_some { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename remove_reference_t< + Stream>::lowest_layer_type::executor_type executor_type; - template <typename Function, typename ConstBufferSequence, - typename WriteHandler> - inline void asio_handler_invoke(const Function& function, - buffered_write_some_handler< - ConstBufferSequence, WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_buffered_write_some( + remove_reference_t<Stream>& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const noexcept + { + return next_layer_.lowest_layer().get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + buffered_stream_storage* storage, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + using asio::buffer_size; + non_const_lvalue<WriteHandler> handler2(handler); + if (buffer_size(buffers) == 0 || storage->size() < storage->capacity()) + { + next_layer_.async_write_some(ASIO_CONST_BUFFER(0, 0), + buffered_write_some_handler<ConstBufferSequence, + decay_t<WriteHandler>>( + *storage, buffers, handler2.value)); + } + else + { + initiate_async_buffered_flush<Stream>(this->next_layer_)( + buffered_write_some_handler<ConstBufferSequence, + decay_t<WriteHandler>>( + *storage, buffers, handler2.value), + storage); + } + } + + private: + remove_reference_t<Stream>& next_layer_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename ConstBufferSequence, - typename WriteHandler, typename Allocator> -struct associated_allocator< +template <template <typename, typename> class Associator, + typename ConstBufferSequence, typename WriteHandler, + typename DefaultCandidate> +struct associator<Associator, detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, - Allocator> + DefaultCandidate> + : Associator<WriteHandler, DefaultCandidate> { - typedef typename associated_allocator<WriteHandler, Allocator>::type type; - - static type get( + static typename Associator<WriteHandler, DefaultCandidate>::type get( const detail::buffered_write_some_handler< - ConstBufferSequence, WriteHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + ConstBufferSequence, WriteHandler>& h) noexcept { - return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename ConstBufferSequence, - typename WriteHandler, typename Executor> -struct associated_executor< - detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, - Executor> -{ - typedef typename associated_executor<WriteHandler, Executor>::type type; - - static type get( + static auto get( const detail::buffered_write_some_handler< ConstBufferSequence, WriteHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> -template <typename ConstBufferSequence, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -buffered_write_stream<Stream>::async_write_some( - const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) +template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteHandler> +inline auto buffered_write_stream<Stream>::async_write_some( + const ConstBufferSequence& buffers, WriteHandler&& handler) + -> decltype( + async_initiate<WriteHandler, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_buffered_write_some<Stream>>(), + handler, declval<detail::buffered_stream_storage*>(), buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - if (asio::buffer_size(buffers) == 0 - || storage_.size() < storage_.capacity()) - { - next_layer_.async_write_some(ASIO_CONST_BUFFER(0, 0), - detail::buffered_write_some_handler< - ConstBufferSequence, ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - else - { - this->async_flush(detail::buffered_write_some_handler< - ConstBufferSequence, ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - - return init.result.get(); + return async_initiate<WriteHandler, + void (asio::error_code, std::size_t)>( + detail::initiate_async_buffered_write_some<Stream>(next_layer_), + handler, &storage_, buffers); } template <typename Stream> @@ -390,9 +367,10 @@ template <typename ConstBufferSequence> std::size_t buffered_write_stream<Stream>::copy( const ConstBufferSequence& buffers) { + using asio::buffer_size; std::size_t orig_size = storage_.size(); std::size_t space_avail = storage_.capacity() - orig_size; - std::size_t bytes_avail = asio::buffer_size(buffers); + std::size_t bytes_avail = buffer_size(buffers); std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail; storage_.resize(orig_size + length); return asio::buffer_copy( diff --git a/3rdparty/asio/include/asio/impl/cancellation_signal.ipp b/3rdparty/asio/include/asio/impl/cancellation_signal.ipp new file mode 100644 index 00000000000..f63ab8de0f3 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/cancellation_signal.ipp @@ -0,0 +1,96 @@ +// +// impl/cancellation_signal.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_CANCELLATION_SIGNAL_IPP +#define ASIO_IMPL_CANCELLATION_SIGNAL_IPP + +#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/thread_context.hpp" +#include "asio/detail/thread_info_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +cancellation_signal::~cancellation_signal() +{ + if (handler_) + { + std::pair<void*, std::size_t> mem = handler_->destroy(); + detail::thread_info_base::deallocate( + detail::thread_info_base::cancellation_signal_tag(), + detail::thread_context::top_of_thread_call_stack(), + mem.first, mem.second); + } +} + +void cancellation_slot::clear() +{ + if (handler_ != 0 && *handler_ != 0) + { + std::pair<void*, std::size_t> mem = (*handler_)->destroy(); + detail::thread_info_base::deallocate( + detail::thread_info_base::cancellation_signal_tag(), + detail::thread_context::top_of_thread_call_stack(), + mem.first, mem.second); + *handler_ = 0; + } +} + +std::pair<void*, std::size_t> cancellation_slot::prepare_memory( + std::size_t size, std::size_t align) +{ + assert(handler_); + std::pair<void*, std::size_t> mem; + if (*handler_) + { + mem = (*handler_)->destroy(); + *handler_ = 0; + } + if (size > mem.second + || reinterpret_cast<std::size_t>(mem.first) % align != 0) + { + if (mem.first) + { + detail::thread_info_base::deallocate( + detail::thread_info_base::cancellation_signal_tag(), + detail::thread_context::top_of_thread_call_stack(), + mem.first, mem.second); + } + mem.first = detail::thread_info_base::allocate( + detail::thread_info_base::cancellation_signal_tag(), + detail::thread_context::top_of_thread_call_stack(), + size, align); + mem.second = size; + } + return mem; +} + +cancellation_slot::auto_delete_helper::~auto_delete_helper() +{ + if (mem.first) + { + detail::thread_info_base::deallocate( + detail::thread_info_base::cancellation_signal_tag(), + detail::thread_context::top_of_thread_call_stack(), + mem.first, mem.second); + } +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_CANCELLATION_SIGNAL_IPP diff --git a/3rdparty/asio/include/asio/impl/co_spawn.hpp b/3rdparty/asio/include/asio/impl/co_spawn.hpp new file mode 100644 index 00000000000..3eba7d86db8 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/co_spawn.hpp @@ -0,0 +1,449 @@ +// +// impl/co_spawn.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_CO_SPAWN_HPP +#define ASIO_IMPL_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_cancellation_slot.hpp" +#include "asio/awaitable.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/dispatch.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/post.hpp" +#include "asio/prefer.hpp" +#include "asio/use_awaitable.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Executor, typename = void> +class co_spawn_work_guard +{ +public: + typedef decay_t< + prefer_result_t<Executor, + execution::outstanding_work_t::tracked_t + > + > executor_type; + + co_spawn_work_guard(const Executor& ex) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + executor_type get_executor() const noexcept + { + return executor_; + } + +private: + executor_type executor_; +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor> +struct co_spawn_work_guard<Executor, + enable_if_t< + !execution::is_executor<Executor>::value + >> : executor_work_guard<Executor> +{ + co_spawn_work_guard(const Executor& ex) + : executor_work_guard<Executor>(ex) + { + } +}; + +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Handler, typename Executor, + typename Function, typename = void> +struct co_spawn_state +{ + template <typename H, typename F> + co_spawn_state(H&& h, const Executor& ex, F&& f) + : handler(std::forward<H>(h)), + spawn_work(ex), + handler_work(asio::get_associated_executor(handler, ex)), + function(std::forward<F>(f)) + { + } + + Handler handler; + co_spawn_work_guard<Executor> spawn_work; + co_spawn_work_guard<associated_executor_t<Handler, Executor>> handler_work; + Function function; +}; + +template <typename Handler, typename Executor, typename Function> +struct co_spawn_state<Handler, Executor, Function, + enable_if_t< + is_same< + typename associated_executor<Handler, + Executor>::asio_associated_executor_is_unspecialised, + void + >::value + >> +{ + template <typename H, typename F> + co_spawn_state(H&& h, const Executor& ex, F&& f) + : handler(std::forward<H>(h)), + handler_work(ex), + function(std::forward<F>(f)) + { + } + + Handler handler; + co_spawn_work_guard<Executor> handler_work; + Function function; +}; + +struct co_spawn_dispatch +{ + template <typename CompletionToken> + auto operator()(CompletionToken&& token) const + -> decltype(asio::dispatch(std::forward<CompletionToken>(token))) + { + return asio::dispatch(std::forward<CompletionToken>(token)); + } +}; + +struct co_spawn_post +{ + template <typename CompletionToken> + auto operator()(CompletionToken&& token) const + -> decltype(asio::post(std::forward<CompletionToken>(token))) + { + return asio::post(std::forward<CompletionToken>(token)); + } +}; + +template <typename T, typename Handler, typename Executor, typename Function> +awaitable<awaitable_thread_entry_point, Executor> co_spawn_entry_point( + awaitable<T, Executor>*, co_spawn_state<Handler, Executor, Function> s) +{ + (void) co_await co_spawn_dispatch{}; + + (co_await awaitable_thread_has_context_switched{}) = false; + std::exception_ptr e = nullptr; + bool done = false; + try + { + T t = co_await s.function(); + + done = true; + + bool switched = (co_await awaitable_thread_has_context_switched{}); + if (!switched) + { + co_await this_coro::throw_if_cancelled(false); + (void) co_await co_spawn_post(); + } + + (dispatch)(s.handler_work.get_executor(), + [handler = std::move(s.handler), t = std::move(t)]() mutable + { + std::move(handler)(std::exception_ptr(), std::move(t)); + }); + + co_return; + } + catch (...) + { + if (done) + throw; + + e = std::current_exception(); + } + + bool switched = (co_await awaitable_thread_has_context_switched{}); + if (!switched) + { + co_await this_coro::throw_if_cancelled(false); + (void) co_await co_spawn_post(); + } + + (dispatch)(s.handler_work.get_executor(), + [handler = std::move(s.handler), e]() mutable + { + std::move(handler)(e, T()); + }); +} + +template <typename Handler, typename Executor, typename Function> +awaitable<awaitable_thread_entry_point, Executor> co_spawn_entry_point( + awaitable<void, Executor>*, co_spawn_state<Handler, Executor, Function> s) +{ + (void) co_await co_spawn_dispatch{}; + + (co_await awaitable_thread_has_context_switched{}) = false; + std::exception_ptr e = nullptr; + try + { + co_await s.function(); + } + catch (...) + { + e = std::current_exception(); + } + + bool switched = (co_await awaitable_thread_has_context_switched{}); + if (!switched) + { + co_await this_coro::throw_if_cancelled(false); + (void) co_await co_spawn_post(); + } + + (dispatch)(s.handler_work.get_executor(), + [handler = std::move(s.handler), e]() mutable + { + std::move(handler)(e); + }); +} + +template <typename T, typename Executor> +class awaitable_as_function +{ +public: + explicit awaitable_as_function(awaitable<T, Executor>&& a) + : awaitable_(std::move(a)) + { + } + + awaitable<T, Executor> operator()() + { + return std::move(awaitable_); + } + +private: + awaitable<T, Executor> awaitable_; +}; + +template <typename Handler, typename Executor, typename = void> +class co_spawn_cancellation_handler +{ +public: + co_spawn_cancellation_handler(const Handler&, const Executor& ex) + : signal_(detail::allocate_shared<cancellation_signal>( + detail::recycling_allocator<cancellation_signal, + detail::thread_info_base::cancellation_signal_tag>())), + ex_(ex) + { + } + + cancellation_slot slot() + { + return signal_->slot(); + } + + void operator()(cancellation_type_t type) + { + shared_ptr<cancellation_signal> sig = signal_; + asio::dispatch(ex_, [sig, type]{ sig->emit(type); }); + } + +private: + shared_ptr<cancellation_signal> signal_; + Executor ex_; +}; + +template <typename Handler, typename Executor> +class co_spawn_cancellation_handler<Handler, Executor, + enable_if_t< + is_same< + typename associated_executor<Handler, + Executor>::asio_associated_executor_is_unspecialised, + void + >::value + >> +{ +public: + co_spawn_cancellation_handler(const Handler&, const Executor&) + { + } + + cancellation_slot slot() + { + return signal_.slot(); + } + + void operator()(cancellation_type_t type) + { + signal_.emit(type); + } + +private: + cancellation_signal signal_; +}; + +template <typename Executor> +class initiate_co_spawn +{ +public: + typedef Executor executor_type; + + template <typename OtherExecutor> + explicit initiate_co_spawn(const OtherExecutor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const noexcept + { + return ex_; + } + + template <typename Handler, typename F> + void operator()(Handler&& handler, F&& f) const + { + typedef result_of_t<F()> awaitable_type; + typedef decay_t<Handler> handler_type; + typedef decay_t<F> function_type; + typedef co_spawn_cancellation_handler< + handler_type, Executor> cancel_handler_type; + + auto slot = asio::get_associated_cancellation_slot(handler); + cancel_handler_type* cancel_handler = slot.is_connected() + ? &slot.template emplace<cancel_handler_type>(handler, ex_) + : nullptr; + + cancellation_slot proxy_slot( + cancel_handler + ? cancel_handler->slot() + : cancellation_slot()); + + cancellation_state cancel_state(proxy_slot); + + auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr), + co_spawn_state<handler_type, Executor, function_type>( + std::forward<Handler>(handler), ex_, std::forward<F>(f))); + awaitable_handler<executor_type, void>(std::move(a), + ex_, proxy_slot, cancel_state).launch(); + } + +private: + Executor ex_; +}; + +} // namespace detail + +template <typename Executor, typename T, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr, T)) CompletionToken> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(const Executor& ex, + awaitable<T, AwaitableExecutor> a, CompletionToken&& token, + constraint_t< + (is_executor<Executor>::value || execution::is_executor<Executor>::value) + && is_convertible<Executor, AwaitableExecutor>::value + >) +{ + return async_initiate<CompletionToken, void(std::exception_ptr, T)>( + detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)), + token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a))); +} + +template <typename Executor, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr)) CompletionToken> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(const Executor& ex, + awaitable<void, AwaitableExecutor> a, CompletionToken&& token, + constraint_t< + (is_executor<Executor>::value || execution::is_executor<Executor>::value) + && is_convertible<Executor, AwaitableExecutor>::value + >) +{ + return async_initiate<CompletionToken, void(std::exception_ptr)>( + detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)), + token, detail::awaitable_as_function< + void, AwaitableExecutor>(std::move(a))); +} + +template <typename ExecutionContext, typename T, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr, T)) CompletionToken> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(ExecutionContext& ctx, + awaitable<T, AwaitableExecutor> a, CompletionToken&& token, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + && is_convertible<typename ExecutionContext::executor_type, + AwaitableExecutor>::value + >) +{ + return (co_spawn)(ctx.get_executor(), std::move(a), + std::forward<CompletionToken>(token)); +} + +template <typename ExecutionContext, typename AwaitableExecutor, + ASIO_COMPLETION_TOKEN_FOR( + void(std::exception_ptr)) CompletionToken> +inline ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(ExecutionContext& ctx, + awaitable<void, AwaitableExecutor> a, CompletionToken&& token, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + && is_convertible<typename ExecutionContext::executor_type, + AwaitableExecutor>::value + >) +{ + return (co_spawn)(ctx.get_executor(), std::move(a), + std::forward<CompletionToken>(token)); +} + +template <typename Executor, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< + result_of_t<F()>>::type) CompletionToken> +inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature<result_of_t<F()>>::type) +co_spawn(const Executor& ex, F&& f, CompletionToken&& token, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + >) +{ + return async_initiate<CompletionToken, + typename detail::awaitable_signature<result_of_t<F()>>::type>( + detail::initiate_co_spawn< + typename result_of_t<F()>::executor_type>(ex), + token, std::forward<F>(f)); +} + +template <typename ExecutionContext, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< + result_of_t<F()>>::type) CompletionToken> +inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature<result_of_t<F()>>::type) +co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + >) +{ + return (co_spawn)(ctx.get_executor(), std::forward<F>(f), + std::forward<CompletionToken>(token)); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_CO_SPAWN_HPP diff --git a/3rdparty/asio/include/asio/impl/connect.hpp b/3rdparty/asio/include/asio/impl/connect.hpp index 2ab72f6d726..ac74ae0a782 100644 --- a/3rdparty/asio/include/asio/impl/connect.hpp +++ b/3rdparty/asio/include/asio/impl/connect.hpp @@ -2,7 +2,7 @@ // impl/connect.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,14 +16,15 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <algorithm> -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" +#include "asio/associator.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" #include "asio/detail/bind_handler.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_tracking.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" #include "asio/error.hpp" #include "asio/post.hpp" @@ -41,14 +42,69 @@ namespace detail return true; } }; + + template <typename Protocol, typename Iterator> + inline typename Protocol::endpoint deref_connect_result( + Iterator iter, asio::error_code& ec) + { + return ec ? typename Protocol::endpoint() : *iter; + } + + template <typename T, typename Iterator> + struct legacy_connect_condition_helper : T + { + typedef char (*fallback_func_type)(...); + operator fallback_func_type() const; + }; + + template <typename R, typename Arg1, typename Arg2, typename Iterator> + struct legacy_connect_condition_helper<R (*)(Arg1, Arg2), Iterator> + { + R operator()(Arg1, Arg2) const; + char operator()(...) const; + }; + + template <typename T, typename Iterator> + struct is_legacy_connect_condition + { + static char asio_connect_condition_check(char); + static char (&asio_connect_condition_check(Iterator))[2]; + + static const bool value = + sizeof(asio_connect_condition_check( + (declval<legacy_connect_condition_helper<T, Iterator>>())( + declval<const asio::error_code>(), + declval<const Iterator>()))) != 1; + }; + + template <typename ConnectCondition, typename Iterator> + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const asio::error_code& ec, Iterator next, Iterator end, + enable_if_t<is_legacy_connect_condition< + ConnectCondition, Iterator>::value>* = 0) + { + if (next != end) + return connect_condition(ec, next); + return end; + } + + template <typename ConnectCondition, typename Iterator> + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const asio::error_code& ec, Iterator next, Iterator end, + enable_if_t<!is_legacy_connect_condition< + ConnectCondition, Iterator>::value>* = 0) + { + for (;next != end; ++next) + if (connect_condition(ec, *next)) + return next; + return end; + } } -template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename EndpointSequence> +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type*) + constraint_t<is_endpoint_sequence<EndpointSequence>::value>) { asio::error_code ec; typename Protocol::endpoint result = connect(s, endpoints, ec); @@ -56,23 +112,20 @@ typename Protocol::endpoint connect( return result; } -template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename EndpointSequence> +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, asio::error_code& ec, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type*) + constraint_t<is_endpoint_sequence<EndpointSequence>::value>) { - typename EndpointSequence::iterator iter = connect( - s, endpoints.begin(), endpoints.end(), - detail::default_connect_condition(), ec); - return ec ? typename Protocol::endpoint() : *iter; + return detail::deref_connect_result<Protocol>( + connect(s, endpoints.begin(), endpoints.end(), + detail::default_connect_condition(), ec), ec); } #if !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, + constraint_t<!is_endpoint_sequence<Iterator>::value>) { asio::error_code ec; Iterator result = connect(s, begin, ec); @@ -80,17 +133,17 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, return result; } -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -inline Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, asio::error_code& ec, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) + constraint_t<!is_endpoint_sequence<Iterator>::value>) { return connect(s, begin, Iterator(), detail::default_connect_condition(), ec); } #endif // !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end) { asio::error_code ec; @@ -99,20 +152,18 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, return result; } -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> -inline Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, asio::error_code& ec) { return connect(s, begin, end, detail::default_connect_condition(), ec); } -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type*) + constraint_t<is_endpoint_sequence<EndpointSequence>::value>) { asio::error_code ec; typename Protocol::endpoint result = connect( @@ -121,26 +172,24 @@ typename Protocol::endpoint connect( return result; } -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition> -typename Protocol::endpoint connect( - basic_socket<Protocol ASIO_SVC_TARG>& s, +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, asio::error_code& ec, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type*) + constraint_t<is_endpoint_sequence<EndpointSequence>::value>) { - typename EndpointSequence::iterator iter = connect( - s, endpoints.begin(), endpoints.end(), connect_condition, ec); - return ec ? typename Protocol::endpoint() : *iter; + return detail::deref_connect_result<Protocol>( + connect(s, endpoints.begin(), endpoints.end(), + connect_condition, ec), ec); } #if !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) + constraint_t<!is_endpoint_sequence<Iterator>::value>) { asio::error_code ec; Iterator result = connect(s, begin, connect_condition, ec); @@ -148,21 +197,21 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, return result; } -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -inline Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, asio::error_code& ec, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) + constraint_t<!is_endpoint_sequence<Iterator>::value>) { return connect(s, begin, Iterator(), connect_condition, ec); } #endif // !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, ConnectCondition connect_condition) +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, + Iterator end, ConnectCondition connect_condition) { asio::error_code ec; Iterator result = connect(s, begin, end, connect_condition, ec); @@ -170,23 +219,26 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, return result; } -template <typename Protocol ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, ConnectCondition connect_condition, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, + Iterator end, ConnectCondition connect_condition, asio::error_code& ec) { ec = asio::error_code(); for (Iterator iter = begin; iter != end; ++iter) { - if (connect_condition(ec, iter)) + iter = (detail::call_connect_condition(connect_condition, ec, iter, end)); + if (iter != end) { s.close(ec); s.connect(*iter, ec); if (!ec) return iter; } + else + break; } if (!ec) @@ -208,11 +260,11 @@ namespace detail { } - template <typename Endpoint> - bool check_condition(const asio::error_code& ec, - const Endpoint& endpoint) + template <typename Iterator> + void check_condition(const asio::error_code& ec, + Iterator& iter, Iterator& end) { - return connect_condition_(ec, endpoint); + iter = detail::call_connect_condition(connect_condition_, ec, iter, end); } private: @@ -229,35 +281,37 @@ namespace detail { } - template <typename Endpoint> - bool check_condition(const asio::error_code&, const Endpoint&) + template <typename Iterator> + void check_condition(const asio::error_code&, Iterator&, Iterator&) { - return true; } }; - template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> - class range_connect_op : base_from_connect_condition<ConnectCondition> + template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> + class range_connect_op + : public base_from_cancellation_state<RangeConnectHandler>, + base_from_connect_condition<ConnectCondition> { public: - range_connect_op(basic_socket<Protocol ASIO_SVC_TARG>& sock, + range_connect_op(basic_socket<Protocol, Executor>& sock, const EndpointSequence& endpoints, const ConnectCondition& connect_condition, RangeConnectHandler& handler) - : base_from_connect_condition<ConnectCondition>(connect_condition), + : base_from_cancellation_state<RangeConnectHandler>( + handler, enable_partial_cancellation()), + base_from_connect_condition<ConnectCondition>(connect_condition), socket_(sock), endpoints_(endpoints), index_(0), start_(0), - handler_(ASIO_MOVE_CAST(RangeConnectHandler)(handler)) + handler_(static_cast<RangeConnectHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) range_connect_op(const range_connect_op& other) - : base_from_connect_condition<ConnectCondition>(other), + : base_from_cancellation_state<RangeConnectHandler>(other), + base_from_connect_condition<ConnectCondition>(other), socket_(other.socket_), endpoints_(other.endpoints_), index_(other.index_), @@ -267,49 +321,61 @@ namespace detail } range_connect_op(range_connect_op&& other) - : base_from_connect_condition<ConnectCondition>(other), + : base_from_cancellation_state<RangeConnectHandler>( + static_cast<base_from_cancellation_state<RangeConnectHandler>&&>( + other)), + base_from_connect_condition<ConnectCondition>(other), socket_(other.socket_), endpoints_(other.endpoints_), index_(other.index_), start_(other.start_), - handler_(ASIO_MOVE_CAST(RangeConnectHandler)(other.handler_)) + handler_(static_cast<RangeConnectHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()(asio::error_code ec, int start = 0) { - typename EndpointSequence::iterator iter = endpoints_.begin(); + this->process(ec, start, + const_cast<const EndpointSequence&>(endpoints_).begin(), + const_cast<const EndpointSequence&>(endpoints_).end()); + } + + //private: + template <typename Iterator> + void process(asio::error_code ec, + int start, Iterator begin, Iterator end) + { + Iterator iter = begin; std::advance(iter, index_); - typename EndpointSequence::iterator end = endpoints_.end(); switch (start_ = start) { case 1: for (;;) { - for (; iter != end; ++iter, ++index_) - if (this->check_condition(ec, *iter)) - break; + this->check_condition(ec, iter, end); + index_ = std::distance(begin, iter); if (iter != end) { socket_.close(ec); + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); socket_.async_connect(*iter, - ASIO_MOVE_CAST(range_connect_op)(*this)); + static_cast<range_connect_op&&>(*this)); return; } if (start) { ec = asio::error::not_found; + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); asio::post(socket_.get_executor(), detail::bind_handler( - ASIO_MOVE_CAST(range_connect_op)(*this), ec)); + static_cast<range_connect_op&&>(*this), ec)); return; } - default: + /* fall-through */ default: if (iter == end) break; @@ -323,100 +389,103 @@ namespace detail if (!ec) break; + if (this->cancelled() != cancellation_type::none) + { + ec = asio::error::operation_aborted; + break; + } + ++iter; ++index_; } - handler_(static_cast<const asio::error_code&>(ec), + static_cast<RangeConnectHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), static_cast<const typename Protocol::endpoint&>( ec || iter == end ? typename Protocol::endpoint() : *iter)); } } - //private: - basic_socket<Protocol ASIO_SVC_TARG>& socket_; + basic_socket<Protocol, Executor>& socket_; EndpointSequence endpoints_; std::size_t index_; int start_; RangeConnectHandler handler_; }; - template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> - inline void* asio_handler_allocate(std::size_t size, - range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, - ConnectCondition, RangeConnectHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, - ConnectCondition, RangeConnectHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> + template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> inline bool asio_handler_is_continuation( - range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { return asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename Protocol - ASIO_SVC_TPARAM, typename EndpointSequence, - typename ConnectCondition, typename RangeConnectHandler> - inline void asio_handler_invoke(Function& function, - range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, - ConnectCondition, RangeConnectHandler>* this_handler) + template <typename Protocol, typename Executor> + class initiate_async_range_connect { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef Executor executor_type; - template <typename Function, typename Protocol - ASIO_SVC_TPARAM, typename EndpointSequence, - typename ConnectCondition, typename RangeConnectHandler> - inline void asio_handler_invoke(const Function& function, - range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, - ConnectCondition, RangeConnectHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s) + : socket_(s) + { + } + + executor_type get_executor() const noexcept + { + return socket_.get_executor(); + } + + template <typename RangeConnectHandler, + typename EndpointSequence, typename ConnectCondition> + void operator()(RangeConnectHandler&& handler, + const EndpointSequence& endpoints, + const ConnectCondition& connect_condition) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for an + // RangeConnectHandler. + ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler, + handler, typename Protocol::endpoint) type_check; + + non_const_lvalue<RangeConnectHandler> handler2(handler); + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, + decay_t<RangeConnectHandler>>(socket_, endpoints, + connect_condition, handler2.value)(asio::error_code(), 1); + } + + private: + basic_socket<Protocol, Executor>& socket_; + }; - template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> - class iterator_connect_op : base_from_connect_condition<ConnectCondition> + class iterator_connect_op + : public base_from_cancellation_state<IteratorConnectHandler>, + base_from_connect_condition<ConnectCondition> { public: - iterator_connect_op(basic_socket<Protocol ASIO_SVC_TARG>& sock, + iterator_connect_op(basic_socket<Protocol, Executor>& sock, const Iterator& begin, const Iterator& end, const ConnectCondition& connect_condition, IteratorConnectHandler& handler) - : base_from_connect_condition<ConnectCondition>(connect_condition), + : base_from_cancellation_state<IteratorConnectHandler>( + handler, enable_partial_cancellation()), + base_from_connect_condition<ConnectCondition>(connect_condition), socket_(sock), iter_(begin), end_(end), start_(0), - handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(handler)) + handler_(static_cast<IteratorConnectHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) iterator_connect_op(const iterator_connect_op& other) - : base_from_connect_condition<ConnectCondition>(other), + : base_from_cancellation_state<IteratorConnectHandler>(other), + base_from_connect_condition<ConnectCondition>(other), socket_(other.socket_), iter_(other.iter_), end_(other.end_), @@ -426,15 +495,17 @@ namespace detail } iterator_connect_op(iterator_connect_op&& other) - : base_from_connect_condition<ConnectCondition>(other), + : base_from_cancellation_state<IteratorConnectHandler>( + static_cast<base_from_cancellation_state<IteratorConnectHandler>&&>( + other)), + base_from_connect_condition<ConnectCondition>(other), socket_(other.socket_), iter_(other.iter_), end_(other.end_), start_(other.start_), - handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(other.handler_)) + handler_(static_cast<IteratorConnectHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()(asio::error_code ec, int start = 0) { @@ -443,28 +514,28 @@ namespace detail case 1: for (;;) { - for (; iter_ != end_; ++iter_) - if (this->check_condition(ec, *iter_)) - break; + this->check_condition(ec, iter_, end_); if (iter_ != end_) { socket_.close(ec); + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); socket_.async_connect(*iter_, - ASIO_MOVE_CAST(iterator_connect_op)(*this)); + static_cast<iterator_connect_op&&>(*this)); return; } if (start) { ec = asio::error::not_found; + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); asio::post(socket_.get_executor(), detail::bind_handler( - ASIO_MOVE_CAST(iterator_connect_op)(*this), ec)); + static_cast<iterator_connect_op&&>(*this), ec)); return; } - default: + /* fall-through */ default: if (iter_ == end_) break; @@ -478,323 +549,257 @@ namespace detail if (!ec) break; + if (this->cancelled() != cancellation_type::none) + { + ec = asio::error::operation_aborted; + break; + } + ++iter_; } - handler_(static_cast<const asio::error_code&>(ec), + static_cast<IteratorConnectHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), static_cast<const Iterator&>(iter_)); } } //private: - basic_socket<Protocol ASIO_SVC_TARG>& socket_; + basic_socket<Protocol, Executor>& socket_; Iterator iter_; Iterator end_; int start_; IteratorConnectHandler handler_; }; - template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> - inline void* asio_handler_allocate(std::size_t size, - iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline bool asio_handler_is_continuation( - iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { return asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename Protocol - ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> - inline void asio_handler_invoke(Function& function, - iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>* this_handler) + template <typename Protocol, typename Executor> + class initiate_async_iterator_connect { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef Executor executor_type; - template <typename Function, typename Protocol - ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> - inline void asio_handler_invoke(const Function& function, - iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_iterator_connect( + basic_socket<Protocol, Executor>& s) + : socket_(s) + { + } + + executor_type get_executor() const noexcept + { + return socket_.get_executor(); + } + + template <typename IteratorConnectHandler, + typename Iterator, typename ConnectCondition> + void operator()(IteratorConnectHandler&& handler, + Iterator begin, Iterator end, + const ConnectCondition& connect_condition) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for an + // IteratorConnectHandler. + ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; + + non_const_lvalue<IteratorConnectHandler> handler2(handler); + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, + decay_t<IteratorConnectHandler>>(socket_, begin, end, + connect_condition, handler2.value)(asio::error_code(), 1); + } + + private: + basic_socket<Protocol, Executor>& socket_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler, typename Allocator> -struct associated_allocator< - detail::range_connect_op<Protocol ASIO_SVC_TARG, +template <template <typename, typename> class Associator, + typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler, + typename DefaultCandidate> +struct associator<Associator, + detail::range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>, - Allocator> + DefaultCandidate> + : Associator<RangeConnectHandler, DefaultCandidate> { - typedef typename associated_allocator< - RangeConnectHandler, Allocator>::type type; - - static type get( - const detail::range_connect_op<Protocol ASIO_SVC_TARG, - EndpointSequence, ConnectCondition, RangeConnectHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<RangeConnectHandler, DefaultCandidate>::type get( + const detail::range_connect_op<Protocol, Executor, EndpointSequence, + ConnectCondition, RangeConnectHandler>& h) noexcept { - return associated_allocator<RangeConnectHandler, - Allocator>::get(h.handler_, a); + return Associator<RangeConnectHandler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler, typename Executor> -struct associated_executor< - detail::range_connect_op<Protocol ASIO_SVC_TARG, - EndpointSequence, ConnectCondition, RangeConnectHandler>, - Executor> -{ - typedef typename associated_executor< - RangeConnectHandler, Executor>::type type; - static type get( - const detail::range_connect_op<Protocol ASIO_SVC_TARG, + static auto get( + const detail::range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype( + Associator<RangeConnectHandler, DefaultCandidate>::get( + h.handler_, c)) { - return associated_executor<RangeConnectHandler, - Executor>::get(h.handler_, ex); + return Associator<RangeConnectHandler, DefaultCandidate>::get( + h.handler_, c); } }; -template <typename Protocol ASIO_SVC_TPARAM, - typename Iterator, typename ConnectCondition, - typename IteratorConnectHandler, typename Allocator> -struct associated_allocator< - detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>, - Allocator> +template <template <typename, typename> class Associator, + typename Protocol, typename Executor, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler, + typename DefaultCandidate> +struct associator<Associator, + detail::iterator_connect_op<Protocol, Executor, + Iterator, ConnectCondition, IteratorConnectHandler>, + DefaultCandidate> + : Associator<IteratorConnectHandler, DefaultCandidate> { - typedef typename associated_allocator< - IteratorConnectHandler, Allocator>::type type; - - static type get( - const detail::iterator_connect_op<Protocol ASIO_SVC_TARG, - Iterator, ConnectCondition, IteratorConnectHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<IteratorConnectHandler, DefaultCandidate>::type + get(const detail::iterator_connect_op<Protocol, Executor, Iterator, + ConnectCondition, IteratorConnectHandler>& h) noexcept { - return associated_allocator<IteratorConnectHandler, - Allocator>::get(h.handler_, a); + return Associator<IteratorConnectHandler, DefaultCandidate>::get( + h.handler_); } -}; -template <typename Protocol ASIO_SVC_TPARAM, - typename Iterator, typename ConnectCondition, - typename IteratorConnectHandler, typename Executor> -struct associated_executor< - detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>, - Executor> -{ - typedef typename associated_executor< - IteratorConnectHandler, Executor>::type type; - - static type get( - const detail::iterator_connect_op<Protocol ASIO_SVC_TARG, + static auto get( + const detail::iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype( + Associator<IteratorConnectHandler, DefaultCandidate>::get( + h.handler_, c)) { - return associated_executor<IteratorConnectHandler, - Executor>::get(h.handler_, ex); + return Associator<IteratorConnectHandler, DefaultCandidate>::get( + h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename Protocol ASIO_SVC_TPARAM, - typename EndpointSequence, typename RangeConnectHandler> -inline ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - const EndpointSequence& endpoints, - ASIO_MOVE_ARG(RangeConnectHandler) handler, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type*) +template <typename Protocol, typename Executor, typename EndpointSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::endpoint)) RangeConnectToken> +inline auto async_connect(basic_socket<Protocol, Executor>& s, + const EndpointSequence& endpoints, RangeConnectToken&& token, + constraint_t<is_endpoint_sequence<EndpointSequence>::value>) + -> decltype( + async_initiate<RangeConnectToken, + void (asio::error_code, typename Protocol::endpoint)>( + declval<detail::initiate_async_range_connect<Protocol, Executor>>(), + token, endpoints, declval<detail::default_connect_condition>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a RangeConnectHandler. - ASIO_RANGE_CONNECT_HANDLER_CHECK( - RangeConnectHandler, handler, typename Protocol::endpoint) type_check; - - async_completion<RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint)> - init(handler); - - detail::range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, - detail::default_connect_condition, - ASIO_HANDLER_TYPE(RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint))>(s, - endpoints, detail::default_connect_condition(), - init.completion_handler)(asio::error_code(), 1); - - return init.result.get(); + return async_initiate<RangeConnectToken, + void (asio::error_code, typename Protocol::endpoint)>( + detail::initiate_async_range_connect<Protocol, Executor>(s), + token, endpoints, detail::default_connect_condition()); } #if !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, - typename Iterator, typename IteratorConnectHandler> -inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - Iterator begin, ASIO_MOVE_ARG(IteratorConnectHandler) handler, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) +template <typename Protocol, typename Executor, typename Iterator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken> +inline auto async_connect(basic_socket<Protocol, Executor>& s, + Iterator begin, IteratorConnectToken&& token, + constraint_t<!is_endpoint_sequence<Iterator>::value>) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, Iterator(), declval<detail::default_connect_condition>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (asio::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - detail::default_connect_condition, ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (asio::error_code, Iterator))>(s, - begin, Iterator(), detail::default_connect_condition(), - init.completion_handler)(asio::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + detail::initiate_async_iterator_connect<Protocol, Executor>(s), + token, begin, Iterator(), detail::default_connect_condition()); } #endif // !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, - typename Iterator, typename IteratorConnectHandler> -inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, - ASIO_MOVE_ARG(IteratorConnectHandler) handler) +template <typename Protocol, typename Executor, typename Iterator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken> +inline auto async_connect(basic_socket<Protocol, Executor>& s, + Iterator begin, Iterator end, IteratorConnectToken&& token) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, end, declval<detail::default_connect_condition>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (asio::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - detail::default_connect_condition, ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (asio::error_code, Iterator))>(s, - begin, end, detail::default_connect_condition(), - init.completion_handler)(asio::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + detail::initiate_async_iterator_connect<Protocol, Executor>(s), + token, begin, end, detail::default_connect_condition()); } -template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence, - typename ConnectCondition, typename RangeConnectHandler> -inline ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, + typename EndpointSequence, typename ConnectCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + typename Protocol::endpoint)) RangeConnectToken> +inline auto async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, - ASIO_MOVE_ARG(RangeConnectHandler) handler, - typename enable_if<is_endpoint_sequence< - EndpointSequence>::value>::type*) + RangeConnectToken&& token, + constraint_t<is_endpoint_sequence<EndpointSequence>::value>) + -> decltype( + async_initiate<RangeConnectToken, + void (asio::error_code, typename Protocol::endpoint)>( + declval<detail::initiate_async_range_connect<Protocol, Executor>>(), + token, endpoints, connect_condition)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a RangeConnectHandler. - ASIO_RANGE_CONNECT_HANDLER_CHECK( - RangeConnectHandler, handler, typename Protocol::endpoint) type_check; - - async_completion<RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint)> - init(handler); - - detail::range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, - ConnectCondition, ASIO_HANDLER_TYPE(RangeConnectHandler, - void (asio::error_code, typename Protocol::endpoint))>(s, - endpoints, connect_condition, init.completion_handler)( - asio::error_code(), 1); - - return init.result.get(); + return async_initiate<RangeConnectToken, + void (asio::error_code, typename Protocol::endpoint)>( + detail::initiate_async_range_connect<Protocol, Executor>(s), + token, endpoints, connect_condition); } #if !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> -inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, - Iterator begin, ConnectCondition connect_condition, - ASIO_MOVE_ARG(IteratorConnectHandler) handler, - typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) +template <typename Protocol, typename Executor, + typename Iterator, typename ConnectCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken> +inline auto async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, + ConnectCondition connect_condition, IteratorConnectToken&& token, + constraint_t<!is_endpoint_sequence<Iterator>::value>) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, Iterator(), connect_condition)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (asio::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (asio::error_code, Iterator))>(s, - begin, Iterator(), connect_condition, init.completion_handler)( - asio::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + detail::initiate_async_iterator_connect<Protocol, Executor>(s), + token, begin, Iterator(), connect_condition); } #endif // !defined(ASIO_NO_DEPRECATED) -template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> -inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, - void (asio::error_code, Iterator)) -async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, + typename Iterator, typename ConnectCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + Iterator)) IteratorConnectToken> +inline auto async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, - ASIO_MOVE_ARG(IteratorConnectHandler) handler) + IteratorConnectToken&& token) + -> decltype( + async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(), + token, begin, end, connect_condition)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (asio::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, - ConnectCondition, ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (asio::error_code, Iterator))>(s, - begin, end, connect_condition, init.completion_handler)( - asio::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectToken, + void (asio::error_code, Iterator)>( + detail::initiate_async_iterator_connect<Protocol, Executor>(s), + token, begin, end, connect_condition); } } // namespace asio diff --git a/3rdparty/asio/include/asio/impl/connect_pipe.hpp b/3rdparty/asio/include/asio/impl/connect_pipe.hpp new file mode 100644 index 00000000000..e40b3c9433c --- /dev/null +++ b/3rdparty/asio/include/asio/impl/connect_pipe.hpp @@ -0,0 +1,73 @@ +// +// impl/connect_pipe.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_CONNECT_PIPE_HPP +#define ASIO_IMPL_CONNECT_PIPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PIPE) + +#include "asio/connect_pipe.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Executor1, typename Executor2> +void connect_pipe(basic_readable_pipe<Executor1>& read_end, + basic_writable_pipe<Executor2>& write_end) +{ + asio::error_code ec; + asio::connect_pipe(read_end, write_end, ec); + asio::detail::throw_error(ec, "connect_pipe"); +} + +template <typename Executor1, typename Executor2> +ASIO_SYNC_OP_VOID connect_pipe(basic_readable_pipe<Executor1>& read_end, + basic_writable_pipe<Executor2>& write_end, asio::error_code& ec) +{ + detail::native_pipe_handle p[2]; + detail::create_pipe(p, ec); + if (ec) + ASIO_SYNC_OP_VOID_RETURN(ec); + + read_end.assign(p[0], ec); + if (ec) + { + detail::close_pipe(p[0]); + detail::close_pipe(p[1]); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + write_end.assign(p[1], ec); + if (ec) + { + asio::error_code temp_ec; + read_end.close(temp_ec); + detail::close_pipe(p[1]); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PIPE) + +#endif // ASIO_IMPL_CONNECT_PIPE_HPP diff --git a/3rdparty/asio/include/asio/impl/connect_pipe.ipp b/3rdparty/asio/include/asio/impl/connect_pipe.ipp new file mode 100644 index 00000000000..6efe790d713 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/connect_pipe.ipp @@ -0,0 +1,149 @@ +// +// impl/connect_pipe.ipp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2021 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_IMPL_CONNECT_PIPE_IPP +#define ASIO_IMPL_CONNECT_PIPE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PIPE) + +#include "asio/connect_pipe.hpp" + +#if defined(ASIO_HAS_IOCP) +# include <cstdio> +# if _WIN32_WINNT >= 0x601 +# include <bcrypt.h> +# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS) +# if defined(_MSC_VER) +# pragma comment(lib, "bcrypt.lib") +# endif // defined(_MSC_VER) +# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS) +# endif // _WIN32_WINNT >= 0x601 +#else // defined(ASIO_HAS_IOCP) +# include "asio/detail/descriptor_ops.hpp" +#endif // defined(ASIO_HAS_IOCP) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +void create_pipe(native_pipe_handle p[2], asio::error_code& ec) +{ +#if defined(ASIO_HAS_IOCP) + using namespace std; // For sprintf and memcmp. + + static long counter1 = 0; + static long counter2 = 0; + + long n1 = ::InterlockedIncrement(&counter1); + long n2 = (static_cast<unsigned long>(n1) % 0x10000000) == 0 + ? ::InterlockedIncrement(&counter2) + : ::InterlockedExchangeAdd(&counter2, 0); + + wchar_t pipe_name[128]; +#if defined(ASIO_HAS_SECURE_RTL) + swprintf_s( +#else // defined(ASIO_HAS_SECURE_RTL) + _snwprintf( +#endif // defined(ASIO_HAS_SECURE_RTL) + pipe_name, 128, + L"\\\\.\\pipe\\asio-A0812896-741A-484D-AF23-BE51BF620E22-%u-%ld-%ld", + static_cast<unsigned int>(::GetCurrentProcessId()), n1, n2); + + p[0] = ::CreateNamedPipeW(pipe_name, + PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + 0, 1, 8192, 8192, 0, 0); + + if (p[0] == INVALID_HANDLE_VALUE) + { + DWORD last_error = ::GetLastError(); + ec.assign(last_error, asio::error::get_system_category()); + return; + } + + p[1] = ::CreateFileW(pipe_name, GENERIC_WRITE, 0, + 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + + if (p[1] == INVALID_HANDLE_VALUE) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(p[0]); + ec.assign(last_error, asio::error::get_system_category()); + return; + } + +# if _WIN32_WINNT >= 0x601 + unsigned char nonce[16]; + if (::BCryptGenRandom(0, nonce, sizeof(nonce), + BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) + { + ec = asio::error::connection_aborted; + ::CloseHandle(p[0]); + ::CloseHandle(p[1]); + return; + } + + DWORD bytes_written = 0; + BOOL ok = ::WriteFile(p[1], nonce, sizeof(nonce), &bytes_written, 0); + if (!ok || bytes_written != sizeof(nonce)) + { + ec = asio::error::connection_aborted; + ::CloseHandle(p[0]); + ::CloseHandle(p[1]); + return; + } + + unsigned char nonce_check[sizeof(nonce)]; + DWORD bytes_read = 0; + ok = ::ReadFile(p[0], nonce_check, sizeof(nonce), &bytes_read, 0); + if (!ok || bytes_read != sizeof(nonce) + || memcmp(nonce, nonce_check, sizeof(nonce)) != 0) + { + ec = asio::error::connection_aborted; + ::CloseHandle(p[0]); + ::CloseHandle(p[1]); + return; + } +#endif // _WIN32_WINNT >= 0x601 + + asio::error::clear(ec); +#else // defined(ASIO_HAS_IOCP) + int result = ::pipe(p); + detail::descriptor_ops::get_last_error(ec, result != 0); +#endif // defined(ASIO_HAS_IOCP) +} + +void close_pipe(native_pipe_handle p) +{ +#if defined(ASIO_HAS_IOCP) + ::CloseHandle(p); +#else // defined(ASIO_HAS_IOCP) + asio::error_code ignored_ec; + detail::descriptor_ops::state_type state = 0; + detail::descriptor_ops::close(p, state, ignored_ec); +#endif // defined(ASIO_HAS_IOCP) +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_PIPE) + +#endif // ASIO_IMPL_CONNECT_PIPE_IPP diff --git a/3rdparty/asio/include/asio/impl/consign.hpp b/3rdparty/asio/include/asio/impl/consign.hpp new file mode 100644 index 00000000000..3b753c10fd0 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/consign.hpp @@ -0,0 +1,137 @@ +// +// impl/consign.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_CONSIGN_HPP +#define ASIO_IMPL_CONSIGN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/utility.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Class to adapt a consign_t as a completion handler. +template <typename Handler, typename... Values> +class consign_handler +{ +public: + typedef void result_type; + + template <typename H> + consign_handler(H&& handler, std::tuple<Values...> values) + : handler_(static_cast<H&&>(handler)), + values_(static_cast<std::tuple<Values...>&&>(values)) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + static_cast<Handler&&>(handler_)(static_cast<Args&&>(args)...); + } + +//private: + Handler handler_; + std::tuple<Values...> values_; +}; + +template <typename Handler> +inline bool asio_handler_is_continuation( + consign_handler<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename... Values, typename... Signatures> +struct async_result<consign_t<CompletionToken, Values...>, Signatures...> + : async_result<CompletionToken, Signatures...> +{ + template <typename Initiation> + struct init_wrapper + { + init_wrapper(Initiation init) + : initiation_(static_cast<Initiation&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, + std::tuple<Values...> values, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + detail::consign_handler<decay_t<Handler>, Values...>( + static_cast<Handler&&>(handler), + static_cast<std::tuple<Values...>&&>(values)), + static_cast<Args&&>(args)...); + } + + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<CompletionToken, Signatures...>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<std::tuple<Values...>&&>(token.values_), + static_cast<Args&&>(args)...)) + { + return async_initiate<CompletionToken, Signatures...>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, static_cast<std::tuple<Values...>&&>(token.values_), + static_cast<Args&&>(args)...); + } +}; + +template <template <typename, typename> class Associator, + typename Handler, typename... Values, typename DefaultCandidate> +struct associator<Associator, + detail::consign_handler<Handler, Values...>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::consign_handler<Handler, Values...>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const detail::consign_handler<Handler, Values...>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_CONSIGN_HPP diff --git a/3rdparty/asio/include/asio/impl/defer.hpp b/3rdparty/asio/include/asio/impl/defer.hpp deleted file mode 100644 index cf76ba58fa6..00000000000 --- a/3rdparty/asio/include/asio/impl/defer.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// impl/defer.hpp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_IMPL_DEFER_HPP -#define ASIO_IMPL_DEFER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" -#include "asio/detail/work_dispatcher.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -template <typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - ASIO_MOVE_ARG(CompletionToken) token) -{ - typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - typename associated_executor<handler>::type ex( - (get_associated_executor)(init.completion_handler)); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex.defer(ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); - - return init.result.get(); -} - -template <typename Executor, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_executor<Executor>::value>::type*) -{ - typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - Executor ex1(ex); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex1.defer(detail::work_dispatcher<handler>(init.completion_handler), alloc); - - return init.result.get(); -} - -template <typename ExecutionContext, typename CompletionToken> -inline ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type*) -{ - return (defer)(ctx.get_executor(), - ASIO_MOVE_CAST(CompletionToken)(token)); -} - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_IMPL_DEFER_HPP diff --git a/3rdparty/asio/include/asio/impl/deferred.hpp b/3rdparty/asio/include/asio/impl/deferred.hpp new file mode 100644 index 00000000000..defc34fb3e7 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/deferred.hpp @@ -0,0 +1,147 @@ +// +// impl/deferred.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_DEFERRED_HPP +#define ASIO_IMPL_DEFERRED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Signature> +class async_result<deferred_t, Signature> +{ +public: + template <typename Initiation, typename... InitArgs> + static deferred_async_operation<Signature, Initiation, InitArgs...> + initiate(Initiation&& initiation, deferred_t, InitArgs&&... args) + { + return deferred_async_operation<Signature, Initiation, InitArgs...>( + deferred_init_tag{}, + static_cast<Initiation&&>(initiation), + static_cast<InitArgs&&>(args)...); + } +}; + +template <typename... Signatures> +class async_result<deferred_t, Signatures...> +{ +public: + template <typename Initiation, typename... InitArgs> + static deferred_async_operation< + deferred_signatures<Signatures...>, Initiation, InitArgs...> + initiate(Initiation&& initiation, deferred_t, InitArgs&&... args) + { + return deferred_async_operation< + deferred_signatures<Signatures...>, Initiation, InitArgs...>( + deferred_init_tag{}, + static_cast<Initiation&&>(initiation), + static_cast<InitArgs&&>(args)...); + } +}; + +template <typename Function, typename Signature> +class async_result<deferred_function<Function>, Signature> +{ +public: + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation&& initiation, + deferred_function<Function> token, InitArgs&&... init_args) + -> decltype( + deferred_sequence< + deferred_async_operation< + Signature, Initiation, InitArgs...>, + Function>(deferred_init_tag{}, + deferred_async_operation< + Signature, Initiation, InitArgs...>( + deferred_init_tag{}, + static_cast<Initiation&&>(initiation), + static_cast<InitArgs&&>(init_args)...), + static_cast<Function&&>(token.function_))) + { + return deferred_sequence< + deferred_async_operation< + Signature, Initiation, InitArgs...>, + Function>(deferred_init_tag{}, + deferred_async_operation< + Signature, Initiation, InitArgs...>( + deferred_init_tag{}, + static_cast<Initiation&&>(initiation), + static_cast<InitArgs&&>(init_args)...), + static_cast<Function&&>(token.function_)); + } +}; + +template <typename Function, typename... Signatures> +class async_result<deferred_function<Function>, Signatures...> +{ +public: + template <typename Initiation, typename... InitArgs> + static auto initiate(Initiation&& initiation, + deferred_function<Function> token, InitArgs&&... init_args) + -> decltype( + deferred_sequence< + deferred_async_operation< + deferred_signatures<Signatures...>, Initiation, InitArgs...>, + Function>(deferred_init_tag{}, + deferred_async_operation< + deferred_signatures<Signatures...>, Initiation, InitArgs...>( + deferred_init_tag{}, + static_cast<Initiation&&>(initiation), + static_cast<InitArgs&&>(init_args)...), + static_cast<Function&&>(token.function_))) + { + return deferred_sequence< + deferred_async_operation< + deferred_signatures<Signatures...>, Initiation, InitArgs...>, + Function>(deferred_init_tag{}, + deferred_async_operation< + deferred_signatures<Signatures...>, Initiation, InitArgs...>( + deferred_init_tag{}, + static_cast<Initiation&&>(initiation), + static_cast<InitArgs&&>(init_args)...), + static_cast<Function&&>(token.function_)); + } +}; + +template <template <typename, typename> class Associator, + typename Handler, typename Tail, typename DefaultCandidate> +struct associator<Associator, + detail::deferred_sequence_handler<Handler, Tail>, + DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::deferred_sequence_handler<Handler, Tail>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const detail::deferred_sequence_handler<Handler, Tail>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_DEFERRED_HPP diff --git a/3rdparty/asio/include/asio/impl/detached.hpp b/3rdparty/asio/include/asio/impl/detached.hpp new file mode 100644 index 00000000000..774e52b1e01 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/detached.hpp @@ -0,0 +1,77 @@ +// +// impl/detached.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_DETACHED_HPP +#define ASIO_IMPL_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + + // Class to adapt a detached_t as a completion handler. + class detached_handler + { + public: + typedef void result_type; + + detached_handler(detached_t) + { + } + + template <typename... Args> + void operator()(Args...) + { + } + }; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Signature> +struct async_result<detached_t, Signature> +{ + typedef asio::detail::detached_handler completion_handler_type; + + typedef void return_type; + + explicit async_result(completion_handler_type&) + { + } + + void get() + { + } + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static return_type initiate(Initiation&& initiation, + RawCompletionToken&&, Args&&... args) + { + static_cast<Initiation&&>(initiation)( + detail::detached_handler(detached_t()), + static_cast<Args&&>(args)...); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_DETACHED_HPP diff --git a/3rdparty/asio/include/asio/impl/dispatch.hpp b/3rdparty/asio/include/asio/impl/dispatch.hpp deleted file mode 100644 index cfebc5cfde0..00000000000 --- a/3rdparty/asio/include/asio/impl/dispatch.hpp +++ /dev/null @@ -1,80 +0,0 @@ -// -// impl/dispatch.hpp -// ~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_IMPL_DISPATCH_HPP -#define ASIO_IMPL_DISPATCH_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" -#include "asio/detail/work_dispatcher.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -template <typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - ASIO_MOVE_ARG(CompletionToken) token) -{ - typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - typename associated_executor<handler>::type ex( - (get_associated_executor)(init.completion_handler)); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex.dispatch(ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); - - return init.result.get(); -} - -template <typename Executor, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_executor<Executor>::value>::type*) -{ - typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - Executor ex1(ex); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex1.dispatch(detail::work_dispatcher<handler>( - init.completion_handler), alloc); - - return init.result.get(); -} - -template <typename ExecutionContext, typename CompletionToken> -inline ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type*) -{ - return (dispatch)(ctx.get_executor(), - ASIO_MOVE_CAST(CompletionToken)(token)); -} - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_IMPL_DISPATCH_HPP diff --git a/3rdparty/asio/include/asio/impl/error.ipp b/3rdparty/asio/include/asio/impl/error.ipp index 735178578e5..b564a8c68e2 100644 --- a/3rdparty/asio/include/asio/impl/error.ipp +++ b/3rdparty/asio/include/asio/impl/error.ipp @@ -2,7 +2,7 @@ // impl/error.ipp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -31,7 +31,7 @@ namespace detail { class netdb_category : public asio::error_category { public: - const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + const char* name() const noexcept { return "asio.netdb"; } @@ -63,7 +63,7 @@ namespace detail { class addrinfo_category : public asio::error_category { public: - const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + const char* name() const noexcept { return "asio.addrinfo"; } @@ -93,7 +93,7 @@ namespace detail { class misc_category : public asio::error_category { public: - const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + const char* name() const noexcept { return "asio.misc"; } diff --git a/3rdparty/asio/include/asio/impl/error_code.ipp b/3rdparty/asio/include/asio/impl/error_code.ipp index c986812d154..caeb1967caa 100644 --- a/3rdparty/asio/include/asio/impl/error_code.ipp +++ b/3rdparty/asio/include/asio/impl/error_code.ipp @@ -2,7 +2,7 @@ // impl/error_code.ipp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -37,7 +37,7 @@ namespace detail { class system_category : public error_category { public: - const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + const char* name() const noexcept { return "asio.system"; } @@ -108,7 +108,7 @@ public: #if defined(ASIO_HAS_STD_ERROR_CODE) std::error_condition default_error_condition( - int ev) const ASIO_ERROR_CATEGORY_NOEXCEPT + int ev) const noexcept { switch (ev) { diff --git a/3rdparty/asio/include/asio/impl/execution_context.hpp b/3rdparty/asio/include/asio/impl/execution_context.hpp index 2e44ec11fd7..35dda80417f 100644 --- a/3rdparty/asio/include/asio/impl/execution_context.hpp +++ b/3rdparty/asio/include/asio/impl/execution_context.hpp @@ -2,7 +2,7 @@ // impl/execution_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,6 +23,8 @@ namespace asio { +#if !defined(GENERATING_DOCUMENTATION) + template <typename Service> inline Service& use_service(execution_context& e) { @@ -32,51 +34,17 @@ inline Service& use_service(execution_context& e) return e.service_registry_->template use_service<Service>(); } -#if !defined(GENERATING_DOCUMENTATION) -# if defined(ASIO_HAS_VARIADIC_TEMPLATES) - template <typename Service, typename... Args> -Service& make_service(execution_context& e, ASIO_MOVE_ARG(Args)... args) +Service& make_service(execution_context& e, Args&&... args) { detail::scoped_ptr<Service> svc( - new Service(e, ASIO_MOVE_CAST(Args)(args)...)); + new Service(e, static_cast<Args&&>(args)...)); e.service_registry_->template add_service<Service>(svc.get()); Service& result = *svc; svc.release(); return result; } -# else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - -template <typename Service> -Service& make_service(execution_context& e) -{ - detail::scoped_ptr<Service> svc(new Service(e)); - e.service_registry_->template add_service<Service>(svc.get()); - Service& result = *svc; - svc.release(); - return result; -} - -#define ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ - template <typename Service, ASIO_VARIADIC_TPARAMS(n)> \ - Service& make_service(execution_context& e, \ - ASIO_VARIADIC_MOVE_PARAMS(n)) \ - { \ - detail::scoped_ptr<Service> svc( \ - new Service(e, ASIO_VARIADIC_MOVE_ARGS(n))); \ - e.service_registry_->template add_service<Service>(svc.get()); \ - Service& result = *svc; \ - svc.release(); \ - return result; \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_MAKE_SERVICE_DEF) -#undef ASIO_PRIVATE_MAKE_SERVICE_DEF - -# endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) -#endif // !defined(GENERATING_DOCUMENTATION) - template <typename Service> inline void add_service(execution_context& e, Service* svc) { @@ -95,6 +63,8 @@ inline bool has_service(execution_context& e) return e.service_registry_->template has_service<Service>(); } +#endif // !defined(GENERATING_DOCUMENTATION) + inline execution_context& execution_context::service::context() { return owner_; diff --git a/3rdparty/asio/include/asio/impl/execution_context.ipp b/3rdparty/asio/include/asio/impl/execution_context.ipp index 40bb263f3d8..ed2603c9011 100644 --- a/3rdparty/asio/include/asio/impl/execution_context.ipp +++ b/3rdparty/asio/include/asio/impl/execution_context.ipp @@ -2,7 +2,7 @@ // impl/execution_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/impl/executor.hpp b/3rdparty/asio/include/asio/impl/executor.hpp index eb83e5cc91a..8bf76ccd183 100644 --- a/3rdparty/asio/include/asio/impl/executor.hpp +++ b/3rdparty/asio/include/asio/impl/executor.hpp @@ -2,7 +2,7 @@ // impl/executor.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,11 +16,13 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_TS_EXECUTORS) + +#include <new> #include "asio/detail/atomic_count.hpp" -#include "asio/detail/executor_op.hpp" #include "asio/detail/global.hpp" #include "asio/detail/memory.hpp" -#include "asio/detail/recycling_allocator.hpp" #include "asio/executor.hpp" #include "asio/system_executor.hpp" @@ -30,109 +32,13 @@ namespace asio { #if !defined(GENERATING_DOCUMENTATION) -#if defined(ASIO_HAS_MOVE) - -// Lightweight, move-only function object wrapper. -class executor::function -{ -public: - template <typename F, typename Alloc> - explicit function(F f, const Alloc& a) - { - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Alloc>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Alloc>::get(a)); - - // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<F, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - op_ = new (p.v) op(f, allocator); - p.v = 0; - } - - function(function&& other) - : op_(other.op_) - { - other.op_ = 0; - } - - ~function() - { - if (op_) - op_->destroy(); - } - - void operator()() - { - if (op_) - { - detail::scheduler_operation* op = op_; - op_ = 0; - op->complete(this, asio::error_code(), 0); - } - } - -private: - detail::scheduler_operation* op_; -}; - -#else // defined(ASIO_HAS_MOVE) - -// Not so lightweight, copyable function object wrapper. -class executor::function -{ -public: - template <typename F, typename Alloc> - explicit function(const F& f, const Alloc&) - : impl_(new impl<F>(f)) - { - } - - void operator()() - { - impl_->invoke_(impl_.get()); - } - -private: - // Base class for polymorphic function implementations. - struct impl_base - { - void (*invoke_)(impl_base*); - }; - - // Polymorphic function implementation. - template <typename F> - struct impl : impl_base - { - impl(const F& f) - : function_(f) - { - invoke_ = &function::invoke<F>; - } - - F function_; - }; - - // Helper to invoke a function. - template <typename F> - static void invoke(impl_base* i) - { - static_cast<impl<F>*>(i)->function_(); - } - - detail::shared_ptr<impl_base> impl_; -}; - -#endif // defined(ASIO_HAS_MOVE) - -// Default polymorphic allocator implementation. +// Default polymorphic executor implementation. template <typename Executor, typename Allocator> class executor::impl : public executor::impl_base { public: - typedef typename Allocator::template rebind<impl>::other allocator_type; + typedef ASIO_REBIND_ALLOC(Allocator, impl) allocator_type; static impl_base* create(const Executor& e, Allocator a = Allocator()) { @@ -142,7 +48,12 @@ public: return p; } - impl(const Executor& e, const Allocator& a) ASIO_NOEXCEPT + static impl_base* create(std::nothrow_t, const Executor& e) noexcept + { + return new (std::nothrow) impl(e, std::allocator<void>()); + } + + impl(const Executor& e, const Allocator& a) noexcept : impl_base(false), ref_count_(1), executor_(e), @@ -150,15 +61,15 @@ public: { } - impl_base* clone() const ASIO_NOEXCEPT + impl_base* clone() const noexcept { - ++ref_count_; + detail::ref_count_up(ref_count_); return const_cast<impl_base*>(static_cast<const impl_base*>(this)); } - void destroy() ASIO_NOEXCEPT + void destroy() noexcept { - if (--ref_count_ == 0) + if (detail::ref_count_down(ref_count_)) { allocator_type alloc(allocator_); impl* p = this; @@ -167,52 +78,52 @@ public: } } - void on_work_started() ASIO_NOEXCEPT + void on_work_started() noexcept { executor_.on_work_started(); } - void on_work_finished() ASIO_NOEXCEPT + void on_work_finished() noexcept { executor_.on_work_finished(); } - execution_context& context() ASIO_NOEXCEPT + execution_context& context() noexcept { return executor_.context(); } - void dispatch(ASIO_MOVE_ARG(function) f) + void dispatch(function&& f) { - executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_); + executor_.dispatch(static_cast<function&&>(f), allocator_); } - void post(ASIO_MOVE_ARG(function) f) + void post(function&& f) { - executor_.post(ASIO_MOVE_CAST(function)(f), allocator_); + executor_.post(static_cast<function&&>(f), allocator_); } - void defer(ASIO_MOVE_ARG(function) f) + void defer(function&& f) { - executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_); + executor_.defer(static_cast<function&&>(f), allocator_); } - type_id_result_type target_type() const ASIO_NOEXCEPT + type_id_result_type target_type() const noexcept { return type_id<Executor>(); } - void* target() ASIO_NOEXCEPT + void* target() noexcept { return &executor_; } - const void* target() const ASIO_NOEXCEPT + const void* target() const noexcept { return &executor_; } - bool equals(const impl_base* e) const ASIO_NOEXCEPT + bool equals(const impl_base* e) const noexcept { if (this == e) return true; @@ -250,7 +161,7 @@ private: }; }; -// Polymorphic allocator specialisation for system_executor. +// Polymorphic executor specialisation for system_executor. template <typename Allocator> class executor::impl<system_executor, Allocator> : public executor::impl_base @@ -259,7 +170,12 @@ public: static impl_base* create(const system_executor&, const Allocator& = Allocator()) { - return &detail::global<impl<system_executor, std::allocator<void> > >(); + return &detail::global<impl<system_executor, std::allocator<void>> >(); + } + + static impl_base* create(std::nothrow_t, const system_executor&) noexcept + { + return &detail::global<impl<system_executor, std::allocator<void>> >(); } impl() @@ -267,73 +183,81 @@ public: { } - impl_base* clone() const ASIO_NOEXCEPT + impl_base* clone() const noexcept { return const_cast<impl_base*>(static_cast<const impl_base*>(this)); } - void destroy() ASIO_NOEXCEPT + void destroy() noexcept { } - void on_work_started() ASIO_NOEXCEPT + void on_work_started() noexcept { executor_.on_work_started(); } - void on_work_finished() ASIO_NOEXCEPT + void on_work_finished() noexcept { executor_.on_work_finished(); } - execution_context& context() ASIO_NOEXCEPT + execution_context& context() noexcept { return executor_.context(); } - void dispatch(ASIO_MOVE_ARG(function) f) + void dispatch(function&& f) { - executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_); + executor_.dispatch(static_cast<function&&>(f), + std::allocator<void>()); } - void post(ASIO_MOVE_ARG(function) f) + void post(function&& f) { - executor_.post(ASIO_MOVE_CAST(function)(f), allocator_); + executor_.post(static_cast<function&&>(f), + std::allocator<void>()); } - void defer(ASIO_MOVE_ARG(function) f) + void defer(function&& f) { - executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_); + executor_.defer(static_cast<function&&>(f), + std::allocator<void>()); } - type_id_result_type target_type() const ASIO_NOEXCEPT + type_id_result_type target_type() const noexcept { return type_id<system_executor>(); } - void* target() ASIO_NOEXCEPT + void* target() noexcept { return &executor_; } - const void* target() const ASIO_NOEXCEPT + const void* target() const noexcept { return &executor_; } - bool equals(const impl_base* e) const ASIO_NOEXCEPT + bool equals(const impl_base* e) const noexcept { return this == e; } private: system_executor executor_; - Allocator allocator_; }; template <typename Executor> executor::executor(Executor e) - : impl_(impl<Executor, std::allocator<void> >::create(e)) + : impl_(impl<Executor, std::allocator<void>>::create(e)) +{ +} + +template <typename Executor> +executor::executor(std::nothrow_t, Executor e) noexcept + : impl_(impl<Executor, std::allocator<void>>::create(std::nothrow, e)) { } @@ -344,39 +268,39 @@ executor::executor(allocator_arg_t, const Allocator& a, Executor e) } template <typename Function, typename Allocator> -void executor::dispatch(ASIO_MOVE_ARG(Function) f, +void executor::dispatch(Function&& f, const Allocator& a) const { impl_base* i = get_impl(); if (i->fast_dispatch_) - system_executor().dispatch(ASIO_MOVE_CAST(Function)(f), a); + system_executor().dispatch(static_cast<Function&&>(f), a); else - i->dispatch(function(ASIO_MOVE_CAST(Function)(f), a)); + i->dispatch(function(static_cast<Function&&>(f), a)); } template <typename Function, typename Allocator> -void executor::post(ASIO_MOVE_ARG(Function) f, +void executor::post(Function&& f, const Allocator& a) const { - get_impl()->post(function(ASIO_MOVE_CAST(Function)(f), a)); + get_impl()->post(function(static_cast<Function&&>(f), a)); } template <typename Function, typename Allocator> -void executor::defer(ASIO_MOVE_ARG(Function) f, +void executor::defer(Function&& f, const Allocator& a) const { - get_impl()->defer(function(ASIO_MOVE_CAST(Function)(f), a)); + get_impl()->defer(function(static_cast<Function&&>(f), a)); } template <typename Executor> -Executor* executor::target() ASIO_NOEXCEPT +Executor* executor::target() noexcept { return impl_ && impl_->target_type() == type_id<Executor>() ? static_cast<Executor*>(impl_->target()) : 0; } template <typename Executor> -const Executor* executor::target() const ASIO_NOEXCEPT +const Executor* executor::target() const noexcept { return impl_ && impl_->target_type() == type_id<Executor>() ? static_cast<Executor*>(impl_->target()) : 0; @@ -388,4 +312,6 @@ const Executor* executor::target() const ASIO_NOEXCEPT #include "asio/detail/pop_options.hpp" +#endif // !defined(ASIO_NO_TS_EXECUTORS) + #endif // ASIO_IMPL_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/impl/executor.ipp b/3rdparty/asio/include/asio/impl/executor.ipp index 605333e4879..4153a171e09 100644 --- a/3rdparty/asio/include/asio/impl/executor.ipp +++ b/3rdparty/asio/include/asio/impl/executor.ipp @@ -2,7 +2,7 @@ // impl/executor.ipp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,17 +16,20 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_TS_EXECUTORS) + #include "asio/executor.hpp" #include "asio/detail/push_options.hpp" namespace asio { -bad_executor::bad_executor() ASIO_NOEXCEPT +bad_executor::bad_executor() noexcept { } -const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW +const char* bad_executor::what() const noexcept { return "bad executor"; } @@ -35,4 +38,6 @@ const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW #include "asio/detail/pop_options.hpp" +#endif // !defined(ASIO_NO_TS_EXECUTORS) + #endif // ASIO_IMPL_EXECUTOR_IPP diff --git a/3rdparty/asio/include/asio/impl/handler_alloc_hook.ipp b/3rdparty/asio/include/asio/impl/handler_alloc_hook.ipp deleted file mode 100644 index f4bcdf90b13..00000000000 --- a/3rdparty/asio/include/asio/impl/handler_alloc_hook.ipp +++ /dev/null @@ -1,52 +0,0 @@ -// -// impl/handler_alloc_hook.ipp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_IMPL_HANDLER_ALLOC_HOOK_IPP -#define ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include "asio/detail/thread_context.hpp" -#include "asio/detail/thread_info_base.hpp" -#include "asio/handler_alloc_hook.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -void* asio_handler_allocate(std::size_t size, ...) -{ -#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) - return detail::thread_info_base::allocate( - detail::thread_context::thread_call_stack::top(), size); -#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) - return ::operator new(size); -#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) -} - -void asio_handler_deallocate(void* pointer, std::size_t size, ...) -{ -#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) - detail::thread_info_base::deallocate( - detail::thread_context::thread_call_stack::top(), pointer, size); -#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) - (void)size; - ::operator delete(pointer); -#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) -} - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP diff --git a/3rdparty/asio/include/asio/impl/io_context.hpp b/3rdparty/asio/include/asio/impl/io_context.hpp index 45805ae6262..002b585502d 100644 --- a/3rdparty/asio/include/asio/impl/io_context.hpp +++ b/3rdparty/asio/include/asio/impl/io_context.hpp @@ -2,7 +2,7 @@ // impl/io_context.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,7 +19,7 @@ #include "asio/detail/executor_op.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_type_requirements.hpp" -#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/service_registry.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/type_traits.hpp" @@ -28,6 +28,8 @@ namespace asio { +#if !defined(GENERATING_DOCUMENTATION) + template <typename Service> inline Service& use_service(io_context& ioc) { @@ -45,28 +47,14 @@ inline detail::io_context_impl& use_service<detail::io_context_impl>( return ioc.impl_; } -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#if defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_io_context.hpp" -#else -# include "asio/detail/scheduler.hpp" -#endif - -#include "asio/detail/push_options.hpp" - -namespace asio { +#endif // !defined(GENERATING_DOCUMENTATION) inline io_context::executor_type -io_context::get_executor() ASIO_NOEXCEPT +io_context::get_executor() noexcept { return executor_type(*this); } -#if defined(ASIO_HAS_CHRONO) - template <typename Rep, typename Period> std::size_t io_context::run_for( const chrono::duration<Rep, Period>& rel_time) @@ -118,8 +106,6 @@ std::size_t io_context::run_one_until( return 0; } -#endif // defined(ASIO_HAS_CHRONO) - #if !defined(ASIO_NO_DEPRECATED) inline void io_context::reset() @@ -127,68 +113,90 @@ inline void io_context::reset() restart(); } -template <typename CompletionHandler> -ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) -io_context::dispatch(ASIO_MOVE_ARG(CompletionHandler) handler) +struct io_context::initiate_dispatch { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; - - async_completion<CompletionHandler, void ()> init(handler); - - if (impl_.can_dispatch()) + template <typename LegacyCompletionHandler> + void operator()(LegacyCompletionHandler&& handler, + io_context* self) const { - detail::fenced_block b(detail::fenced_block::full); - asio_handler_invoke_helpers::invoke( - init.completion_handler, init.completion_handler); - } - else - { - // Allocate and construct an operation to wrap the handler. - typedef detail::completion_handler< - typename handler_type<CompletionHandler, void ()>::type> op; - typename op::ptr p = { detail::addressof(init.completion_handler), - op::ptr::allocate(init.completion_handler), 0 }; - p.p = new (p.v) op(init.completion_handler); - - ASIO_HANDLER_CREATION((*this, *p.p, - "io_context", this, 0, "dispatch")); - - impl_.do_dispatch(p.p); - p.v = p.p = 0; + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a LegacyCompletionHandler. + ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); + if (self->impl_.can_dispatch()) + { + detail::fenced_block b(detail::fenced_block::full); + static_cast<decay_t<LegacyCompletionHandler>&&>(handler2.value)(); + } + else + { + // Allocate and construct an operation to wrap the handler. + typedef detail::completion_handler< + decay_t<LegacyCompletionHandler>, executor_type> op; + typename op::ptr p = { detail::addressof(handler2.value), + op::ptr::allocate(handler2.value), 0 }; + p.p = new (p.v) op(handler2.value, self->get_executor()); + + ASIO_HANDLER_CREATION((*self, *p.p, + "io_context", self, 0, "dispatch")); + + self->impl_.do_dispatch(p.p); + p.v = p.p = 0; + } } +}; - return init.result.get(); +template <typename LegacyCompletionHandler> +auto io_context::dispatch(LegacyCompletionHandler&& handler) + -> decltype( + async_initiate<LegacyCompletionHandler, void ()>( + declval<initiate_dispatch>(), handler, this)) +{ + return async_initiate<LegacyCompletionHandler, void ()>( + initiate_dispatch(), handler, this); } -template <typename CompletionHandler> -ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) -io_context::post(ASIO_MOVE_ARG(CompletionHandler) handler) +struct io_context::initiate_post { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; + template <typename LegacyCompletionHandler> + void operator()(LegacyCompletionHandler&& handler, + io_context* self) const + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a LegacyCompletionHandler. + ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; - async_completion<CompletionHandler, void ()> init(handler); + detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); - bool is_continuation = - asio_handler_cont_helpers::is_continuation(init.completion_handler); + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler2.value); - // Allocate and construct an operation to wrap the handler. - typedef detail::completion_handler< - typename handler_type<CompletionHandler, void ()>::type> op; - typename op::ptr p = { detail::addressof(init.completion_handler), - op::ptr::allocate(init.completion_handler), 0 }; - p.p = new (p.v) op(init.completion_handler); + // Allocate and construct an operation to wrap the handler. + typedef detail::completion_handler< + decay_t<LegacyCompletionHandler>, executor_type> op; + typename op::ptr p = { detail::addressof(handler2.value), + op::ptr::allocate(handler2.value), 0 }; + p.p = new (p.v) op(handler2.value, self->get_executor()); - ASIO_HANDLER_CREATION((*this, *p.p, - "io_context", this, 0, "post")); + ASIO_HANDLER_CREATION((*self, *p.p, + "io_context", self, 0, "post")); - impl_.post_immediate_completion(p.p, is_continuation); - p.v = p.p = 0; + self->impl_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + } +}; - return init.result.get(); +template <typename LegacyCompletionHandler> +auto io_context::post(LegacyCompletionHandler&& handler) + -> decltype( + async_initiate<LegacyCompletionHandler, void ()>( + declval<initiate_post>(), handler, this)) +{ + return async_initiate<LegacyCompletionHandler, void ()>( + initiate_post(), handler, this); } template <typename Handler> @@ -204,112 +212,190 @@ io_context::wrap(Handler handler) #endif // !defined(ASIO_NO_DEPRECATED) -inline io_context& -io_context::executor_type::context() const ASIO_NOEXCEPT +template <typename Allocator, uintptr_t Bits> +io_context::basic_executor_type<Allocator, Bits>& +io_context::basic_executor_type<Allocator, Bits>::operator=( + const basic_executor_type& other) noexcept { - return io_context_; + if (this != &other) + { + static_cast<Allocator&>(*this) = static_cast<const Allocator&>(other); + io_context* old_io_context = context_ptr(); + target_ = other.target_; + if (Bits & outstanding_work_tracked) + { + if (context_ptr()) + context_ptr()->impl_.work_started(); + if (old_io_context) + old_io_context->impl_.work_finished(); + } + } + return *this; } -inline void -io_context::executor_type::on_work_started() const ASIO_NOEXCEPT +template <typename Allocator, uintptr_t Bits> +io_context::basic_executor_type<Allocator, Bits>& +io_context::basic_executor_type<Allocator, Bits>::operator=( + basic_executor_type&& other) noexcept { - io_context_.impl_.work_started(); + if (this != &other) + { + static_cast<Allocator&>(*this) = static_cast<Allocator&&>(other); + io_context* old_io_context = context_ptr(); + target_ = other.target_; + if (Bits & outstanding_work_tracked) + { + other.target_ = 0; + if (old_io_context) + old_io_context->impl_.work_finished(); + } + } + return *this; } -inline void -io_context::executor_type::on_work_finished() const ASIO_NOEXCEPT +template <typename Allocator, uintptr_t Bits> +inline bool io_context::basic_executor_type<Allocator, + Bits>::running_in_this_thread() const noexcept { - io_context_.impl_.work_finished(); + return context_ptr()->impl_.can_dispatch(); } -template <typename Function, typename Allocator> -void io_context::executor_type::dispatch( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Allocator, uintptr_t Bits> +template <typename Function> +void io_context::basic_executor_type<Allocator, Bits>::execute( + Function&& f) const { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); + typedef decay_t<Function> function_type; - // Invoke immediately if we are already inside the thread pool. - if (io_context_.impl_.can_dispatch()) + // Invoke immediately if the blocking.possibly property is enabled and we are + // already inside the thread pool. + if ((bits() & blocking_never) == 0 && context_ptr()->impl_.can_dispatch()) { - detail::fenced_block b(detail::fenced_block::full); - asio_handler_invoke_helpers::invoke(tmp, tmp); - return; + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(f)); + +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif // !defined(ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + static_cast<function_type&&>(tmp)(); + return; +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + context_ptr()->impl_.capture_current_exception(); + return; + } +#endif // !defined(ASIO_NO_EXCEPTIONS) } - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); - // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type, detail::operation> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<function_type, Allocator, detail::operation> op; + typename op::ptr p = { + detail::addressof(static_cast<const Allocator&>(*this)), + op::ptr::allocate(static_cast<const Allocator&>(*this)), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), + static_cast<const Allocator&>(*this)); + + ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "execute")); + + context_ptr()->impl_.post_immediate_completion(p.p, + (bits() & relationship_continuation) != 0); + p.v = p.p = 0; +} - ASIO_HANDLER_CREATION((this->context(), *p.p, - "io_context", &this->context(), 0, "post")); +#if !defined(ASIO_NO_TS_EXECUTORS) +template <typename Allocator, uintptr_t Bits> +inline io_context& io_context::basic_executor_type< + Allocator, Bits>::context() const noexcept +{ + return *context_ptr(); +} - io_context_.impl_.post_immediate_completion(p.p, false); - p.v = p.p = 0; +template <typename Allocator, uintptr_t Bits> +inline void io_context::basic_executor_type<Allocator, + Bits>::on_work_started() const noexcept +{ + context_ptr()->impl_.work_started(); } -template <typename Function, typename Allocator> -void io_context::executor_type::post( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Allocator, uintptr_t Bits> +inline void io_context::basic_executor_type<Allocator, + Bits>::on_work_finished() const noexcept { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); + context_ptr()->impl_.work_finished(); +} - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); +template <typename Allocator, uintptr_t Bits> +template <typename Function, typename OtherAllocator> +void io_context::basic_executor_type<Allocator, Bits>::dispatch( + Function&& f, const OtherAllocator& a) const +{ + typedef decay_t<Function> function_type; + + // Invoke immediately if we are already inside the thread pool. + if (context_ptr()->impl_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(f)); + + detail::fenced_block b(detail::fenced_block::full); + static_cast<function_type&&>(tmp)(); + return; + } // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type, detail::operation> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<function_type, + OtherAllocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); - ASIO_HANDLER_CREATION((this->context(), *p.p, - "io_context", &this->context(), 0, "post")); + ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "dispatch")); - io_context_.impl_.post_immediate_completion(p.p, false); + context_ptr()->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template <typename Function, typename Allocator> -void io_context::executor_type::defer( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Allocator, uintptr_t Bits> +template <typename Function, typename OtherAllocator> +void io_context::basic_executor_type<Allocator, Bits>::post( + Function&& f, const OtherAllocator& a) const { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); - - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); - // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type, detail::operation> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<decay_t<Function>, + OtherAllocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); - ASIO_HANDLER_CREATION((this->context(), *p.p, - "io_context", &this->context(), 0, "defer")); + ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "post")); - io_context_.impl_.post_immediate_completion(p.p, true); + context_ptr()->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -inline bool -io_context::executor_type::running_in_this_thread() const ASIO_NOEXCEPT +template <typename Allocator, uintptr_t Bits> +template <typename Function, typename OtherAllocator> +void io_context::basic_executor_type<Allocator, Bits>::defer( + Function&& f, const OtherAllocator& a) const { - return io_context_.impl_.can_dispatch(); + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<decay_t<Function>, + OtherAllocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); + + ASIO_HANDLER_CREATION((*context_ptr(), *p.p, + "io_context", context_ptr(), 0, "defer")); + + context_ptr()->impl_.post_immediate_completion(p.p, true); + p.v = p.p = 0; } +#endif // !defined(ASIO_NO_TS_EXECUTORS) #if !defined(ASIO_NO_DEPRECATED) inline io_context::work::work(asio::io_context& io_context) @@ -333,11 +419,6 @@ inline asio::io_context& io_context::work::get_io_context() { return static_cast<asio::io_context&>(io_context_impl_.context()); } - -inline asio::io_context& io_context::work::get_io_service() -{ - return static_cast<asio::io_context&>(io_context_impl_.context()); -} #endif // !defined(ASIO_NO_DEPRECATED) inline asio::io_context& io_context::service::get_io_context() @@ -345,13 +426,6 @@ inline asio::io_context& io_context::service::get_io_context() return static_cast<asio::io_context&>(context()); } -#if !defined(ASIO_NO_DEPRECATED) -inline asio::io_context& io_context::service::get_io_service() -{ - return static_cast<asio::io_context&>(context()); -} -#endif // !defined(ASIO_NO_DEPRECATED) - } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/impl/io_context.ipp b/3rdparty/asio/include/asio/impl/io_context.ipp index b78ec1e81bb..14c8736c7b2 100644 --- a/3rdparty/asio/include/asio/impl/io_context.ipp +++ b/3rdparty/asio/include/asio/impl/io_context.ipp @@ -2,7 +2,7 @@ // impl/io_context.ipp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -34,13 +34,14 @@ namespace asio { io_context::io_context() - : impl_(add_impl(new impl_type(*this, ASIO_CONCURRENCY_HINT_DEFAULT))) + : impl_(add_impl(new impl_type(*this, + ASIO_CONCURRENCY_HINT_DEFAULT, false))) { } io_context::io_context(int concurrency_hint) : impl_(add_impl(new impl_type(*this, concurrency_hint == 1 - ? ASIO_CONCURRENCY_HINT_1 : concurrency_hint))) + ? ASIO_CONCURRENCY_HINT_1 : concurrency_hint, false))) { } @@ -53,6 +54,7 @@ io_context::impl_type& io_context::add_impl(io_context::impl_type* impl) io_context::~io_context() { + shutdown(); } io_context::count_type io_context::run() diff --git a/3rdparty/asio/include/asio/impl/multiple_exceptions.ipp b/3rdparty/asio/include/asio/impl/multiple_exceptions.ipp new file mode 100644 index 00000000000..c922c27a055 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/multiple_exceptions.ipp @@ -0,0 +1,45 @@ +// +// impl/multiple_exceptions.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_MULTIPLE_EXCEPTIONS_IPP +#define ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/multiple_exceptions.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +multiple_exceptions::multiple_exceptions( + std::exception_ptr first) noexcept + : first_(static_cast<std::exception_ptr&&>(first)) +{ +} + +const char* multiple_exceptions::what() const noexcept +{ + return "multiple exceptions"; +} + +std::exception_ptr multiple_exceptions::first_exception() const +{ + return first_; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP diff --git a/3rdparty/asio/include/asio/impl/post.hpp b/3rdparty/asio/include/asio/impl/post.hpp deleted file mode 100644 index 293b3873bd4..00000000000 --- a/3rdparty/asio/include/asio/impl/post.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// impl/post.hpp -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_IMPL_POST_HPP -#define ASIO_IMPL_POST_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" -#include "asio/detail/work_dispatcher.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -template <typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - ASIO_MOVE_ARG(CompletionToken) token) -{ - typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - typename associated_executor<handler>::type ex( - (get_associated_executor)(init.completion_handler)); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex.post(ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); - - return init.result.get(); -} - -template <typename Executor, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_executor<Executor>::value>::type*) -{ - typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - Executor ex1(ex); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex1.post(detail::work_dispatcher<handler>(init.completion_handler), alloc); - - return init.result.get(); -} - -template <typename ExecutionContext, typename CompletionToken> -inline ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type*) -{ - return (post)(ctx.get_executor(), - ASIO_MOVE_CAST(CompletionToken)(token)); -} - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_IMPL_POST_HPP diff --git a/3rdparty/asio/include/asio/impl/prepend.hpp b/3rdparty/asio/include/asio/impl/prepend.hpp new file mode 100644 index 00000000000..f336d55d825 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/prepend.hpp @@ -0,0 +1,163 @@ +// +// impl/prepend.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_PREPEND_HPP +#define ASIO_IMPL_PREPEND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/utility.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Class to adapt a prepend_t as a completion handler. +template <typename Handler, typename... Values> +class prepend_handler +{ +public: + typedef void result_type; + + template <typename H> + prepend_handler(H&& handler, std::tuple<Values...> values) + : handler_(static_cast<H&&>(handler)), + values_(static_cast<std::tuple<Values...>&&>(values)) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + this->invoke( + index_sequence_for<Values...>{}, + static_cast<Args&&>(args)...); + } + + template <std::size_t... I, typename... Args> + void invoke(index_sequence<I...>, Args&&... args) + { + static_cast<Handler&&>(handler_)( + static_cast<Values&&>(std::get<I>(values_))..., + static_cast<Args&&>(args)...); + } + +//private: + Handler handler_; + std::tuple<Values...> values_; +}; + +template <typename Handler> +inline bool asio_handler_is_continuation( + prepend_handler<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Signature, typename... Values> +struct prepend_signature; + +template <typename R, typename... Args, typename... Values> +struct prepend_signature<R(Args...), Values...> +{ + typedef R type(Values..., decay_t<Args>...); +}; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename... Values, typename Signature> +struct async_result< + prepend_t<CompletionToken, Values...>, Signature> + : async_result<CompletionToken, + typename detail::prepend_signature< + Signature, Values...>::type> +{ + typedef typename detail::prepend_signature< + Signature, Values...>::type signature; + + template <typename Initiation> + struct init_wrapper + { + init_wrapper(Initiation init) + : initiation_(static_cast<Initiation&&>(init)) + { + } + + template <typename Handler, typename... Args> + void operator()(Handler&& handler, + std::tuple<Values...> values, Args&&... args) + { + static_cast<Initiation&&>(initiation_)( + detail::prepend_handler<decay_t<Handler>, Values...>( + static_cast<Handler&&>(handler), + static_cast<std::tuple<Values...>&&>(values)), + static_cast<Args&&>(args)...); + } + + Initiation initiation_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<CompletionToken, signature>( + declval<init_wrapper<decay_t<Initiation>>>(), + token.token_, + static_cast<std::tuple<Values...>&&>(token.values_), + static_cast<Args&&>(args)...)) + { + return async_initiate<CompletionToken, signature>( + init_wrapper<decay_t<Initiation>>( + static_cast<Initiation&&>(initiation)), + token.token_, + static_cast<std::tuple<Values...>&&>(token.values_), + static_cast<Args&&>(args)...); + } +}; + +template <template <typename, typename> class Associator, + typename Handler, typename... Values, typename DefaultCandidate> +struct associator<Associator, + detail::prepend_handler<Handler, Values...>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::prepend_handler<Handler, Values...>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const detail::prepend_handler<Handler, Values...>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_PREPEND_HPP diff --git a/3rdparty/asio/include/asio/impl/read.hpp b/3rdparty/asio/include/asio/impl/read.hpp index 385a552ed8e..d86fb6467b1 100644 --- a/3rdparty/asio/include/asio/impl/read.hpp +++ b/3rdparty/asio/include/asio/impl/read.hpp @@ -2,7 +2,7 @@ // impl/read.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,19 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <algorithm> -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" +#include "asio/associator.hpp" #include "asio/buffer.hpp" -#include "asio/completion_condition.hpp" #include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/dependent_type.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_tracking.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" @@ -40,7 +39,7 @@ namespace detail { template <typename SyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition> - std::size_t read_buffer_sequence(SyncReadStream& s, + std::size_t read_buffer_seq(SyncReadStream& s, const MutableBufferSequence& buffers, const MutableBufferIterator&, CompletionCondition completion_condition, asio::error_code& ec) { @@ -55,7 +54,7 @@ namespace detail else break; } - return tmp.total_consumed();; + return tmp.total_consumed(); } } // namespace detail @@ -63,19 +62,20 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type*) + >) { - return detail::read_buffer_sequence(s, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, ec); + return detail::read_buffer_seq(s, buffers, + asio::buffer_sequence_begin(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); } template <typename SyncReadStream, typename MutableBufferSequence> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type*) + >) { asio::error_code ec; std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); @@ -86,9 +86,9 @@ inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, template <typename SyncReadStream, typename MutableBufferSequence> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, asio::error_code& ec, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type*) + >) { return read(s, buffers, transfer_all(), ec); } @@ -97,27 +97,33 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type*) + >) { asio::error_code ec; - std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); + std::size_t bytes_transferred = read(s, buffers, + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "read"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer, +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - typename decay<DynamicBuffer>::type b( - ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + decay_t<DynamicBuffer_v1> b( + static_cast<DynamicBuffer_v1&&>(buffers)); ec = asio::error_code(); std::size_t total_transferred = 0; @@ -140,45 +146,54 @@ std::size_t read(SyncReadStream& s, return total_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + DynamicBuffer_v1&& buffers, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = read(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), transfer_all(), ec); + static_cast<DynamicBuffer_v1&&>(buffers), transfer_all(), ec); asio::detail::throw_error(ec, "read"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - return read(s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + return read(s, static_cast<DynamicBuffer_v1&&>(buffers), transfer_all(), ec); } -template <typename SyncReadStream, typename DynamicBuffer, +template <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = read(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, ec); + static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "read"); return bytes_transferred; } @@ -192,7 +207,8 @@ inline std::size_t read(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, asio::error_code& ec) { - return read(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); + return read(s, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition), ec); } template <typename SyncReadStream, typename Allocator> @@ -216,11 +232,87 @@ inline std::size_t read(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - return read(s, basic_streambuf_ref<Allocator>(b), completion_condition); + return read(s, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition)); } #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + DynamicBuffer_v2& b = buffers; + + ec = asio::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); + while (bytes_available > 0) + { + std::size_t pos = b.size(); + b.grow(bytes_available); + std::size_t bytes_transferred = s.read_some( + b.data(pos, bytes_available), ec); + b.shrink(bytes_available - bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); + } + return total_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, + static_cast<DynamicBuffer_v2&&>(buffers), transfer_all(), ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + return read(s, static_cast<DynamicBuffer_v2&&>(buffers), + transfer_all(), ec); +} + +template <typename SyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, + static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} namespace detail { @@ -228,23 +320,25 @@ namespace detail typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> class read_op - : detail::base_from_completion_cond<CompletionCondition> + : public base_from_cancellation_state<ReadHandler>, + base_from_completion_cond<CompletionCondition> { public: read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), + CompletionCondition& completion_condition, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + base_from_completion_cond<CompletionCondition>(completion_condition), stream_(stream), buffers_(buffers), start_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) read_op(const read_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<ReadHandler>(other), + base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), @@ -253,16 +347,18 @@ namespace detail } read_op(read_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + base_from_completion_cond<CompletionCondition>( + static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), stream_(other.stream_), - buffers_(other.buffers_), + buffers_(static_cast<buffers_type&&>(other.buffers_)), start_(other.start_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size; @@ -270,25 +366,39 @@ namespace detail { case 1: max_size = this->check_for_completion(ec, buffers_.total_consumed()); - do + for (;;) { - stream_.async_read_some(buffers_.prepare(max_size), - ASIO_MOVE_CAST(read_op)(*this)); + { + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); + stream_.async_read_some(buffers_.prepare(max_size), + static_cast<read_op&&>(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; max_size = this->check_for_completion(ec, buffers_.total_consumed()); - } while (max_size > 0); + if (max_size == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } + } - handler_(ec, buffers_.total_consumed()); + static_cast<ReadHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), + static_cast<const std::size_t&>(buffers_.total_consumed())); } } //private: + typedef asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_type; + AsyncReadStream& stream_; - asio::detail::consuming_buffers<mutable_buffer, - MutableBufferSequence, MutableBufferIterator> buffers_; + buffers_type buffers_; int start_; ReadHandler handler_; }; @@ -296,28 +406,6 @@ namespace detail template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, - CompletionCondition, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncReadStream, typename MutableBufferSequence, - typename MutableBufferIterator, typename CompletionCondition, - typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, - CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncReadStream, typename MutableBufferSequence, - typename MutableBufferIterator, typename CompletionCondition, - typename ReadHandler> inline bool asio_handler_is_continuation( read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) @@ -327,158 +415,158 @@ namespace detail this_handler->handler_); } - template <typename Function, typename AsyncReadStream, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, - CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - - template <typename Function, typename AsyncReadStream, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, - CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> - inline void start_read_buffer_sequence_op(AsyncReadStream& stream, + inline void start_read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, const MutableBufferIterator&, - CompletionCondition completion_condition, ReadHandler& handler) + CompletionCondition& completion_condition, ReadHandler& handler) { - detail::read_op<AsyncReadStream, MutableBufferSequence, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>( stream, buffers, completion_condition, handler)( asio::error_code(), 0, 1); } + + template <typename AsyncReadStream> + class initiate_async_read + { + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence, + typename CompletionCondition> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_read_op(stream_, buffers, + asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + + private: + AsyncReadStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename MutableBufferSequence, +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, - typename ReadHandler, typename Allocator> -struct associated_allocator< + typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>, - Allocator> + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get( + static typename Associator<ReadHandler, DefaultCandidate>::type get( const detail::read_op<AsyncReadStream, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + MutableBufferIterator, CompletionCondition, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename AsyncReadStream, typename MutableBufferSequence, - typename MutableBufferIterator, typename CompletionCondition, - typename ReadHandler, typename Executor> -struct associated_executor< - detail::read_op<AsyncReadStream, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>, - Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - - static type get( + static auto get( const detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< +template <typename AsyncReadStream, + typename MutableBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadToken&& token, + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type*) + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read<AsyncReadStream>>(), token, buffers, + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_read_buffer_sequence_op(s, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read<AsyncReadStream>(s), token, buffers, + static_cast<CompletionCondition&&>(completion_condition)); } template <typename AsyncReadStream, typename MutableBufferSequence, - typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, + const MutableBufferSequence& buffers, ReadToken&& token, + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type*) + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read<AsyncReadStream>>(), + token, buffers, transfer_all())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_read_buffer_sequence_op(s, buffers, - asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read<AsyncReadStream>(s), + token, buffers, transfer_all()); } +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + namespace detail { - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> - class read_dynbuf_op - : detail::base_from_completion_cond<CompletionCondition> + class read_dynbuf_v1_op + : public base_from_cancellation_state<ReadHandler>, + base_from_completion_cond<CompletionCondition> { public: template <typename BufferSequence> - read_dynbuf_op(AsyncReadStream& stream, - ASIO_MOVE_ARG(BufferSequence) buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), + read_dynbuf_v1_op(AsyncReadStream& stream, + BufferSequence&& buffers, + CompletionCondition& completion_condition, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + base_from_completion_cond<CompletionCondition>(completion_condition), stream_(stream), - buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + buffers_(static_cast<BufferSequence&&>(buffers)), start_(0), total_transferred_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - read_dynbuf_op(const read_dynbuf_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + read_dynbuf_v1_op(const read_dynbuf_v1_op& other) + : base_from_cancellation_state<ReadHandler>(other), + base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), @@ -487,18 +575,20 @@ namespace detail { } - read_dynbuf_op(read_dynbuf_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + read_dynbuf_v1_op(read_dynbuf_v1_op&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + base_from_completion_cond<CompletionCondition>( + static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), stream_(other.stream_), - buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)), start_(other.start_), total_transferred_(other.total_transferred_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size, bytes_available; @@ -513,8 +603,11 @@ namespace detail buffers_.max_size() - buffers_.size())); for (;;) { - stream_.async_read_some(buffers_.prepare(bytes_available), - ASIO_MOVE_CAST(read_dynbuf_op)(*this)); + { + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); + stream_.async_read_some(buffers_.prepare(bytes_available), + static_cast<read_dynbuf_v1_op&&>(*this)); + } return; default: total_transferred_ += bytes_transferred; buffers_.commit(bytes_transferred); @@ -526,44 +619,31 @@ namespace detail buffers_.max_size() - buffers_.size())); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } } - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + static_cast<ReadHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), + static_cast<const std::size_t&>(total_transferred_)); } } //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; int start_; std::size_t total_transferred_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename DynamicBuffer, - typename CompletionCondition, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, - CompletionCondition, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncReadStream, typename DynamicBuffer, - typename CompletionCondition, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, - CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( - read_dynbuf_op<AsyncReadStream, DynamicBuffer, + read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true @@ -571,142 +651,400 @@ namespace detail this_handler->handler_); } - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename CompletionCondition, - typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, - CompletionCondition, ReadHandler>* this_handler) + template <typename AsyncReadStream> + class initiate_async_read_dynbuf_v1 { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncReadStream::executor_type executor_type; - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename CompletionCondition, - typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, - CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_read_dynbuf_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v1, + typename CompletionCondition> + void operator()(ReadHandler&& handler, + DynamicBuffer_v1&& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + read_dynbuf_v1_op<AsyncReadStream, decay_t<DynamicBuffer_v1>, + CompletionCondition, decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v1&&>(buffers), + completion_cond2.value, handler2.value)( + asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, - typename CompletionCondition, typename ReadHandler, typename Allocator> -struct associated_allocator< - detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>, - Allocator> +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v1, + typename CompletionCondition, typename ReadHandler, + typename DefaultCandidate> +struct associator<Associator, + detail::read_dynbuf_v1_op<AsyncReadStream, + DynamicBuffer_v1, CompletionCondition, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get( - const detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, + CompletionCondition, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename AsyncReadStream, typename DynamicBuffer, - typename CompletionCondition, typename ReadHandler, typename Executor> -struct associated_executor< - detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>, - Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - - static type get( - const detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get( + const detail::read_dynbuf_v1_op<AsyncReadStream, + DynamicBuffer_v1, CompletionCondition, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) +template <typename AsyncReadStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, + DynamicBuffer_v1&& buffers, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), transfer_all())) { - return async_read(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), - transfer_all(), ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), transfer_all()); } -template <typename AsyncReadStream, typename DynamicBuffer, - typename CompletionCondition, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) +template <typename AsyncReadStream, + typename DynamicBuffer_v1, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, DynamicBuffer_v1&& buffers, + CompletionCondition completion_condition, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_dynbuf_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - CompletionCondition, ASIO_HANDLER_TYPE( - ReadHandler, void (asio::error_code, std::size_t))>( - s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, init.completion_handler)( - asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition)); } #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, - ASIO_MOVE_ARG(ReadHandler) handler) +template <typename AsyncReadStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, + basic_streambuf<Allocator>& b, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), transfer_all())) { - return async_read(s, basic_streambuf_ref<Allocator>(b), - ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s), + token, basic_streambuf_ref<Allocator>(b), transfer_all()); } -template <typename AsyncReadStream, typename Allocator, - typename CompletionCondition, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler) +template <typename AsyncReadStream, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition))) { - return async_read(s, basic_streambuf_ref<Allocator>(b), - completion_condition, ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s), + token, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition)); } #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler> + class read_dynbuf_v2_op + : public base_from_cancellation_state<ReadHandler>, + base_from_completion_cond<CompletionCondition> + { + public: + template <typename BufferSequence> + read_dynbuf_v2_op(AsyncReadStream& stream, + BufferSequence&& buffers, + CompletionCondition& completion_condition, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + base_from_completion_cond<CompletionCondition>(completion_condition), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), + start_(0), + total_transferred_(0), + bytes_available_(0), + handler_(static_cast<ReadHandler&&>(handler)) + { + } + + read_dynbuf_v2_op(const read_dynbuf_v2_op& other) + : base_from_cancellation_state<ReadHandler>(other), + base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + total_transferred_(other.total_transferred_), + bytes_available_(other.bytes_available_), + handler_(other.handler_) + { + } + + read_dynbuf_v2_op(read_dynbuf_v2_op&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + base_from_completion_cond<CompletionCondition>( + static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)), + start_(other.start_), + total_transferred_(other.total_transferred_), + bytes_available_(other.bytes_available_), + handler_(static_cast<ReadHandler&&>(other.handler_)) + { + } + + void operator()(asio::error_code ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, pos; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); + for (;;) + { + pos = buffers_.size(); + buffers_.grow(bytes_available_); + { + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); + stream_.async_read_some(buffers_.data(pos, bytes_available_), + static_cast<read_dynbuf_v2_op&&>(*this)); + } + return; default: + total_transferred_ += bytes_transferred; + buffers_.shrink(bytes_available_ - bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); + if ((!ec && bytes_transferred == 0) || bytes_available_ == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } + } + + static_cast<ReadHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), + static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + int start_; + std::size_t total_transferred_; + std::size_t bytes_available_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, + CompletionCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename AsyncReadStream> + class initiate_async_read_dynbuf_v2 + { + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_dynbuf_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v2, + typename CompletionCondition> + void operator()(ReadHandler&& handler, + DynamicBuffer_v2&& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + read_dynbuf_v2_op<AsyncReadStream, decay_t<DynamicBuffer_v2>, + CompletionCondition, decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v2&&>(buffers), + completion_cond2.value, handler2.value)( + asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler, + typename DefaultCandidate> +struct associator<Associator, + detail::read_dynbuf_v2_op<AsyncReadStream, + DynamicBuffer_v2, CompletionCondition, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> +{ + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, + CompletionCondition, ReadHandler>& h) noexcept + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); + } + + static auto get( + const detail::read_dynbuf_v2_op<AsyncReadStream, + DynamicBuffer_v2, CompletionCondition, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, + DynamicBuffer_v2 buffers, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), transfer_all())) +{ + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v2<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), transfer_all()); +} + +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))) +{ + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v2<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition)); +} } // namespace asio diff --git a/3rdparty/asio/include/asio/impl/read_at.hpp b/3rdparty/asio/include/asio/impl/read_at.hpp index 273312f139f..7c668a03f46 100644 --- a/3rdparty/asio/include/asio/impl/read_at.hpp +++ b/3rdparty/asio/include/asio/impl/read_at.hpp @@ -2,7 +2,7 @@ // impl/read_at.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,19 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <algorithm> -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" +#include "asio/associator.hpp" #include "asio/buffer.hpp" -#include "asio/completion_condition.hpp" #include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/dependent_type.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_tracking.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" @@ -59,7 +58,7 @@ namespace detail else break; } - return tmp.total_consumed();; + return tmp.total_consumed(); } } // namespace detail @@ -70,7 +69,8 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, CompletionCondition completion_condition, asio::error_code& ec) { return detail::read_at_buffer_sequence(d, offset, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, ec); + asio::buffer_sequence_begin(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); } template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> @@ -99,8 +99,8 @@ inline std::size_t read_at(SyncRandomAccessReadDevice& d, CompletionCondition completion_condition) { asio::error_code ec; - std::size_t bytes_transferred = read_at( - d, offset, buffers, completion_condition, ec); + std::size_t bytes_transferred = read_at(d, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "read_at"); return bytes_transferred; } @@ -158,8 +158,8 @@ inline std::size_t read_at(SyncRandomAccessReadDevice& d, CompletionCondition completion_condition) { asio::error_code ec; - std::size_t bytes_transferred = read_at( - d, offset, b, completion_condition, ec); + std::size_t bytes_transferred = read_at(d, offset, b, + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "read_at"); return bytes_transferred; } @@ -173,25 +173,27 @@ namespace detail typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> class read_at_op - : detail::base_from_completion_cond<CompletionCondition> + : public base_from_cancellation_state<ReadHandler>, + base_from_completion_cond<CompletionCondition> { public: read_at_op(AsyncRandomAccessReadDevice& device, uint64_t offset, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), + CompletionCondition& completion_condition, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + base_from_completion_cond<CompletionCondition>(completion_condition), device_(device), offset_(offset), buffers_(buffers), start_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) read_at_op(const read_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<ReadHandler>(other), + base_from_completion_cond<CompletionCondition>(other), device_(other.device_), offset_(other.offset_), buffers_(other.buffers_), @@ -201,17 +203,19 @@ namespace detail } read_at_op(read_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + base_from_completion_cond<CompletionCondition>( + static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), device_(other.device_), offset_(other.offset_), - buffers_(other.buffers_), + buffers_(static_cast<buffers_type&&>(other.buffers_)), start_(other.start_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size; @@ -219,27 +223,41 @@ namespace detail { case 1: max_size = this->check_for_completion(ec, buffers_.total_consumed()); - do + for (;;) { - device_.async_read_some_at( - offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), - ASIO_MOVE_CAST(read_at_op)(*this)); + { + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at")); + device_.async_read_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + static_cast<read_at_op&&>(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; max_size = this->check_for_completion(ec, buffers_.total_consumed()); - } while (max_size > 0); + if (max_size == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = asio::error::operation_aborted; + break; + } + } - handler_(ec, buffers_.total_consumed()); + static_cast<ReadHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), + static_cast<const std::size_t&>(buffers_.total_consumed())); } } //private: + typedef asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_type; + AsyncRandomAccessReadDevice& device_; uint64_t offset_; - asio::detail::consuming_buffers<mutable_buffer, - MutableBufferSequence, MutableBufferIterator> buffers_; + buffers_type buffers_; int start_; ReadHandler handler_; }; @@ -247,28 +265,6 @@ namespace detail template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) @@ -278,34 +274,12 @@ namespace detail this_handler->handler_); } - template <typename Function, typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - - template <typename Function, typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> - inline void start_read_at_buffer_sequence_op(AsyncRandomAccessReadDevice& d, + inline void start_read_at_op(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, - const MutableBufferIterator&, CompletionCondition completion_condition, + const MutableBufferIterator&, CompletionCondition& completion_condition, ReadHandler& handler) { detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, @@ -313,95 +287,114 @@ namespace detail d, offset, buffers, completion_condition, handler)( asio::error_code(), 0, 1); } + + template <typename AsyncRandomAccessReadDevice> + class initiate_async_read_at + { + public: + typedef typename AsyncRandomAccessReadDevice::executor_type executor_type; + + explicit initiate_async_read_at(AsyncRandomAccessReadDevice& device) + : device_(device) + { + } + + executor_type get_executor() const noexcept + { + return device_.get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence, + typename CompletionCondition> + void operator()(ReadHandler&& handler, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_read_at_op(device_, offset, buffers, + asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + + private: + AsyncRandomAccessReadDevice& device_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler, typename Allocator> -struct associated_allocator< +template <template <typename, typename> class Associator, + typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>, - Allocator> + MutableBufferIterator, CompletionCondition, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get( + static typename Associator<ReadHandler, DefaultCandidate>::type get( const detail::read_at_op<AsyncRandomAccessReadDevice, - MutableBufferSequence, MutableBufferIterator, - CompletionCondition, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename MutableBufferIterator, - typename CompletionCondition, typename ReadHandler, typename Executor> -struct associated_executor< - detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - MutableBufferIterator, CompletionCondition, ReadHandler>, - Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - static type get( + static auto get( const detail::read_at_op<AsyncRandomAccessReadDevice, - MutableBufferSequence, MutableBufferIterator, - CompletionCondition, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, +template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler) + CompletionCondition completion_condition, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at<AsyncRandomAccessReadDevice>>(), + token, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_read_at_buffer_sequence_op(d, offset, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_at<AsyncRandomAccessReadDevice>(d), + token, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition)); } template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, - typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, - uint64_t offset, const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at<AsyncRandomAccessReadDevice>>(), + token, offset, buffers, transfer_all())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_read_at_buffer_sequence_op(d, offset, buffers, - asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_at<AsyncRandomAccessReadDevice>(d), + token, offset, buffers, transfer_all()); } #if !defined(ASIO_NO_EXTENSIONS) @@ -412,26 +405,28 @@ namespace detail template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> class read_at_streambuf_op - : detail::base_from_completion_cond<CompletionCondition> + : public base_from_cancellation_state<ReadHandler>, + base_from_completion_cond<CompletionCondition> { public: read_at_streambuf_op(AsyncRandomAccessReadDevice& device, uint64_t offset, basic_streambuf<Allocator>& streambuf, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), + CompletionCondition& completion_condition, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + base_from_completion_cond<CompletionCondition>(completion_condition), device_(device), offset_(offset), streambuf_(streambuf), start_(0), total_transferred_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) read_at_streambuf_op(const read_at_streambuf_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<ReadHandler>(other), + base_from_completion_cond<CompletionCondition>(other), device_(other.device_), offset_(other.offset_), streambuf_(other.streambuf_), @@ -442,18 +437,20 @@ namespace detail } read_at_streambuf_op(read_at_streambuf_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + base_from_completion_cond<CompletionCondition>( + static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), device_(other.device_), offset_(other.offset_), streambuf_(other.streambuf_), start_(other.start_), total_transferred_(other.total_transferred_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size, bytes_available; @@ -464,9 +461,12 @@ namespace detail bytes_available = read_size_helper(streambuf_, max_size); for (;;) { - device_.async_read_some_at(offset_ + total_transferred_, - streambuf_.prepare(bytes_available), - ASIO_MOVE_CAST(read_at_streambuf_op)(*this)); + { + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at")); + device_.async_read_some_at(offset_ + total_transferred_, + streambuf_.prepare(bytes_available), + static_cast<read_at_streambuf_op&&>(*this)); + } return; default: total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); @@ -474,9 +474,16 @@ namespace detail bytes_available = read_size_helper(streambuf_, max_size); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; + if (this->cancelled() != cancellation_type::none) + { + ec = asio::error::operation_aborted; + break; + } } - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + static_cast<ReadHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), + static_cast<const std::size_t&>(total_transferred_)); } } @@ -491,26 +498,6 @@ namespace detail template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - CompletionCondition, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncRandomAccessReadDevice, typename Allocator, - typename CompletionCondition, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncRandomAccessReadDevice, typename Allocator, - typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>* this_handler) @@ -520,114 +507,115 @@ namespace detail this_handler->handler_); } - template <typename Function, typename AsyncRandomAccessReadDevice, - typename Allocator, typename CompletionCondition, typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - CompletionCondition, ReadHandler>* this_handler) + template <typename AsyncRandomAccessReadDevice> + class initiate_async_read_at_streambuf { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncRandomAccessReadDevice::executor_type executor_type; + + explicit initiate_async_read_at_streambuf( + AsyncRandomAccessReadDevice& device) + : device_(device) + { + } - template <typename Function, typename AsyncRandomAccessReadDevice, - typename Allocator, typename CompletionCondition, typename ReadHandler> - inline void asio_handler_invoke(const Function& function, + executor_type get_executor() const noexcept + { + return device_.get_executor(); + } + + template <typename ReadHandler, + typename Allocator, typename CompletionCondition> + void operator()(ReadHandler&& handler, + uint64_t offset, basic_streambuf<Allocator>* b, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - CompletionCondition, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + CompletionCondition, decay_t<ReadHandler>>( + device_, offset, *b, completion_cond2.value, handler2.value)( + asio::error_code(), 0, 1); + } + + private: + AsyncRandomAccessReadDevice& device_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncRandomAccessReadDevice, typename Allocator, - typename CompletionCondition, typename ReadHandler, typename Allocator1> -struct associated_allocator< +template <template <typename, typename> class Associator, + typename AsyncRandomAccessReadDevice, typename Executor, + typename CompletionCondition, typename ReadHandler, + typename DefaultCandidate> +struct associator<Associator, detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, - Allocator, CompletionCondition, ReadHandler>, - Allocator1> + Executor, CompletionCondition, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator1>::type type; - - static type get( + static typename Associator<ReadHandler, DefaultCandidate>::type get( const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, - Allocator, CompletionCondition, ReadHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + Executor, CompletionCondition, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename AsyncRandomAccessReadDevice, typename Executor, - typename CompletionCondition, typename ReadHandler, typename Executor1> -struct associated_executor< - detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, - Executor, CompletionCondition, ReadHandler>, - Executor1> -{ - typedef typename associated_executor<ReadHandler, Executor1>::type type; - - static type get( + static auto get( const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Executor, CompletionCondition, ReadHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncRandomAccessReadDevice, typename Allocator, - typename CompletionCondition, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, +template <typename AsyncRandomAccessReadDevice, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, asio::basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler) + CompletionCondition completion_condition, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at_streambuf< + AsyncRandomAccessReadDevice>>(), + token, offset, &b, + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - CompletionCondition, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - d, offset, b, completion_condition, init.completion_handler)( - asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d), + token, offset, &b, + static_cast<CompletionCondition&&>(completion_condition)); } template <typename AsyncRandomAccessReadDevice, typename Allocator, - typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, - uint64_t offset, asio::basic_streambuf<Allocator>& b, - ASIO_MOVE_ARG(ReadHandler) handler) + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, + asio::basic_streambuf<Allocator>& b, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at_streambuf< + AsyncRandomAccessReadDevice>>(), + token, offset, &b, transfer_all())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - detail::transfer_all_t, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - d, offset, b, transfer_all(), init.completion_handler)( - asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d), + token, offset, &b, transfer_all()); } #endif // !defined(ASIO_NO_IOSTREAM) diff --git a/3rdparty/asio/include/asio/impl/read_until.hpp b/3rdparty/asio/include/asio/impl/read_until.hpp index c0a435e63b8..7592263723f 100644 --- a/3rdparty/asio/include/asio/impl/read_until.hpp +++ b/3rdparty/asio/include/asio/impl/read_until.hpp @@ -2,7 +2,7 @@ // impl/read_until.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,46 +19,95 @@ #include <string> #include <vector> #include <utility> -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" +#include "asio/associator.hpp" #include "asio/buffer.hpp" #include "asio/buffers_iterator.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" #include "asio/detail/bind_handler.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_tracking.hpp" #include "asio/detail/handler_type_requirements.hpp" #include "asio/detail/limits.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { -template <typename SyncReadStream, typename DynamicBuffer> +namespace detail +{ + // Algorithm that finds a subsequence of equal values in a sequence. Returns + // (iterator,true) if a full match was found, in which case the iterator + // points to the beginning of the match. Returns (iterator,false) if a + // partial match was found at the end of the first sequence, in which case + // the iterator points to the beginning of the partial match. Returns + // (last1,false) if no full or partial match was found. + template <typename Iterator1, typename Iterator2> + std::pair<Iterator1, bool> partial_search( + Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + { + for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) + { + Iterator1 test_iter1 = iter1; + Iterator2 test_iter2 = first2; + for (;; ++test_iter1, ++test_iter2) + { + if (test_iter2 == last2) + return std::make_pair(iter1, true); + if (test_iter1 == last1) + { + if (test_iter2 != first2) + return std::make_pair(iter1, false); + else + break; + } + if (*test_iter1 != *test_iter2) + break; + } + } + return std::make_pair(last1, false); + } +} // namespace detail + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim) + DynamicBuffer_v1&& buffers, char delim, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); + static_cast<DynamicBuffer_v1&&>(buffers), delim, ec); asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - char delim, asio::error_code& ec) + DynamicBuffer_v1&& buffers, + char delim, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - typename decay<DynamicBuffer>::type b( - ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + decay_t<DynamicBuffer_v1> b( + static_cast<DynamicBuffer_v1&&>(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -96,66 +145,43 @@ std::size_t read_until(SyncReadStream& s, } } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_STRING_VIEW_PARAM delim) + DynamicBuffer_v1&& buffers, + ASIO_STRING_VIEW_PARAM delim, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); + static_cast<DynamicBuffer_v1&&>(buffers), delim, ec); asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -namespace detail -{ - // Algorithm that finds a subsequence of equal values in a sequence. Returns - // (iterator,true) if a full match was found, in which case the iterator - // points to the beginning of the match. Returns (iterator,false) if a - // partial match was found at the end of the first sequence, in which case - // the iterator points to the beginning of the partial match. Returns - // (last1,false) if no full or partial match was found. - template <typename Iterator1, typename Iterator2> - std::pair<Iterator1, bool> partial_search( - Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) - { - for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) - { - Iterator1 test_iter1 = iter1; - Iterator2 test_iter2 = first2; - for (;; ++test_iter1, ++test_iter2) - { - if (test_iter2 == last2) - return std::make_pair(iter1, true); - if (test_iter1 == last1) - { - if (test_iter2 != first2) - return std::make_pair(iter1, false); - else - break; - } - if (*test_iter1 != *test_iter2) - break; - } - } - return std::make_pair(last1, false); - } -} // namespace detail - -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec) + DynamicBuffer_v1&& buffers, + ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - typename decay<DynamicBuffer>::type b( - ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + decay_t<DynamicBuffer_v1> b( + static_cast<DynamicBuffer_v1&&>(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -205,31 +231,54 @@ std::size_t read_until(SyncReadStream& s, #if !defined(ASIO_NO_EXTENSIONS) #if defined(ASIO_HAS_BOOST_REGEX) -template <typename SyncReadStream, typename DynamicBuffer> -inline std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr) +namespace detail { + +struct regex_match_flags +{ + template <typename T> + operator T() const + { + return T::match_default | T::match_partial; + } +}; + +} // namespace detail + +template <typename SyncReadStream, typename DynamicBuffer_v1, typename Traits> +inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v1&& buffers, + const boost::basic_regex<char, Traits>& expr, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), expr, ec); + static_cast<DynamicBuffer_v1&&>(buffers), expr, ec); asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> -std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr, asio::error_code& ec) +template <typename SyncReadStream, typename DynamicBuffer_v1, typename Traits> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v1&& buffers, + const boost::basic_regex<char, Traits>& expr, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - typename decay<DynamicBuffer>::type b( - ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + decay_t<DynamicBuffer_v1> b( + static_cast<DynamicBuffer_v1&&>(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -238,10 +287,10 @@ std::size_t read_until(SyncReadStream& s, // Look for a match. boost::match_results<iterator, - typename std::vector<boost::sub_match<iterator> >::allocator_type> + typename std::vector<boost::sub_match<iterator>>::allocator_type> match_results; - if (regex_search(start_pos, end, match_results, expr, - boost::match_default | boost::match_partial)) + if (regex_search(start_pos, end, match_results, + expr, detail::regex_match_flags())) { if (match_results[0].matched) { @@ -269,7 +318,9 @@ std::size_t read_until(SyncReadStream& s, } // Need more data. - std::size_t bytes_to_read = read_size_helper(b, 65536); + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; @@ -279,35 +330,51 @@ std::size_t read_until(SyncReadStream& s, #endif // defined(ASIO_HAS_BOOST_REGEX) template <typename SyncReadStream, - typename DynamicBuffer, typename MatchCondition> + typename DynamicBuffer_v1, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, MatchCondition match_condition, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) + constraint_t< + is_match_condition<MatchCondition>::value + >, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), + static_cast<DynamicBuffer_v1&&>(buffers), match_condition, ec); asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } template <typename SyncReadStream, - typename DynamicBuffer, typename MatchCondition> + typename DynamicBuffer_v1, typename MatchCondition> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, MatchCondition match_condition, asio::error_code& ec, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) + constraint_t< + is_match_condition<MatchCondition>::value + >, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - typename decay<DynamicBuffer>::type b( - ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + decay_t<DynamicBuffer_v1> b( + static_cast<DynamicBuffer_v1&&>(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -385,16 +452,18 @@ inline std::size_t read_until(SyncReadStream& s, #if defined(ASIO_HAS_BOOST_REGEX) -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename Allocator, typename Traits> inline std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr) + asio::basic_streambuf<Allocator>& b, + const boost::basic_regex<char, Traits>& expr) { return read_until(s, basic_streambuf_ref<Allocator>(b), expr); } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename Allocator, typename Traits> inline std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + asio::basic_streambuf<Allocator>& b, + const boost::basic_regex<char, Traits>& expr, asio::error_code& ec) { return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec); @@ -405,7 +474,7 @@ inline std::size_t read_until(SyncReadStream& s, template <typename SyncReadStream, typename Allocator, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) + constraint_t<is_match_condition<MatchCondition>::value>) { return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition); } @@ -414,37 +483,360 @@ template <typename SyncReadStream, typename Allocator, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, asio::error_code& ec, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) + constraint_t<is_match_condition<MatchCondition>::value>) { return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec); } #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, char delim, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + static_cast<DynamicBuffer_v2&&>(buffers), delim, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim); + if (iter != end) + { + // Found a match. We're done. + ec = asio::error_code(); + return iter - begin + 1; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, ASIO_STRING_VIEW_PARAM delim, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + static_cast<DynamicBuffer_v2&&>(buffers), delim, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = detail::partial_search( + start_pos, end, delim.begin(), delim.end()); + if (result.first != end) + { + if (result.second) + { + // Full match. We're done. + ec = asio::error_code(); + return result.first - begin + delim.length(); + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if defined(ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, typename DynamicBuffer_v2, typename Traits> +inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::basic_regex<char, Traits>& expr, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + static_cast<DynamicBuffer_v2&&>(buffers), expr, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2, typename Traits> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::basic_regex<char, Traits>& expr, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results<iterator, + typename std::vector<boost::sub_match<iterator>>::allocator_type> + match_results; + if (regex_search(start_pos, end, match_results, + expr, detail::regex_match_flags())) + { + if (match_results[0].matched) + { + // Full match. We're done. + ec = asio::error_code(); + return match_results[0].second - begin; + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = match_results[0].first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, MatchCondition match_condition, + constraint_t< + is_match_condition<MatchCondition>::value + >, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + static_cast<DynamicBuffer_v2&&>(buffers), + match_condition, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, asio::error_code& ec, + constraint_t< + is_match_condition<MatchCondition>::value + >, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = match_condition(start_pos, end); + if (result.second) + { + // Full match. We're done. + ec = asio::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#endif // !defined(ASIO_NO_EXTENSIONS) + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) namespace detail { template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - class read_until_delim_op + typename DynamicBuffer_v1, typename ReadHandler> + class read_until_delim_op_v1 + : public base_from_cancellation_state<ReadHandler> { public: template <typename BufferSequence> - read_until_delim_op(AsyncReadStream& stream, - ASIO_MOVE_ARG(BufferSequence) buffers, + read_until_delim_op_v1(AsyncReadStream& stream, + BufferSequence&& buffers, char delim, ReadHandler& handler) - : stream_(stream), - buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), delim_(delim), start_(0), search_position_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - read_until_delim_op(const read_until_delim_op& other) - : stream_(other.stream_), + read_until_delim_op_v1(const read_until_delim_op_v1& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), buffers_(other.buffers_), delim_(other.delim_), start_(other.start_), @@ -453,18 +845,19 @@ namespace detail { } - read_until_delim_op(read_until_delim_op&& other) - : stream_(other.stream_), - buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + read_until_delim_op_v1(read_until_delim_op_v1&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); @@ -476,7 +869,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -518,12 +911,21 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - ASIO_MOVE_CAST(read_until_delim_op)(*this)); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + static_cast<read_until_delim_op_v1&&>(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } } const asio::error_code result_ec = @@ -534,13 +936,13 @@ namespace detail (ec || search_position_ == not_found) ? 0 : search_position_; - handler_(result_ec, result_n); + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); } } //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; char delim_; int start_; std::size_t search_position_; @@ -548,145 +950,133 @@ namespace detail }; template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + template <typename AsyncReadStream> + class initiate_async_read_until_delim_v1 { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncReadStream::executor_type executor_type; - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_read_until_delim_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v1> + void operator()(ReadHandler&& handler, + DynamicBuffer_v1&& buffers, + char delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_op_v1<AsyncReadStream, + decay_t<DynamicBuffer_v1>, + decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v1&&>(buffers), + delim, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, - typename ReadHandler, typename Allocator> -struct associated_allocator< - detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, - Allocator> +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v1, + typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get( - const detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename AsyncReadStream, typename DynamicBuffer, - typename ReadHandler, typename Executor> -struct associated_executor< - detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, - Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - - static type get( - const detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get( + const detail::read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - char delim, ASIO_MOVE_ARG(ReadHandler) handler) +template <typename AsyncReadStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, + DynamicBuffer_v1&& buffers, char delim, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), delim)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_until_delim_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), - delim, init.completion_handler)(asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), delim); } namespace detail { template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - class read_until_delim_string_op + typename DynamicBuffer_v1, typename ReadHandler> + class read_until_delim_string_op_v1 + : public base_from_cancellation_state<ReadHandler> { public: template <typename BufferSequence> - read_until_delim_string_op(AsyncReadStream& stream, - ASIO_MOVE_ARG(BufferSequence) buffers, + read_until_delim_string_op_v1(AsyncReadStream& stream, + BufferSequence&& buffers, const std::string& delim, ReadHandler& handler) - : stream_(stream), - buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), delim_(delim), start_(0), search_position_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - read_until_delim_string_op(const read_until_delim_string_op& other) - : stream_(other.stream_), + read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), buffers_(other.buffers_), delim_(other.delim_), start_(other.start_), @@ -695,18 +1085,19 @@ namespace detail { } - read_until_delim_string_op(read_until_delim_string_op&& other) - : stream_(other.stream_), - buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), - delim_(ASIO_MOVE_CAST(std::string)(other.delim_)), + read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)), + delim_(static_cast<std::string&&>(other.delim_)), start_(other.start_), search_position_(other.search_position_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); @@ -718,7 +1109,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -771,12 +1162,21 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - ASIO_MOVE_CAST(read_until_delim_string_op)(*this)); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + static_cast<read_until_delim_string_op_v1&&>(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } } const asio::error_code result_ec = @@ -787,13 +1187,13 @@ namespace detail (ec || search_position_ == not_found) ? 0 : search_position_; - handler_(result_ec, result_n); + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); } } //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; std::string delim_; int start_; std::size_t search_position_; @@ -801,122 +1201,108 @@ namespace detail }; template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + template <typename AsyncReadStream> + class initiate_async_read_until_delim_string_v1 { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncReadStream::executor_type executor_type; - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v1> + void operator()(ReadHandler&& handler, + DynamicBuffer_v1&& buffers, + const std::string& delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_string_op_v1<AsyncReadStream, + decay_t<DynamicBuffer_v1>, + decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v1&&>(buffers), + delim, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, - typename ReadHandler, typename Allocator> -struct associated_allocator< - detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, - Allocator> +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v1, + typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get( - const detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_delim_string_op_v1< + AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename AsyncReadStream, typename DynamicBuffer, - typename ReadHandler, typename Executor> -struct associated_executor< - detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, - Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - static type get( - const detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get( + const detail::read_until_delim_string_op_v1< + AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_STRING_VIEW_PARAM delim, - ASIO_MOVE_ARG(ReadHandler) handler) +template <typename AsyncReadStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v1&& buffers, + ASIO_STRING_VIEW_PARAM delim, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_string_v1< + AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<std::string>(delim))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_until_delim_string_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), - static_cast<std::string>(delim), - init.completion_handler)(asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<std::string>(delim)); } #if !defined(ASIO_NO_EXTENSIONS) @@ -924,27 +1310,29 @@ async_read_until(AsyncReadStream& s, namespace detail { - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> - class read_until_expr_op + class read_until_expr_op_v1 + : public base_from_cancellation_state<ReadHandler> { public: - template <typename BufferSequence> - read_until_expr_op(AsyncReadStream& stream, - ASIO_MOVE_ARG(BufferSequence) buffers, - const boost::regex& expr, ReadHandler& handler) - : stream_(stream), - buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + template <typename BufferSequence, typename Traits> + read_until_expr_op_v1(AsyncReadStream& stream, BufferSequence&& buffers, + const boost::basic_regex<char, Traits>& expr, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), expr_(expr), start_(0), search_position_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - read_until_expr_op(const read_until_expr_op& other) - : stream_(other.stream_), + read_until_expr_op_v1(const read_until_expr_op_v1& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), buffers_(other.buffers_), expr_(other.expr_), start_(other.start_), @@ -953,18 +1341,19 @@ namespace detail { } - read_until_expr_op(read_until_expr_op&& other) - : stream_(other.stream_), - buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + read_until_expr_op_v1(read_until_expr_op_v1&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)), expr_(other.expr_), start_(other.start_), search_position_(other.search_position_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); @@ -976,7 +1365,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -986,10 +1375,10 @@ namespace detail // Look for a match. boost::match_results<iterator, - typename std::vector<boost::sub_match<iterator> >::allocator_type> + typename std::vector<boost::sub_match<iterator>>::allocator_type> match_results; - bool match = regex_search(start_pos, end, match_results, expr_, - boost::match_default | boost::match_partial); + bool match = regex_search(start_pos, end, + match_results, expr_, regex_match_flags()); if (match && match_results[0].matched) { // Full match. We're done. @@ -1032,12 +1421,21 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - ASIO_MOVE_CAST(read_until_expr_op)(*this)); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + static_cast<read_until_expr_op_v1&&>(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } } const asio::error_code result_ec = @@ -1048,162 +1446,148 @@ namespace detail (ec || search_position_ == not_found) ? 0 : search_position_; - handler_(result_ec, result_n); + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); } } //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; RegEx expr_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename DynamicBuffer, - typename RegEx, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncReadStream, typename DynamicBuffer, - typename RegEx, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) + read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename RegEx, typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) + template <typename AsyncReadStream> + class initiate_async_read_until_expr_v1 { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncReadStream::executor_type executor_type; - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename RegEx, typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v1, typename RegEx> + void operator()(ReadHandler&& handler, + DynamicBuffer_v1&& buffers, const RegEx& expr) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_expr_op_v1<AsyncReadStream, + decay_t<DynamicBuffer_v1>, + RegEx, decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v1&&>(buffers), + expr, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, - typename RegEx, typename ReadHandler, typename Allocator> -struct associated_allocator< - detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>, - Allocator> +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v1, + typename RegEx, typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; - - static type get( - const detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>& h) noexcept { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename AsyncReadStream, typename DynamicBuffer, - typename RegEx, typename ReadHandler, typename Executor> -struct associated_executor< - detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>, - Executor> -{ - typedef typename associated_executor<ReadHandler, Executor>::type type; - - static type get( - const detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get( + const detail::read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr, - ASIO_MOVE_ARG(ReadHandler) handler) +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename Traits, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v1&& buffers, + const boost::basic_regex<char, Traits>& expr, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_expr_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), expr)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_until_expr_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - boost::regex, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), - expr, init.completion_handler)(asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), expr); } #endif // defined(ASIO_HAS_BOOST_REGEX) namespace detail { - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> - class read_until_match_op + class read_until_match_op_v1 + : public base_from_cancellation_state<ReadHandler> { public: template <typename BufferSequence> - read_until_match_op(AsyncReadStream& stream, - ASIO_MOVE_ARG(BufferSequence) buffers, + read_until_match_op_v1(AsyncReadStream& stream, + BufferSequence&& buffers, MatchCondition match_condition, ReadHandler& handler) - : stream_(stream), - buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), match_condition_(match_condition), start_(0), search_position_(0), - handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + handler_(static_cast<ReadHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - read_until_match_op(const read_until_match_op& other) - : stream_(other.stream_), + read_until_match_op_v1(const read_until_match_op_v1& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), buffers_(other.buffers_), match_condition_(other.match_condition_), start_(other.start_), @@ -1212,18 +1596,19 @@ namespace detail { } - read_until_match_op(read_until_match_op&& other) - : stream_(other.stream_), - buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + read_until_match_op_v1(read_until_match_op_v1&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)), match_condition_(other.match_condition_), start_(other.start_), search_position_(other.search_position_), - handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + handler_(static_cast<ReadHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); @@ -1235,7 +1620,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -1287,12 +1672,21 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - ASIO_MOVE_CAST(read_until_match_op)(*this)); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + static_cast<read_until_match_op_v1&&>(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } } const asio::error_code result_ec = @@ -1303,194 +1697,1241 @@ namespace detail (ec || search_position_ == not_found) ? 0 : search_position_; - handler_(result_ec, result_n); + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); } } //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; MatchCondition match_condition_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> - inline void* asio_handler_allocate(std::size_t size, - read_until_match_op<AsyncReadStream, DynamicBuffer, + inline bool asio_handler_is_continuation( + read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, - typename MatchCondition, typename ReadHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_match_op<AsyncReadStream, DynamicBuffer, - MatchCondition, ReadHandler>* this_handler) + template <typename AsyncReadStream> + class initiate_async_read_until_match_v1 { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_match_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, + typename DynamicBuffer_v1, typename MatchCondition> + void operator()(ReadHandler&& handler, + DynamicBuffer_v1&& buffers, + MatchCondition match_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_match_op_v1<AsyncReadStream, + decay_t<DynamicBuffer_v1>, + MatchCondition, decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v1&&>(buffers), + match_condition, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v1, + typename MatchCondition, typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_match_op_v1<AsyncReadStream, + DynamicBuffer_v1, MatchCondition, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> +{ + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_match_op_v1<AsyncReadStream, + DynamicBuffer_v1, MatchCondition, ReadHandler>& h) noexcept + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, - typename MatchCondition, typename ReadHandler> + static auto get( + const detail::read_until_match_op_v1<AsyncReadStream, + DynamicBuffer_v1, MatchCondition, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer_v1, typename MatchCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v1&& buffers, + MatchCondition match_condition, ReadToken&& token, + constraint_t< + is_match_condition<MatchCondition>::value + >, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_match_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + match_condition)) +{ + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_match_v1<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), + match_condition); +} + +#if !defined(ASIO_NO_IOSTREAM) + +template <typename AsyncReadStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), delim)) +{ + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s), + token, basic_streambuf_ref<Allocator>(b), delim); +} + +template <typename AsyncReadStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + ASIO_STRING_VIEW_PARAM delim, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_string_v1< + AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), + static_cast<std::string>(delim))) +{ + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s), + token, basic_streambuf_ref<Allocator>(b), + static_cast<std::string>(delim)); +} + +#if defined(ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, typename Traits, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + const boost::basic_regex<char, Traits>& expr, ReadToken&& token) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_expr_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), expr)) +{ + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s), + token, basic_streambuf_ref<Allocator>(b), expr); +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, typename MatchCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, ReadToken&& token, + constraint_t<is_match_condition<MatchCondition>::value>) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_match_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), match_condition)) +{ + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_match_v1<AsyncReadStream>(s), + token, basic_streambuf_ref<Allocator>(b), match_condition); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + class read_until_delim_op_v2 + : public base_from_cancellation_state<ReadHandler> + { + public: + template <typename BufferSequence> + read_until_delim_op_v2(AsyncReadStream& stream, + BufferSequence&& buffers, + char delim, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), + delim_(delim), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(static_cast<ReadHandler&&>(handler)) + { + } + + read_until_delim_op_v2(const read_until_delim_op_v2& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_delim_op_v2(read_until_delim_op_v2&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(static_cast<ReadHandler&&>(other.handler_)) + { + } + + void operator()(asio::error_code ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim_); + if (iter != end) + { + // Found a match. We're done. + search_position_ = iter - begin + 1; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + // Next search can start with the new data. + search_position_ = end - begin; + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + static_cast<read_until_delim_op_v2&&>(*this)); + } + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + char delim_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_match_op<AsyncReadStream, DynamicBuffer, - MatchCondition, ReadHandler>* this_handler) + read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename MatchCondition, - typename ReadHandler> - inline void asio_handler_invoke(Function& function, - read_until_match_op<AsyncReadStream, DynamicBuffer, - MatchCondition, ReadHandler>* this_handler) + template <typename AsyncReadStream> + class initiate_async_read_until_delim_v2 { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncReadStream::executor_type executor_type; - template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename MatchCondition, - typename ReadHandler> - inline void asio_handler_invoke(const Function& function, - read_until_match_op<AsyncReadStream, DynamicBuffer, - MatchCondition, ReadHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v2> + void operator()(ReadHandler&& handler, + DynamicBuffer_v2&& buffers, char delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_op_v2<AsyncReadStream, + decay_t<DynamicBuffer_v2>, + decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v2&&>(buffers), + delim, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, - typename MatchCondition, typename ReadHandler, typename Allocator> -struct associated_allocator< - detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>, - Allocator> +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v2, + typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - typedef typename associated_allocator<ReadHandler, Allocator>::type type; + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>& h) noexcept + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); + } - static type get( - const detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static auto get( + const detail::read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; -template <typename AsyncReadStream, typename DynamicBuffer, - typename MatchCondition, typename ReadHandler, typename Executor> -struct associated_executor< - detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>, - Executor> +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, + DynamicBuffer_v2 buffers, char delim, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), delim)) { - typedef typename associated_executor<ReadHandler, Executor>::type type; + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_v2<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), delim); +} - static type get( - const detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT +namespace detail +{ + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + class read_until_delim_string_op_v2 + : public base_from_cancellation_state<ReadHandler> { - return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + public: + template <typename BufferSequence> + read_until_delim_string_op_v2(AsyncReadStream& stream, + BufferSequence&& buffers, + const std::string& delim, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), + delim_(delim), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(static_cast<ReadHandler&&>(handler)) + { + } + + read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)), + delim_(static_cast<std::string&&>(other.delim_)), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(static_cast<ReadHandler&&>(other.handler_)) + { + } + + void operator()(asio::error_code ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = detail::partial_search( + start_pos, end, delim_.begin(), delim_.end()); + if (result.first != end && result.second) + { + // Full match. We're done. + search_position_ = result.first - begin + delim_.length(); + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + static_cast<read_until_delim_string_op_v2&&>(*this)); + } + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + std::string delim_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename AsyncReadStream> + class initiate_async_read_until_delim_string_v2 + { + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v2> + void operator()(ReadHandler&& handler, + DynamicBuffer_v2&& buffers, + const std::string& delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_string_op_v2<AsyncReadStream, + decay_t<DynamicBuffer_v2>, + decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v2&&>(buffers), + delim, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v2, + typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> +{ + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_delim_string_op_v2< + AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h) noexcept + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); + } + + static auto get( + const detail::read_until_delim_string_op_v2< + AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, - typename MatchCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) +template <typename AsyncReadStream, + typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + ASIO_STRING_VIEW_PARAM delim, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_string_v2< + AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<std::string>(delim))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::read_until_match_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - MatchCondition, ASIO_HANDLER_TYPE(ReadHandler, - void (asio::error_code, std::size_t))>( - s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), - match_condition, init.completion_handler)( - asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_string_v2<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<std::string>(delim)); } -#if !defined(ASIO_NO_IOSTREAM) +#if !defined(ASIO_NO_EXTENSIONS) +#if defined(ASIO_HAS_BOOST_REGEX) -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, - char delim, ASIO_MOVE_ARG(ReadHandler) handler) +namespace detail { - return async_read_until(s, basic_streambuf_ref<Allocator>(b), - delim, ASIO_MOVE_CAST(ReadHandler)(handler)); -} + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler> + class read_until_expr_op_v2 + : public base_from_cancellation_state<ReadHandler> + { + public: + template <typename BufferSequence, typename Traits> + read_until_expr_op_v2(AsyncReadStream& stream, BufferSequence&& buffers, + const boost::basic_regex<char, Traits>& expr, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), + expr_(expr), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(static_cast<ReadHandler&&>(handler)) + { + } -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, - ASIO_STRING_VIEW_PARAM delim, - ASIO_MOVE_ARG(ReadHandler) handler) + read_until_expr_op_v2(const read_until_expr_op_v2& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), + buffers_(other.buffers_), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_expr_op_v2(read_until_expr_op_v2&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(static_cast<ReadHandler&&>(other.handler_)) + { + } + + void operator()(asio::error_code ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results<iterator, + typename std::vector<boost::sub_match<iterator>>::allocator_type> + match_results; + bool match = regex_search(start_pos, end, + match_results, expr_, regex_match_flags()); + if (match && match_results[0].matched) + { + // Full match. We're done. + search_position_ = match_results[0].second - begin; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (match) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = match_results[0].first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + static_cast<read_until_expr_op_v2&&>(*this)); + } + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + RegEx expr_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename AsyncReadStream> + class initiate_async_read_until_expr_v2 + { + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, typename DynamicBuffer_v2, typename RegEx> + void operator()(ReadHandler&& handler, + DynamicBuffer_v2&& buffers, + const RegEx& expr) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_expr_op_v2<AsyncReadStream, + decay_t<DynamicBuffer_v2>, + RegEx, decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v2&&>(buffers), + expr, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> { - return async_read_until(s, basic_streambuf_ref<Allocator>(b), - delim, ASIO_MOVE_CAST(ReadHandler)(handler)); -} + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>& h) noexcept + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); + } -#if defined(ASIO_HAS_BOOST_REGEX) + static auto get( + const detail::read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr, - ASIO_MOVE_ARG(ReadHandler) handler) +template <typename AsyncReadStream, typename DynamicBuffer_v2, typename Traits, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::basic_regex<char, Traits>& expr, ReadToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_expr_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), expr)) { - return async_read_until(s, basic_streambuf_ref<Allocator>(b), - expr, ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_expr_v2<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), expr); } #endif // defined(ASIO_HAS_BOOST_REGEX) -template <typename AsyncReadStream, typename Allocator, - typename MatchCondition, typename ReadHandler> -inline ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, - MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler> + class read_until_match_op_v2 + : public base_from_cancellation_state<ReadHandler> + { + public: + template <typename BufferSequence> + read_until_match_op_v2(AsyncReadStream& stream, + BufferSequence&& buffers, + MatchCondition match_condition, ReadHandler& handler) + : base_from_cancellation_state<ReadHandler>( + handler, enable_partial_cancellation()), + stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), + match_condition_(match_condition), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(static_cast<ReadHandler&&>(handler)) + { + } + + read_until_match_op_v2(const read_until_match_op_v2& other) + : base_from_cancellation_state<ReadHandler>(other), + stream_(other.stream_), + buffers_(other.buffers_), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_match_op_v2(read_until_match_op_v2&& other) + : base_from_cancellation_state<ReadHandler>( + static_cast<base_from_cancellation_state<ReadHandler>&&>(other)), + stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(static_cast<ReadHandler&&>(other.handler_)) + { + } + + void operator()(asio::error_code ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = match_condition_(start_pos, end); + if (result.second) + { + // Full match. We're done. + search_position_ = result.first - begin; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + static_cast<read_until_match_op_v2&&>(*this)); + } + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } + } + + const asio::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + static_cast<ReadHandler&&>(handler_)(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + MatchCondition match_condition_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, + MatchCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename AsyncReadStream> + class initiate_async_read_until_match_v2 + { + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_match_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename ReadHandler, + typename DynamicBuffer_v2, typename MatchCondition> + void operator()(ReadHandler&& handler, + DynamicBuffer_v2&& buffers, + MatchCondition match_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_match_op_v2<AsyncReadStream, decay_t<DynamicBuffer_v2>, + MatchCondition, decay_t<ReadHandler>>( + stream_, static_cast<DynamicBuffer_v2&&>(buffers), + match_condition, handler2.value)(asio::error_code(), 0, 1); + } + + private: + AsyncReadStream& stream_; + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler, typename DefaultCandidate> +struct associator<Associator, + detail::read_until_match_op_v2<AsyncReadStream, + DynamicBuffer_v2, MatchCondition, ReadHandler>, + DefaultCandidate> + : Associator<ReadHandler, DefaultCandidate> +{ + static typename Associator<ReadHandler, DefaultCandidate>::type get( + const detail::read_until_match_op_v2<AsyncReadStream, + DynamicBuffer_v2, MatchCondition, ReadHandler>& h) noexcept + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_); + } + + static auto get( + const detail::read_until_match_op_v2<AsyncReadStream, + DynamicBuffer_v2, MatchCondition, ReadHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken> +inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, ReadToken&& token, + constraint_t< + is_match_condition<MatchCondition>::value + >, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_match_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + match_condition)) { - return async_read_until(s, basic_streambuf_ref<Allocator>(b), - match_condition, ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_read_until_match_v2<AsyncReadStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), + match_condition); } -#endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) } // namespace asio diff --git a/3rdparty/asio/include/asio/impl/redirect_error.hpp b/3rdparty/asio/include/asio/impl/redirect_error.hpp new file mode 100644 index 00000000000..e75aa0f706c --- /dev/null +++ b/3rdparty/asio/include/asio/impl/redirect_error.hpp @@ -0,0 +1,250 @@ + +// impl/redirect_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_REDIRECT_ERROR_HPP +#define ASIO_IMPL_REDIRECT_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associator.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Class to adapt a redirect_error_t as a completion handler. +template <typename Handler> +class redirect_error_handler +{ +public: + typedef void result_type; + + template <typename CompletionToken> + redirect_error_handler(redirect_error_t<CompletionToken> e) + : ec_(e.ec_), + handler_(static_cast<CompletionToken&&>(e.token_)) + { + } + + template <typename RedirectedHandler> + redirect_error_handler(asio::error_code& ec, + RedirectedHandler&& h) + : ec_(ec), + handler_(static_cast<RedirectedHandler&&>(h)) + { + } + + void operator()() + { + static_cast<Handler&&>(handler_)(); + } + + template <typename Arg, typename... Args> + enable_if_t< + !is_same<decay_t<Arg>, asio::error_code>::value + > + operator()(Arg&& arg, Args&&... args) + { + static_cast<Handler&&>(handler_)( + static_cast<Arg&&>(arg), + static_cast<Args&&>(args)...); + } + + template <typename... Args> + void operator()(const asio::error_code& ec, Args&&... args) + { + ec_ = ec; + static_cast<Handler&&>(handler_)(static_cast<Args&&>(args)...); + } + +//private: + asio::error_code& ec_; + Handler handler_; +}; + +template <typename Handler> +inline bool asio_handler_is_continuation( + redirect_error_handler<Handler>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Signature> +struct redirect_error_signature +{ + typedef Signature type; +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(asio::error_code, Args...)> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(const asio::error_code&, Args...)> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(asio::error_code, Args...) &> +{ + typedef R type(Args...) &; +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(const asio::error_code&, Args...) &> +{ + typedef R type(Args...) &; +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(asio::error_code, Args...) &&> +{ + typedef R type(Args...) &&; +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(const asio::error_code&, Args...) &&> +{ + typedef R type(Args...) &&; +}; + +#if defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +template <typename R, typename... Args> +struct redirect_error_signature< + R(asio::error_code, Args...) noexcept> +{ + typedef R type(Args...) & noexcept; +}; + +template <typename R, typename... Args> +struct redirect_error_signature< + R(const asio::error_code&, Args...) noexcept> +{ + typedef R type(Args...) & noexcept; +}; + +template <typename R, typename... Args> +struct redirect_error_signature< + R(asio::error_code, Args...) & noexcept> +{ + typedef R type(Args...) & noexcept; +}; + +template <typename R, typename... Args> +struct redirect_error_signature< + R(const asio::error_code&, Args...) & noexcept> +{ + typedef R type(Args...) & noexcept; +}; + +template <typename R, typename... Args> +struct redirect_error_signature< + R(asio::error_code, Args...) && noexcept> +{ + typedef R type(Args...) && noexcept; +}; + +template <typename R, typename... Args> +struct redirect_error_signature< + R(const asio::error_code&, Args...) && noexcept> +{ + typedef R type(Args...) && noexcept; +}; + +#endif // defined(ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename Signature> +struct async_result<redirect_error_t<CompletionToken>, Signature> + : async_result<CompletionToken, + typename detail::redirect_error_signature<Signature>::type> +{ + + struct init_wrapper + { + explicit init_wrapper(asio::error_code& ec) + : ec_(ec) + { + } + + template <typename Handler, typename Initiation, typename... Args> + void operator()(Handler&& handler, + Initiation&& initiation, Args&&... args) const + { + static_cast<Initiation&&>(initiation)( + detail::redirect_error_handler<decay_t<Handler>>( + ec_, static_cast<Handler&&>(handler)), + static_cast<Args&&>(args)...); + } + + asio::error_code& ec_; + }; + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate<CompletionToken, + typename detail::redirect_error_signature<Signature>::type>( + declval<init_wrapper>(), token.token_, + static_cast<Initiation&&>(initiation), + static_cast<Args&&>(args)...)) + { + return async_initiate<CompletionToken, + typename detail::redirect_error_signature<Signature>::type>( + init_wrapper(token.ec_), token.token_, + static_cast<Initiation&&>(initiation), + static_cast<Args&&>(args)...); + } +}; + +template <template <typename, typename> class Associator, + typename Handler, typename DefaultCandidate> +struct associator<Associator, + detail::redirect_error_handler<Handler>, DefaultCandidate> + : Associator<Handler, DefaultCandidate> +{ + static typename Associator<Handler, DefaultCandidate>::type get( + const detail::redirect_error_handler<Handler>& h) noexcept + { + return Associator<Handler, DefaultCandidate>::get(h.handler_); + } + + static auto get(const detail::redirect_error_handler<Handler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_REDIRECT_ERROR_HPP diff --git a/3rdparty/asio/include/asio/impl/serial_port_base.hpp b/3rdparty/asio/include/asio/impl/serial_port_base.hpp index c118d93cb9e..1fa2af66f73 100644 --- a/3rdparty/asio/include/asio/impl/serial_port_base.hpp +++ b/3rdparty/asio/include/asio/impl/serial_port_base.hpp @@ -2,7 +2,7 @@ // impl/serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying diff --git a/3rdparty/asio/include/asio/impl/serial_port_base.ipp b/3rdparty/asio/include/asio/impl/serial_port_base.ipp index 748c8ca0d1a..646af3453d6 100644 --- a/3rdparty/asio/include/asio/impl/serial_port_base.ipp +++ b/3rdparty/asio/include/asio/impl/serial_port_base.ipp @@ -2,7 +2,7 @@ // impl/serial_port_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -113,7 +113,7 @@ ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store( ec = asio::error::invalid_argument; ASIO_SYNC_OP_VOID_RETURN(ec); } -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) ::cfsetspeed(&storage, baud); # else ::cfsetispeed(&storage, baud); @@ -249,7 +249,7 @@ ASIO_SYNC_OP_VOID serial_port_base::flow_control::store( { case none: storage.c_iflag &= ~(IXOFF | IXON); -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) storage.c_cflag &= ~CRTSCTS; # elif defined(__QNXNTO__) storage.c_cflag &= ~(IHFLOW | OHFLOW); @@ -257,14 +257,14 @@ ASIO_SYNC_OP_VOID serial_port_base::flow_control::store( break; case software: storage.c_iflag |= IXOFF | IXON; -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) storage.c_cflag &= ~CRTSCTS; # elif defined(__QNXNTO__) storage.c_cflag &= ~(IHFLOW | OHFLOW); # endif break; case hardware: -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) storage.c_iflag &= ~(IXOFF | IXON); storage.c_cflag |= CRTSCTS; break; @@ -305,7 +305,7 @@ ASIO_SYNC_OP_VOID serial_port_base::flow_control::load( { value_ = software; } -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) else if (storage.c_cflag & CRTSCTS) { value_ = hardware; diff --git a/3rdparty/asio/include/asio/impl/spawn.hpp b/3rdparty/asio/include/asio/impl/spawn.hpp index 82a05f086a2..38a96406ed4 100644 --- a/3rdparty/asio/include/asio/impl/spawn.hpp +++ b/3rdparty/asio/include/asio/impl/spawn.hpp @@ -2,7 +2,7 @@ // impl/spawn.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,513 +16,1382 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include <tuple> #include "asio/associated_allocator.hpp" +#include "asio/associated_cancellation_slot.hpp" #include "asio/associated_executor.hpp" #include "asio/async_result.hpp" #include "asio/bind_executor.hpp" #include "asio/detail/atomic_count.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/bind_handler.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/type_traits.hpp" +#include "asio/detail/utility.hpp" #include "asio/system_error.hpp" +#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) +# include <boost/context/fiber.hpp> +#endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { - template <typename Handler, typename T> - class coro_handler +#if !defined(ASIO_NO_EXCEPTIONS) +inline void spawned_thread_rethrow(void* ex) +{ + if (*static_cast<exception_ptr*>(ex)) + rethrow_exception(*static_cast<exception_ptr*>(ex)); +} +#endif // !defined(ASIO_NO_EXCEPTIONS) + +#if defined(ASIO_HAS_BOOST_COROUTINE) + +// Spawned thread implementation using Boost.Coroutine. +class spawned_coroutine_thread : public spawned_thread_base +{ +public: +#if defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2) + typedef boost::coroutines::pull_coroutine<void> callee_type; + typedef boost::coroutines::push_coroutine<void> caller_type; +#else + typedef boost::coroutines::coroutine<void()> callee_type; + typedef boost::coroutines::coroutine<void()> caller_type; +#endif + + spawned_coroutine_thread(caller_type& caller) + : caller_(caller), + on_suspend_fn_(0), + on_suspend_arg_(0) { - public: - coro_handler(basic_yield_context<Handler> ctx) - : coro_(ctx.coro_.lock()), - ca_(ctx.ca_), - handler_(ctx.handler_), - ready_(0), - ec_(ctx.ec_), - value_(0) + } + + template <typename F> + static spawned_thread_base* spawn(F&& f, + const boost::coroutines::attributes& attributes, + cancellation_slot parent_cancel_slot = cancellation_slot(), + cancellation_state cancel_state = cancellation_state()) + { + spawned_coroutine_thread* spawned_thread = 0; + callee_type callee(entry_point<decay_t<F>>( + static_cast<F&&>(f), &spawned_thread), attributes); + spawned_thread->callee_.swap(callee); + spawned_thread->parent_cancellation_slot_ = parent_cancel_slot; + spawned_thread->cancellation_state_ = cancel_state; + return spawned_thread; + } + + template <typename F> + static spawned_thread_base* spawn(F&& f, + cancellation_slot parent_cancel_slot = cancellation_slot(), + cancellation_state cancel_state = cancellation_state()) + { + return spawn(static_cast<F&&>(f), boost::coroutines::attributes(), + parent_cancel_slot, cancel_state); + } + + void resume() + { + callee_(); + if (on_suspend_fn_) { + void (*fn)(void*) = on_suspend_fn_; + void* arg = on_suspend_arg_; + on_suspend_fn_ = 0; + fn(arg); } + } + + void suspend_with(void (*fn)(void*), void* arg) + { + if (throw_if_cancelled_) + if (!!cancellation_state_.cancelled()) + throw_error(asio::error::operation_aborted, "yield"); + has_context_switched_ = true; + on_suspend_fn_ = fn; + on_suspend_arg_ = arg; + caller_(); + } + + void destroy() + { + callee_type callee; + callee.swap(callee_); + if (terminal_) + callee(); + } - void operator()(T value) +private: + template <typename Function> + class entry_point + { + public: + template <typename F> + entry_point(F&& f, + spawned_coroutine_thread** spawned_thread_out) + : function_(static_cast<F&&>(f)), + spawned_thread_out_(spawned_thread_out) { - *ec_ = asio::error_code(); - *value_ = ASIO_MOVE_CAST(T)(value); - if (--*ready_ == 0) - (*coro_)(); } - void operator()(asio::error_code ec, T value) + void operator()(caller_type& caller) { - *ec_ = ec; - *value_ = ASIO_MOVE_CAST(T)(value); - if (--*ready_ == 0) - (*coro_)(); + Function function(static_cast<Function&&>(function_)); + spawned_coroutine_thread spawned_thread(caller); + *spawned_thread_out_ = &spawned_thread; + spawned_thread_out_ = 0; + spawned_thread.suspend(); +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + function(&spawned_thread); + spawned_thread.terminal_ = true; + spawned_thread.suspend(); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (const boost::coroutines::detail::forced_unwind&) + { + throw; + } + catch (...) + { + exception_ptr ex = current_exception(); + spawned_thread.terminal_ = true; + spawned_thread.suspend_with(spawned_thread_rethrow, &ex); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) } - //private: - shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; - typename basic_yield_context<Handler>::caller_type& ca_; - Handler handler_; - atomic_count* ready_; - asio::error_code* ec_; - T* value_; + private: + Function function_; + spawned_coroutine_thread** spawned_thread_out_; }; - template <typename Handler> - class coro_handler<Handler, void> + caller_type& caller_; + callee_type callee_; + void (*on_suspend_fn_)(void*); + void* on_suspend_arg_; +}; + +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + +#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + +// Spawned thread implementation using Boost.Context's fiber. +class spawned_fiber_thread : public spawned_thread_base +{ +public: + typedef boost::context::fiber fiber_type; + + spawned_fiber_thread(fiber_type&& caller) + : caller_(static_cast<fiber_type&&>(caller)), + on_suspend_fn_(0), + on_suspend_arg_(0) { - public: - coro_handler(basic_yield_context<Handler> ctx) - : coro_(ctx.coro_.lock()), - ca_(ctx.ca_), - handler_(ctx.handler_), - ready_(0), - ec_(ctx.ec_) + } + + template <typename StackAllocator, typename F> + static spawned_thread_base* spawn(allocator_arg_t, + StackAllocator&& stack_allocator, + F&& f, + cancellation_slot parent_cancel_slot = cancellation_slot(), + cancellation_state cancel_state = cancellation_state()) + { + spawned_fiber_thread* spawned_thread = 0; + fiber_type callee(allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + entry_point<decay_t<F>>( + static_cast<F&&>(f), &spawned_thread)); + callee = fiber_type(static_cast<fiber_type&&>(callee)).resume(); + spawned_thread->callee_ = static_cast<fiber_type&&>(callee); + spawned_thread->parent_cancellation_slot_ = parent_cancel_slot; + spawned_thread->cancellation_state_ = cancel_state; + return spawned_thread; + } + + template <typename F> + static spawned_thread_base* spawn(F&& f, + cancellation_slot parent_cancel_slot = cancellation_slot(), + cancellation_state cancel_state = cancellation_state()) + { + return spawn(allocator_arg_t(), boost::context::fixedsize_stack(), + static_cast<F&&>(f), parent_cancel_slot, cancel_state); + } + + void resume() + { + callee_ = fiber_type(static_cast<fiber_type&&>(callee_)).resume(); + if (on_suspend_fn_) { + void (*fn)(void*) = on_suspend_fn_; + void* arg = on_suspend_arg_; + on_suspend_fn_ = 0; + fn(arg); } + } - void operator()() + void suspend_with(void (*fn)(void*), void* arg) + { + if (throw_if_cancelled_) + if (!!cancellation_state_.cancelled()) + throw_error(asio::error::operation_aborted, "yield"); + has_context_switched_ = true; + on_suspend_fn_ = fn; + on_suspend_arg_ = arg; + caller_ = fiber_type(static_cast<fiber_type&&>(caller_)).resume(); + } + + void destroy() + { + fiber_type callee = static_cast<fiber_type&&>(callee_); + if (terminal_) + fiber_type(static_cast<fiber_type&&>(callee)).resume(); + } + +private: + template <typename Function> + class entry_point + { + public: + template <typename F> + entry_point(F&& f, + spawned_fiber_thread** spawned_thread_out) + : function_(static_cast<F&&>(f)), + spawned_thread_out_(spawned_thread_out) { - *ec_ = asio::error_code(); - if (--*ready_ == 0) - (*coro_)(); } - void operator()(asio::error_code ec) + fiber_type operator()(fiber_type&& caller) { - *ec_ = ec; - if (--*ready_ == 0) - (*coro_)(); + Function function(static_cast<Function&&>(function_)); + spawned_fiber_thread spawned_thread( + static_cast<fiber_type&&>(caller)); + *spawned_thread_out_ = &spawned_thread; + spawned_thread_out_ = 0; + spawned_thread.suspend(); +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + function(&spawned_thread); + spawned_thread.terminal_ = true; + spawned_thread.suspend(); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (const boost::context::detail::forced_unwind&) + { + throw; + } + catch (...) + { + exception_ptr ex = current_exception(); + spawned_thread.terminal_ = true; + spawned_thread.suspend_with(spawned_thread_rethrow, &ex); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + return static_cast<fiber_type&&>(spawned_thread.caller_); } - //private: - shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; - typename basic_yield_context<Handler>::caller_type& ca_; - Handler handler_; - atomic_count* ready_; - asio::error_code* ec_; + private: + Function function_; + spawned_fiber_thread** spawned_thread_out_; }; - template <typename Handler, typename T> - inline void* asio_handler_allocate(std::size_t size, - coro_handler<Handler, T>* this_handler) + fiber_type caller_; + fiber_type callee_; + void (*on_suspend_fn_)(void*); + void* on_suspend_arg_; +}; + +#endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + +#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) +typedef spawned_fiber_thread default_spawned_thread_type; +#elif defined(ASIO_HAS_BOOST_COROUTINE) +typedef spawned_coroutine_thread default_spawned_thread_type; +#else +# error No spawn() implementation available +#endif + +// Helper class to perform the initial resume on the correct executor. +class spawned_thread_resumer +{ +public: + explicit spawned_thread_resumer(spawned_thread_base* spawned_thread) + : spawned_thread_(spawned_thread) + { + } + + spawned_thread_resumer(spawned_thread_resumer&& other) noexcept + : spawned_thread_(other.spawned_thread_) { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); + other.spawned_thread_ = 0; } - template <typename Handler, typename T> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - coro_handler<Handler, T>* this_handler) + ~spawned_thread_resumer() { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); + if (spawned_thread_) + spawned_thread_->destroy(); } - template <typename Handler, typename T> - inline bool asio_handler_is_continuation(coro_handler<Handler, T>*) + void operator()() { - return true; + spawned_thread_->attach(&spawned_thread_); + spawned_thread_->resume(); } - template <typename Function, typename Handler, typename T> - inline void asio_handler_invoke(Function& function, - coro_handler<Handler, T>* this_handler) +private: + spawned_thread_base* spawned_thread_; +}; + +// Helper class to ensure spawned threads are destroyed on the correct executor. +class spawned_thread_destroyer +{ +public: + explicit spawned_thread_destroyer(spawned_thread_base* spawned_thread) + : spawned_thread_(spawned_thread) { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); + spawned_thread->detach(); } - template <typename Function, typename Handler, typename T> - inline void asio_handler_invoke(const Function& function, - coro_handler<Handler, T>* this_handler) + spawned_thread_destroyer(spawned_thread_destroyer&& other) noexcept + : spawned_thread_(other.spawned_thread_) { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); + other.spawned_thread_ = 0; } - template <typename Handler, typename T> - class coro_async_result + ~spawned_thread_destroyer() { - public: - typedef coro_handler<Handler, T> completion_handler_type; - typedef T return_type; + if (spawned_thread_) + spawned_thread_->destroy(); + } - explicit coro_async_result(completion_handler_type& h) - : handler_(h), - ca_(h.ca_), - ready_(2) + void operator()() + { + if (spawned_thread_) { - h.ready_ = &ready_; - out_ec_ = h.ec_; - if (!out_ec_) h.ec_ = &ec_; - h.value_ = &value_; + spawned_thread_->destroy(); + spawned_thread_ = 0; } + } - return_type get() - { - // Must not hold shared_ptr to coro while suspended. - handler_.coro_.reset(); +private: + spawned_thread_base* spawned_thread_; +}; - if (--ready_ != 0) - ca_(); - if (!out_ec_ && ec_) throw asio::system_error(ec_); - return ASIO_MOVE_CAST(return_type)(value_); - } +// Base class for all completion handlers associated with a spawned thread. +template <typename Executor> +class spawn_handler_base +{ +public: + typedef Executor executor_type; + typedef cancellation_slot cancellation_slot_type; - private: - completion_handler_type& handler_; - typename basic_yield_context<Handler>::caller_type& ca_; - atomic_count ready_; - asio::error_code* out_ec_; - asio::error_code ec_; - return_type value_; - }; + spawn_handler_base(const basic_yield_context<Executor>& yield) + : yield_(yield), + spawned_thread_(yield.spawned_thread_) + { + spawned_thread_->detach(); + } + + spawn_handler_base(spawn_handler_base&& other) noexcept + : yield_(other.yield_), + spawned_thread_(other.spawned_thread_) - template <typename Handler> - class coro_async_result<Handler, void> { - public: - typedef coro_handler<Handler, void> completion_handler_type; - typedef void return_type; + other.spawned_thread_ = 0; + } - explicit coro_async_result(completion_handler_type& h) - : handler_(h), - ca_(h.ca_), - ready_(2) - { - h.ready_ = &ready_; - out_ec_ = h.ec_; - if (!out_ec_) h.ec_ = &ec_; - } + ~spawn_handler_base() + { + if (spawned_thread_) + (post)(yield_.executor_, spawned_thread_destroyer(spawned_thread_)); + } - void get() - { - // Must not hold shared_ptr to coro while suspended. - handler_.coro_.reset(); + executor_type get_executor() const noexcept + { + return yield_.executor_; + } - if (--ready_ != 0) - ca_(); - if (!out_ec_ && ec_) throw asio::system_error(ec_); - } + cancellation_slot_type get_cancellation_slot() const noexcept + { + return spawned_thread_->get_cancellation_slot(); + } - private: - completion_handler_type& handler_; - typename basic_yield_context<Handler>::caller_type& ca_; - atomic_count ready_; - asio::error_code* out_ec_; - asio::error_code ec_; - }; + void resume() + { + spawned_thread_resumer resumer(spawned_thread_); + spawned_thread_ = 0; + resumer(); + } -} // namespace detail +protected: + const basic_yield_context<Executor>& yield_; + spawned_thread_base* spawned_thread_; +}; -#if !defined(GENERATING_DOCUMENTATION) +// Completion handlers for when basic_yield_context is used as a token. +template <typename Executor, typename Signature> +class spawn_handler; -template <typename Handler, typename ReturnType> -class async_result<basic_yield_context<Handler>, ReturnType()> - : public detail::coro_async_result<Handler, void> +template <typename Executor, typename R> +class spawn_handler<Executor, R()> + : public spawn_handler_base<Executor> { public: - explicit async_result( - typename detail::coro_async_result<Handler, - void>::completion_handler_type& h) - : detail::coro_async_result<Handler, void>(h) + typedef void return_type; + + struct result_type {}; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type&) + : spawn_handler_base<Executor>(yield) + { + } + + void operator()() + { + this->resume(); + } + + static return_type on_resume(result_type&) { } }; -template <typename Handler, typename ReturnType, typename Arg1> -class async_result<basic_yield_context<Handler>, ReturnType(Arg1)> - : public detail::coro_async_result<Handler, typename decay<Arg1>::type> +template <typename Executor, typename R> +class spawn_handler<Executor, R(asio::error_code)> + : public spawn_handler_base<Executor> { public: - explicit async_result( - typename detail::coro_async_result<Handler, - typename decay<Arg1>::type>::completion_handler_type& h) - : detail::coro_async_result<Handler, Arg1>(h) + typedef void return_type; + typedef asio::error_code* result_type; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) + { + } + + void operator()(asio::error_code ec) + { + if (this->yield_.ec_) + { + *this->yield_.ec_ = ec; + result_ = 0; + } + else + result_ = &ec; + this->resume(); + } + + static return_type on_resume(result_type& result) { + if (result) + throw_error(*result); } + +private: + result_type& result_; }; -template <typename Handler, typename ReturnType> -class async_result<basic_yield_context<Handler>, - ReturnType(asio::error_code)> - : public detail::coro_async_result<Handler, void> +template <typename Executor, typename R> +class spawn_handler<Executor, R(exception_ptr)> + : public spawn_handler_base<Executor> { public: - explicit async_result( - typename detail::coro_async_result<Handler, - void>::completion_handler_type& h) - : detail::coro_async_result<Handler, void>(h) + typedef void return_type; + typedef exception_ptr* result_type; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) + { + } + + void operator()(exception_ptr ex) { + result_ = &ex; + this->resume(); } + + static return_type on_resume(result_type& result) + { + if (*result) + rethrow_exception(*result); + } + +private: + result_type& result_; }; -template <typename Handler, typename ReturnType, typename Arg2> -class async_result<basic_yield_context<Handler>, - ReturnType(asio::error_code, Arg2)> - : public detail::coro_async_result<Handler, typename decay<Arg2>::type> +template <typename Executor, typename R, typename T> +class spawn_handler<Executor, R(T)> + : public spawn_handler_base<Executor> { public: - explicit async_result( - typename detail::coro_async_result<Handler, - typename decay<Arg2>::type>::completion_handler_type& h) - : detail::coro_async_result<Handler, Arg2>(h) + typedef T return_type; + typedef return_type* result_type; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) { } -}; -#if !defined(ASIO_NO_DEPRECATED) + void operator()(T value) + { + result_ = &value; + this->resume(); + } -template <typename Handler, typename ReturnType> -struct handler_type<basic_yield_context<Handler>, ReturnType()> -{ - typedef detail::coro_handler<Handler, void> type; + static return_type on_resume(result_type& result) + { + return static_cast<return_type&&>(*result); + } + +private: + result_type& result_; }; -template <typename Handler, typename ReturnType, typename Arg1> -struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)> +template <typename Executor, typename R, typename T> +class spawn_handler<Executor, R(asio::error_code, T)> + : public spawn_handler_base<Executor> { - typedef detail::coro_handler<Handler, typename decay<Arg1>::type> type; +public: + typedef T return_type; + + struct result_type + { + asio::error_code* ec_; + return_type* value_; + }; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) + { + } + + void operator()(asio::error_code ec, T value) + { + if (this->yield_.ec_) + { + *this->yield_.ec_ = ec; + result_.ec_ = 0; + } + else + result_.ec_ = &ec; + result_.value_ = &value; + this->resume(); + } + + static return_type on_resume(result_type& result) + { + if (result.ec_) + throw_error(*result.ec_); + return static_cast<return_type&&>(*result.value_); + } + +private: + result_type& result_; }; -template <typename Handler, typename ReturnType> -struct handler_type<basic_yield_context<Handler>, - ReturnType(asio::error_code)> +template <typename Executor, typename R, typename T> +class spawn_handler<Executor, R(exception_ptr, T)> + : public spawn_handler_base<Executor> { - typedef detail::coro_handler<Handler, void> type; +public: + typedef T return_type; + + struct result_type + { + exception_ptr* ex_; + return_type* value_; + }; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) + { + } + + void operator()(exception_ptr ex, T value) + { + result_.ex_ = &ex; + result_.value_ = &value; + this->resume(); + } + + static return_type on_resume(result_type& result) + { + if (*result.ex_) + rethrow_exception(*result.ex_); + return static_cast<return_type&&>(*result.value_); + } + +private: + result_type& result_; }; -template <typename Handler, typename ReturnType, typename Arg2> -struct handler_type<basic_yield_context<Handler>, - ReturnType(asio::error_code, Arg2)> +template <typename Executor, typename R, typename... Ts> +class spawn_handler<Executor, R(Ts...)> + : public spawn_handler_base<Executor> { - typedef detail::coro_handler<Handler, typename decay<Arg2>::type> type; +public: + typedef std::tuple<Ts...> return_type; + + typedef return_type* result_type; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) + { + } + + template <typename... Args> + void operator()(Args&&... args) + { + return_type value(static_cast<Args&&>(args)...); + result_ = &value; + this->resume(); + } + + static return_type on_resume(result_type& result) + { + return static_cast<return_type&&>(*result); + } + +private: + result_type& result_; }; -template <typename Handler, typename T> -class async_result<detail::coro_handler<Handler, T> > - : public detail::coro_async_result<Handler, T> +template <typename Executor, typename R, typename... Ts> +class spawn_handler<Executor, R(asio::error_code, Ts...)> + : public spawn_handler_base<Executor> { public: - typedef typename detail::coro_async_result<Handler, T>::return_type type; + typedef std::tuple<Ts...> return_type; - explicit async_result( - typename detail::coro_async_result<Handler, - void>::completion_handler_type& h) - : detail::coro_async_result<Handler, T>(h) + struct result_type + { + asio::error_code* ec_; + return_type* value_; + }; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) { } -}; -#endif // !defined(ASIO_NO_DEPRECATED) + template <typename... Args> + void operator()(asio::error_code ec, + Args&&... args) + { + return_type value(static_cast<Args&&>(args)...); + if (this->yield_.ec_) + { + *this->yield_.ec_ = ec; + result_.ec_ = 0; + } + else + result_.ec_ = &ec; + result_.value_ = &value; + this->resume(); + } -template <typename Handler, typename T, typename Allocator> -struct associated_allocator<detail::coro_handler<Handler, T>, Allocator> + static return_type on_resume(result_type& result) + { + if (result.ec_) + throw_error(*result.ec_); + return static_cast<return_type&&>(*result.value_); + } + +private: + result_type& result_; +}; + +template <typename Executor, typename R, typename... Ts> +class spawn_handler<Executor, R(exception_ptr, Ts...)> + : public spawn_handler_base<Executor> { - typedef typename associated_allocator<Handler, Allocator>::type type; +public: + typedef std::tuple<Ts...> return_type; + + struct result_type + { + exception_ptr* ex_; + return_type* value_; + }; + + spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) + : spawn_handler_base<Executor>(yield), + result_(result) + { + } - static type get(const detail::coro_handler<Handler, T>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + template <typename... Args> + void operator()(exception_ptr ex, Args&&... args) { - return associated_allocator<Handler, Allocator>::get(h.handler_, a); + return_type value(static_cast<Args&&>(args)...); + result_.ex_ = &ex; + result_.value_ = &value; + this->resume(); } + + static return_type on_resume(result_type& result) + { + if (*result.ex_) + rethrow_exception(*result.ex_); + return static_cast<return_type&&>(*result.value_); + } + +private: + result_type& result_; }; -template <typename Handler, typename T, typename Executor> -struct associated_executor<detail::coro_handler<Handler, T>, Executor> +template <typename Executor, typename Signature> +inline bool asio_handler_is_continuation(spawn_handler<Executor, Signature>*) +{ + return true; +} + +} // namespace detail + +template <typename Executor, typename Signature> +class async_result<basic_yield_context<Executor>, Signature> { - typedef typename associated_executor<Handler, Executor>::type type; +public: + typedef typename detail::spawn_handler<Executor, Signature> handler_type; + typedef typename handler_type::return_type return_type; + +#if defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) - static type get(const detail::coro_handler<Handler, T>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + template <typename Initiation, typename... InitArgs> + static return_type initiate(Initiation&& init, + const basic_yield_context<Executor>& yield, + InitArgs&&... init_args) { - return associated_executor<Handler, Executor>::get(h.handler_, ex); + typename handler_type::result_type result + = typename handler_type::result_type(); + + yield.spawned_thread_->suspend_with( + [&]() + { + static_cast<Initiation&&>(init)( + handler_type(yield, result), + static_cast<InitArgs&&>(init_args)...); + }); + + return handler_type::on_resume(result); } -}; -namespace detail { +#else // defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) - template <typename Handler, typename Function> - struct spawn_data : private noncopyable + template <typename Initiation, typename... InitArgs> + struct suspend_with_helper { - spawn_data(ASIO_MOVE_ARG(Handler) handler, - bool call_handler, ASIO_MOVE_ARG(Function) function) - : handler_(ASIO_MOVE_CAST(Handler)(handler)), - call_handler_(call_handler), - function_(ASIO_MOVE_CAST(Function)(function)) + typename handler_type::result_type& result_; + Initiation&& init_; + const basic_yield_context<Executor>& yield_; + std::tuple<InitArgs&&...> init_args_; + + template <std::size_t... I> + void do_invoke(detail::index_sequence<I...>) { + static_cast<Initiation&&>(init_)( + handler_type(yield_, result_), + static_cast<InitArgs&&>(std::get<I>(init_args_))...); } - weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_; - Handler handler_; - bool call_handler_; - Function function_; + void operator()() + { + this->do_invoke(detail::make_index_sequence<sizeof...(InitArgs)>()); + } }; - template <typename Handler, typename Function> - struct coro_entry_point + template <typename Initiation, typename... InitArgs> + static return_type initiate(Initiation&& init, + const basic_yield_context<Executor>& yield, + InitArgs&&... init_args) + { + typename handler_type::result_type result + = typename handler_type::result_type(); + + yield.spawned_thread_->suspend_with( + suspend_with_helper<Initiation, InitArgs...>{ + result, static_cast<Initiation&&>(init), yield, + std::tuple<InitArgs&&...>( + static_cast<InitArgs&&>(init_args)...)}); + + return handler_type::on_resume(result); + } + +#endif // defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) +}; + +namespace detail { + +template <typename Executor, typename Function, typename Handler> +class spawn_entry_point +{ +public: + template <typename F, typename H> + spawn_entry_point(const Executor& ex, + F&& f, H&& h) + : executor_(ex), + function_(static_cast<F&&>(f)), + handler_(static_cast<H&&>(h)), + work_(handler_, executor_) + { + } + + void operator()(spawned_thread_base* spawned_thread) { - void operator()(typename basic_yield_context<Handler>::caller_type& ca) + const basic_yield_context<Executor> yield(spawned_thread, executor_); + this->call(yield, + void_type<result_of_t<Function(basic_yield_context<Executor>)>>()); + } + +private: + void call(const basic_yield_context<Executor>& yield, void_type<void>) + { +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) { - shared_ptr<spawn_data<Handler, Function> > data(data_); -#if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) - ca(); // Yield until coroutine pointer has been initialised. -#endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) - const basic_yield_context<Handler> yield( - data->coro_, ca, data->handler_); - - (data->function_)(yield); - if (data->call_handler_) - (data->handler_)(); + function_(yield); + if (!yield.spawned_thread_->has_context_switched()) + (post)(yield); + detail::binder1<Handler, exception_ptr> + handler(handler_, exception_ptr()); + work_.complete(handler, handler.handler_); } +#if !defined(ASIO_NO_EXCEPTIONS) +# if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + catch (const boost::context::detail::forced_unwind&) + { + throw; + } +# endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER) +# if defined(ASIO_HAS_BOOST_COROUTINE) + catch (const boost::coroutines::detail::forced_unwind&) + { + throw; + } +# endif // defined(ASIO_HAS_BOOST_COROUTINE) + catch (...) + { + exception_ptr ex = current_exception(); + if (!yield.spawned_thread_->has_context_switched()) + (post)(yield); + detail::binder1<Handler, exception_ptr> handler(handler_, ex); + work_.complete(handler, handler.handler_); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } - shared_ptr<spawn_data<Handler, Function> > data_; - }; - - template <typename Handler, typename Function> - struct spawn_helper + template <typename T> + void call(const basic_yield_context<Executor>& yield, void_type<T>) { - void operator()() +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + T result(function_(yield)); + if (!yield.spawned_thread_->has_context_switched()) + (post)(yield); + detail::binder2<Handler, exception_ptr, T> + handler(handler_, exception_ptr(), static_cast<T&&>(result)); + work_.complete(handler, handler.handler_); + } +#if !defined(ASIO_NO_EXCEPTIONS) +# if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + catch (const boost::context::detail::forced_unwind&) + { + throw; + } +# endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER) +# if defined(ASIO_HAS_BOOST_COROUTINE) + catch (const boost::coroutines::detail::forced_unwind&) + { + throw; + } +# endif // defined(ASIO_HAS_BOOST_COROUTINE) + catch (...) { - typedef typename basic_yield_context<Handler>::callee_type callee_type; - coro_entry_point<Handler, Function> entry_point = { data_ }; - shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_)); - data_->coro_ = coro; - (*coro)(); + exception_ptr ex = current_exception(); + if (!yield.spawned_thread_->has_context_switched()) + (post)(yield); + detail::binder2<Handler, exception_ptr, T> handler(handler_, ex, T()); + work_.complete(handler, handler.handler_); } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } - shared_ptr<spawn_data<Handler, Function> > data_; - boost::coroutines::attributes attributes_; - }; + Executor executor_; + Function function_; + Handler handler_; + handler_work<Handler, Executor> work_; +}; + +struct spawn_cancellation_signal_emitter +{ + cancellation_signal* signal_; + cancellation_type_t type_; - template <typename Function, typename Handler, typename Function1> - inline void asio_handler_invoke(Function& function, - spawn_helper<Handler, Function1>* this_handler) + void operator()() { - asio_handler_invoke_helpers::invoke( - function, this_handler->data_->handler_); + signal_->emit(type_); } +}; - template <typename Function, typename Handler, typename Function1> - inline void asio_handler_invoke(const Function& function, - spawn_helper<Handler, Function1>* this_handler) +template <typename Handler, typename Executor, typename = void> +class spawn_cancellation_handler +{ +public: + spawn_cancellation_handler(const Handler&, const Executor& ex) + : ex_(ex) { - asio_handler_invoke_helpers::invoke( - function, this_handler->data_->handler_); } - inline void default_spawn_handler() {} + cancellation_slot slot() + { + return signal_.slot(); + } -} // namespace detail + void operator()(cancellation_type_t type) + { + spawn_cancellation_signal_emitter emitter = { &signal_, type }; + (dispatch)(ex_, emitter); + } -template <typename Function> -inline void spawn(ASIO_MOVE_ARG(Function) function, - const boost::coroutines::attributes& attributes) +private: + cancellation_signal signal_; + Executor ex_; +}; + + +template <typename Handler, typename Executor> +class spawn_cancellation_handler<Handler, Executor, + enable_if_t< + is_same< + typename associated_executor<Handler, + Executor>::asio_associated_executor_is_unspecialised, + void + >::value + >> { - typedef typename decay<Function>::type function_type; +public: + spawn_cancellation_handler(const Handler&, const Executor&) + { + } - typename associated_executor<function_type>::type ex( - (get_associated_executor)(function)); + cancellation_slot slot() + { + return signal_.slot(); + } + + void operator()(cancellation_type_t type) + { + signal_.emit(type); + } + +private: + cancellation_signal signal_; +}; + +template <typename Executor> +class initiate_spawn +{ +public: + typedef Executor executor_type; - asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes); + explicit initiate_spawn(const executor_type& ex) + : executor_(ex) + { + } + + executor_type get_executor() const noexcept + { + return executor_; + } + + template <typename Handler, typename F> + void operator()(Handler&& handler, + F&& f) const + { + typedef decay_t<Handler> handler_type; + typedef decay_t<F> function_type; + typedef spawn_cancellation_handler< + handler_type, Executor> cancel_handler_type; + + associated_cancellation_slot_t<handler_type> slot + = asio::get_associated_cancellation_slot(handler); + + cancel_handler_type* cancel_handler = slot.is_connected() + ? &slot.template emplace<cancel_handler_type>(handler, executor_) + : 0; + + cancellation_slot proxy_slot( + cancel_handler + ? cancel_handler->slot() + : cancellation_slot()); + + cancellation_state cancel_state(proxy_slot); + + (dispatch)(executor_, + spawned_thread_resumer( + default_spawned_thread_type::spawn( + spawn_entry_point<Executor, function_type, handler_type>( + executor_, static_cast<F&&>(f), + static_cast<Handler&&>(handler)), + proxy_slot, cancel_state))); + } + +#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + + template <typename Handler, typename StackAllocator, typename F> + void operator()(Handler&& handler, allocator_arg_t, + StackAllocator&& stack_allocator, + F&& f) const + { + typedef decay_t<Handler> handler_type; + typedef decay_t<F> function_type; + typedef spawn_cancellation_handler< + handler_type, Executor> cancel_handler_type; + + associated_cancellation_slot_t<handler_type> slot + = asio::get_associated_cancellation_slot(handler); + + cancel_handler_type* cancel_handler = slot.is_connected() + ? &slot.template emplace<cancel_handler_type>(handler, executor_) + : 0; + + cancellation_slot proxy_slot( + cancel_handler + ? cancel_handler->slot() + : cancellation_slot()); + + cancellation_state cancel_state(proxy_slot); + + (dispatch)(executor_, + spawned_thread_resumer( + spawned_fiber_thread::spawn(allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + spawn_entry_point<Executor, function_type, handler_type>( + executor_, static_cast<F&&>(f), + static_cast<Handler&&>(handler)), + proxy_slot, cancel_state))); + } + +#endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + +private: + executor_type executor_; +}; + +} // namespace detail + +template <typename Executor, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken> +inline auto spawn(const Executor& ex, F&& function, CompletionToken&& token, +#if defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + !is_same< + decay_t<CompletionToken>, + boost::coroutines::attributes + >::value + >, +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + >) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), + token, static_cast<F&&>(function))) +{ + return async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + detail::initiate_spawn<Executor>(ex), + token, static_cast<F&&>(function)); } -template <typename Handler, typename Function> -void spawn(ASIO_MOVE_ARG(Handler) handler, - ASIO_MOVE_ARG(Function) function, - const boost::coroutines::attributes& attributes, - typename enable_if<!is_executor<typename decay<Handler>::type>::value && - !is_convertible<Handler&, execution_context&>::value>::type*) +template <typename ExecutionContext, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type) CompletionToken> +inline auto spawn(ExecutionContext& ctx, F&& function, CompletionToken&& token, +#if defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + !is_same< + decay_t<CompletionToken>, + boost::coroutines::attributes + >::value + >, +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + >) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type>( + declval<detail::initiate_spawn< + typename ExecutionContext::executor_type>>(), + token, static_cast<F&&>(function))) { - typedef typename decay<Handler>::type handler_type; + return (spawn)(ctx.get_executor(), static_cast<F&&>(function), + static_cast<CompletionToken&&>(token)); +} - typename associated_executor<handler_type>::type ex( - (get_associated_executor)(handler)); +template <typename Executor, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) + CompletionToken> +inline auto spawn(const basic_yield_context<Executor>& ctx, + F&& function, CompletionToken&& token, +#if defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + !is_same< + decay_t<CompletionToken>, + boost::coroutines::attributes + >::value + >, +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + >) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), + token, static_cast<F&&>(function))) +{ + return (spawn)(ctx.get_executor(), static_cast<F&&>(function), + static_cast<CompletionToken&&>(token)); +} - typename associated_allocator<handler_type>::type a( - (get_associated_allocator)(handler)); +#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + +template <typename Executor, typename StackAllocator, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) + CompletionToken> +inline auto spawn(const Executor& ex, allocator_arg_t, + StackAllocator&& stack_allocator, F&& function, CompletionToken&& token, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + >) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), + token, allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function))) +{ + return async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + detail::initiate_spawn<Executor>(ex), token, allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function)); +} - detail::spawn_helper<handler_type, Function> helper; - helper.data_.reset( - new detail::spawn_data<handler_type, Function>( - ASIO_MOVE_CAST(Handler)(handler), true, - ASIO_MOVE_CAST(Function)(function))); - helper.attributes_ = attributes; +template <typename ExecutionContext, typename StackAllocator, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type) CompletionToken> +inline auto spawn(ExecutionContext& ctx, allocator_arg_t, + StackAllocator&& stack_allocator, F&& function, CompletionToken&& token, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + >) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type>( + declval<detail::initiate_spawn< + typename ExecutionContext::executor_type>>(), + token, allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function))) +{ + return (spawn)(ctx.get_executor(), allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function), static_cast<CompletionToken&&>(token)); +} - ex.dispatch(helper, a); +template <typename Executor, typename StackAllocator, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken> +inline auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t, + StackAllocator&& stack_allocator, F&& function, CompletionToken&& token, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + >) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), token, + allocator_arg_t(), static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function))) +{ + return (spawn)(ctx.get_executor(), allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function), static_cast<CompletionToken&&>(token)); } -template <typename Handler, typename Function> -void spawn(basic_yield_context<Handler> ctx, - ASIO_MOVE_ARG(Function) function, - const boost::coroutines::attributes& attributes) +#endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + +#if defined(ASIO_HAS_BOOST_COROUTINE) + +namespace detail { + +template <typename Executor, typename Function, typename Handler> +class old_spawn_entry_point { - Handler handler(ctx.handler_); // Explicit copy that might be moved from. +public: + template <typename F, typename H> + old_spawn_entry_point(const Executor& ex, F&& f, H&& h) + : executor_(ex), + function_(static_cast<F&&>(f)), + handler_(static_cast<H&&>(h)) + { + } - typename associated_executor<Handler>::type ex( - (get_associated_executor)(handler)); + void operator()(spawned_thread_base* spawned_thread) + { + const basic_yield_context<Executor> yield(spawned_thread, executor_); + this->call(yield, + void_type<result_of_t<Function(basic_yield_context<Executor>)>>()); + } - typename associated_allocator<Handler>::type a( - (get_associated_allocator)(handler)); +private: + void call(const basic_yield_context<Executor>& yield, void_type<void>) + { + function_(yield); + static_cast<Handler&&>(handler_)(); + } - detail::spawn_helper<Handler, Function> helper; - helper.data_.reset( - new detail::spawn_data<Handler, Function>( - ASIO_MOVE_CAST(Handler)(handler), false, - ASIO_MOVE_CAST(Function)(function))); - helper.attributes_ = attributes; + template <typename T> + void call(const basic_yield_context<Executor>& yield, void_type<T>) + { + static_cast<Handler&&>(handler_)(function_(yield)); + } - ex.dispatch(helper, a); + Executor executor_; + Function function_; + Handler handler_; +}; + +inline void default_spawn_handler() {} + +} // namespace detail + +template <typename Function> +inline void spawn(Function&& function, + const boost::coroutines::attributes& attributes) +{ + associated_executor_t<decay_t<Function>> ex( + (get_associated_executor)(function)); + + asio::spawn(ex, static_cast<Function&&>(function), attributes); +} + +template <typename Handler, typename Function> +void spawn(Handler&& handler, Function&& function, + const boost::coroutines::attributes& attributes, + constraint_t< + !is_executor<decay_t<Handler>>::value && + !execution::is_executor<decay_t<Handler>>::value && + !is_convertible<Handler&, execution_context&>::value>) +{ + typedef associated_executor_t<decay_t<Handler>> executor_type; + executor_type ex((get_associated_executor)(handler)); + + (dispatch)(ex, + detail::spawned_thread_resumer( + detail::spawned_coroutine_thread::spawn( + detail::old_spawn_entry_point<executor_type, + decay_t<Function>, void (*)()>( + ex, static_cast<Function&&>(function), + &detail::default_spawn_handler), attributes))); +} + +template <typename Executor, typename Function> +void spawn(basic_yield_context<Executor> ctx, Function&& function, + const boost::coroutines::attributes& attributes) +{ + (dispatch)(ctx.get_executor(), + detail::spawned_thread_resumer( + detail::spawned_coroutine_thread::spawn( + detail::old_spawn_entry_point<Executor, + decay_t<Function>, void (*)()>( + ctx.get_executor(), static_cast<Function&&>(function), + &detail::default_spawn_handler), attributes))); } template <typename Function, typename Executor> -inline void spawn(const Executor& ex, - ASIO_MOVE_ARG(Function) function, +inline void spawn(const Executor& ex, Function&& function, const boost::coroutines::attributes& attributes, - typename enable_if<is_executor<Executor>::value>::type*) + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + >) { asio::spawn(asio::strand<Executor>(ex), - ASIO_MOVE_CAST(Function)(function), attributes); + static_cast<Function&&>(function), attributes); } template <typename Function, typename Executor> -inline void spawn(const strand<Executor>& ex, - ASIO_MOVE_ARG(Function) function, +inline void spawn(const strand<Executor>& ex, Function&& function, const boost::coroutines::attributes& attributes) { asio::spawn(asio::bind_executor( ex, &detail::default_spawn_handler), - ASIO_MOVE_CAST(Function)(function), attributes); + static_cast<Function&&>(function), attributes); } +#if !defined(ASIO_NO_TS_EXECUTORS) + template <typename Function> -inline void spawn(const asio::io_context::strand& s, - ASIO_MOVE_ARG(Function) function, +inline void spawn(const asio::io_context::strand& s, Function&& function, const boost::coroutines::attributes& attributes) { asio::spawn(asio::bind_executor( s, &detail::default_spawn_handler), - ASIO_MOVE_CAST(Function)(function), attributes); + static_cast<Function&&>(function), attributes); } +#endif // !defined(ASIO_NO_TS_EXECUTORS) + template <typename Function, typename ExecutionContext> -inline void spawn(ExecutionContext& ctx, - ASIO_MOVE_ARG(Function) function, +inline void spawn(ExecutionContext& ctx, Function&& function, const boost::coroutines::attributes& attributes, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type*) + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + >) { asio::spawn(ctx.get_executor(), - ASIO_MOVE_CAST(Function)(function), attributes); + static_cast<Function&&>(function), attributes); } -#endif // !defined(GENERATING_DOCUMENTATION) +#endif // defined(ASIO_HAS_BOOST_COROUTINE) } // namespace asio diff --git a/3rdparty/asio/include/asio/impl/src.cpp b/3rdparty/asio/include/asio/impl/src.cpp deleted file mode 100644 index fe56a795149..00000000000 --- a/3rdparty/asio/include/asio/impl/src.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// -// impl/src.cpp -// ~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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) -// - -#if defined(_MSC_VER) \ - || defined(__BORLANDC__) \ - || defined(__DMC__) -# pragma message ( \ - "This file is deprecated. " \ - "Please #include <asio/impl/src.hpp> instead.") -#elif defined(__GNUC__) \ - || defined(__HP_aCC) \ - || defined(__SUNPRO_CC) \ - || defined(__IBMCPP__) -# warning "This file is deprecated." -# warning "Please #include <asio/impl/src.hpp> instead." -#endif - -#include "asio/impl/src.hpp" diff --git a/3rdparty/asio/include/asio/impl/src.hpp b/3rdparty/asio/include/asio/impl/src.hpp index a22b1fb5311..28396195b06 100644 --- a/3rdparty/asio/include/asio/impl/src.hpp +++ b/3rdparty/asio/include/asio/impl/src.hpp @@ -2,7 +2,7 @@ // impl/src.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,14 +19,18 @@ # error Do not compile Asio library source with ASIO_HEADER_ONLY defined #endif +#include "asio/impl/any_completion_executor.ipp" +#include "asio/impl/any_io_executor.ipp" +#include "asio/impl/cancellation_signal.ipp" +#include "asio/impl/connect_pipe.ipp" #include "asio/impl/error.ipp" #include "asio/impl/error_code.ipp" #include "asio/impl/execution_context.ipp" #include "asio/impl/executor.ipp" -#include "asio/impl/handler_alloc_hook.ipp" #include "asio/impl/io_context.ipp" +#include "asio/impl/multiple_exceptions.ipp" #include "asio/impl/serial_port_base.ipp" -#include "asio/impl/system_executor.ipp" +#include "asio/impl/system_context.ipp" #include "asio/impl/thread_pool.ipp" #include "asio/detail/impl/buffer_sequence_adapter.ipp" #include "asio/detail/impl/descriptor_ops.ipp" @@ -34,15 +38,19 @@ #include "asio/detail/impl/epoll_reactor.ipp" #include "asio/detail/impl/eventfd_select_interrupter.ipp" #include "asio/detail/impl/handler_tracking.ipp" +#include "asio/detail/impl/io_uring_descriptor_service.ipp" +#include "asio/detail/impl/io_uring_file_service.ipp" +#include "asio/detail/impl/io_uring_socket_service_base.ipp" +#include "asio/detail/impl/io_uring_service.ipp" #include "asio/detail/impl/kqueue_reactor.ipp" #include "asio/detail/impl/null_event.ipp" #include "asio/detail/impl/pipe_select_interrupter.ipp" #include "asio/detail/impl/posix_event.ipp" #include "asio/detail/impl/posix_mutex.ipp" +#include "asio/detail/impl/posix_serial_port_service.ipp" #include "asio/detail/impl/posix_thread.ipp" #include "asio/detail/impl/posix_tss_ptr.ipp" #include "asio/detail/impl/reactive_descriptor_service.ipp" -#include "asio/detail/impl/reactive_serial_port_service.ipp" #include "asio/detail/impl/reactive_socket_service_base.ipp" #include "asio/detail/impl/resolver_service_base.ipp" #include "asio/detail/impl/scheduler.ipp" @@ -53,9 +61,11 @@ #include "asio/detail/impl/socket_select_interrupter.ipp" #include "asio/detail/impl/strand_executor_service.ipp" #include "asio/detail/impl/strand_service.ipp" +#include "asio/detail/impl/thread_context.ipp" #include "asio/detail/impl/throw_error.ipp" #include "asio/detail/impl/timer_queue_ptime.ipp" #include "asio/detail/impl/timer_queue_set.ipp" +#include "asio/detail/impl/win_iocp_file_service.ipp" #include "asio/detail/impl/win_iocp_handle_service.ipp" #include "asio/detail/impl/win_iocp_io_context.ipp" #include "asio/detail/impl/win_iocp_serial_port_service.ipp" @@ -69,6 +79,8 @@ #include "asio/detail/impl/winrt_ssocket_service_base.ipp" #include "asio/detail/impl/winrt_timer_scheduler.ipp" #include "asio/detail/impl/winsock_init.ipp" +#include "asio/execution/impl/bad_executor.ipp" +#include "asio/experimental/impl/channel_error.ipp" #include "asio/generic/detail/impl/endpoint.ipp" #include "asio/ip/impl/address.ipp" #include "asio/ip/impl/address_v4.ipp" diff --git a/3rdparty/asio/include/asio/impl/system_context.hpp b/3rdparty/asio/include/asio/impl/system_context.hpp new file mode 100644 index 00000000000..34b5a3a0659 --- /dev/null +++ b/3rdparty/asio/include/asio/impl/system_context.hpp @@ -0,0 +1,34 @@ +// +// impl/system_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_SYSTEM_CONTEXT_HPP +#define ASIO_IMPL_SYSTEM_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/system_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +inline system_context::executor_type +system_context::get_executor() noexcept +{ + return system_executor(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SYSTEM_CONTEXT_HPP diff --git a/3rdparty/asio/include/asio/impl/system_context.ipp b/3rdparty/asio/include/asio/impl/system_context.ipp new file mode 100644 index 00000000000..95fda4804da --- /dev/null +++ b/3rdparty/asio/include/asio/impl/system_context.ipp @@ -0,0 +1,92 @@ +// +// impl/system_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_SYSTEM_CONTEXT_IPP +#define ASIO_IMPL_SYSTEM_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/system_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +struct system_context::thread_function +{ + detail::scheduler* scheduler_; + + void operator()() + { +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(ASIO_NO_EXCEPTIONS) + asio::error_code ec; + scheduler_->run(ec); +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(ASIO_NO_EXCEPTIONS) + } +}; + +system_context::system_context() + : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + num_threads_ = detail::thread::hardware_concurrency() * 2; + num_threads_ = num_threads_ ? num_threads_ : 2; + threads_.create_threads(f, num_threads_); +} + +system_context::~system_context() +{ + scheduler_.work_finished(); + scheduler_.stop(); + threads_.join(); +} + +void system_context::stop() +{ + scheduler_.stop(); +} + +bool system_context::stopped() const noexcept +{ + return scheduler_.stopped(); +} + +void system_context::join() +{ + scheduler_.work_finished(); + threads_.join(); +} + +detail::scheduler& system_context::add_scheduler(detail::scheduler* s) +{ + detail::scoped_ptr<detail::scheduler> scoped_impl(s); + asio::add_service<detail::scheduler>(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SYSTEM_CONTEXT_IPP diff --git a/3rdparty/asio/include/asio/impl/system_executor.hpp b/3rdparty/asio/include/asio/impl/system_executor.hpp index 12ca9b958d4..099b2d63ef2 100644 --- a/3rdparty/asio/include/asio/impl/system_executor.hpp +++ b/3rdparty/asio/include/asio/impl/system_executor.hpp @@ -2,7 +2,7 @@ // impl/system_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,46 +17,133 @@ #include "asio/detail/executor_op.hpp" #include "asio/detail/global.hpp" -#include "asio/detail/recycling_allocator.hpp" #include "asio/detail/type_traits.hpp" -#include "asio/execution_context.hpp" +#include "asio/system_context.hpp" #include "asio/detail/push_options.hpp" namespace asio { -inline execution_context& system_executor::context() const ASIO_NOEXCEPT +template <typename Blocking, typename Relationship, typename Allocator> +inline system_context& +basic_system_executor<Blocking, Relationship, Allocator>::query( + execution::context_t) noexcept { - return detail::global<context_impl>(); + return detail::global<system_context>(); } -template <typename Function, typename Allocator> -void system_executor::dispatch( - ASIO_MOVE_ARG(Function) f, const Allocator&) const +template <typename Blocking, typename Relationship, typename Allocator> +inline std::size_t +basic_system_executor<Blocking, Relationship, Allocator>::query( + execution::occupancy_t) const noexcept { - typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f)); - asio_handler_invoke_helpers::invoke(tmp, tmp); + return detail::global<system_context>().num_threads_; } -template <typename Function, typename Allocator> -void system_executor::post( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Blocking, typename Relationship, typename Allocator> +template <typename Function> +inline void +basic_system_executor<Blocking, Relationship, Allocator>::do_execute( + Function&& f, execution::blocking_t::possibly_t) const { - context_impl& ctx = detail::global<context_impl>(); + // Obtain a non-const instance of the function. + detail::non_const_lvalue<Function> f2(f); + +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + static_cast<decay_t<Function>&&>(f2.value)(); +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(ASIO_NO_EXCEPTIONS) +} + +template <typename Blocking, typename Relationship, typename Allocator> +template <typename Function> +inline void +basic_system_executor<Blocking, Relationship, Allocator>::do_execute( + Function&& f, execution::blocking_t::always_t) const +{ + // Obtain a non-const instance of the function. + detail::non_const_lvalue<Function> f2(f); + +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + static_cast<decay_t<Function>&&>(f2.value)(); +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(ASIO_NO_EXCEPTIONS) +} + +template <typename Blocking, typename Relationship, typename Allocator> +template <typename Function> +void basic_system_executor<Blocking, Relationship, Allocator>::do_execute( + Function&& f, execution::blocking_t::never_t) const +{ + system_context& ctx = detail::global<system_context>(); + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<decay_t<Function>, Allocator> op; + typename op::ptr p = { detail::addressof(allocator_), + op::ptr::allocate(allocator_), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), allocator_); + + if (is_same<Relationship, execution::relationship_t::continuation_t>::value) + { + ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &ctx, 0, "execute(blk=never,rel=cont)")); + } + else + { + ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &ctx, 0, "execute(blk=never,rel=fork)")); + } + + ctx.scheduler_.post_immediate_completion(p.p, + is_same<Relationship, execution::relationship_t::continuation_t>::value); + p.v = p.p = 0; +} - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); +#if !defined(ASIO_NO_TS_EXECUTORS) +template <typename Blocking, typename Relationship, typename Allocator> +inline system_context& basic_system_executor< + Blocking, Relationship, Allocator>::context() const noexcept +{ + return detail::global<system_context>(); +} - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); +template <typename Blocking, typename Relationship, typename Allocator> +template <typename Function, typename OtherAllocator> +void basic_system_executor<Blocking, Relationship, Allocator>::dispatch( + Function&& f, const OtherAllocator&) const +{ + decay_t<Function>(static_cast<Function&&>(f))(); +} + +template <typename Blocking, typename Relationship, typename Allocator> +template <typename Function, typename OtherAllocator> +void basic_system_executor<Blocking, Relationship, Allocator>::post( + Function&& f, const OtherAllocator& a) const +{ + system_context& ctx = detail::global<system_context>(); // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<decay_t<Function>, OtherAllocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); ASIO_HANDLER_CREATION((ctx, *p.p, "system_executor", &this->context(), 0, "post")); @@ -65,25 +152,17 @@ void system_executor::post( p.v = p.p = 0; } -template <typename Function, typename Allocator> -void system_executor::defer( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Blocking, typename Relationship, typename Allocator> +template <typename Function, typename OtherAllocator> +void basic_system_executor<Blocking, Relationship, Allocator>::defer( + Function&& f, const OtherAllocator& a) const { - context_impl& ctx = detail::global<context_impl>(); - - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); - - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); + system_context& ctx = detail::global<system_context>(); // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<decay_t<Function>, OtherAllocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); ASIO_HANDLER_CREATION((ctx, *p.p, "system_executor", &this->context(), 0, "defer")); @@ -91,6 +170,7 @@ void system_executor::defer( ctx.scheduler_.post_immediate_completion(p.p, true); p.v = p.p = 0; } +#endif // !defined(ASIO_NO_TS_EXECUTORS) } // namespace asio diff --git a/3rdparty/asio/include/asio/impl/system_executor.ipp b/3rdparty/asio/include/asio/impl/system_executor.ipp deleted file mode 100644 index 6e5b16e73b7..00000000000 --- a/3rdparty/asio/include/asio/impl/system_executor.ipp +++ /dev/null @@ -1,57 +0,0 @@ -// -// impl/system_executor.ipp -// ~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_IMPL_SYSTEM_EXECUTOR_IPP -#define ASIO_IMPL_SYSTEM_EXECUTOR_IPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" -#include "asio/system_executor.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -struct system_executor::thread_function -{ - detail::scheduler* scheduler_; - - void operator()() - { - asio::error_code ec; - scheduler_->run(ec); - } -}; - -system_executor::context_impl::context_impl() - : scheduler_(use_service<detail::scheduler>(*this)) -{ - scheduler_.work_started(); - - thread_function f = { &scheduler_ }; - std::size_t num_threads = detail::thread::hardware_concurrency() * 2; - threads_.create_threads(f, num_threads ? num_threads : 2); -} - -system_executor::context_impl::~context_impl() -{ - scheduler_.work_finished(); - scheduler_.stop(); - threads_.join(); -} - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // ASIO_IMPL_SYSTEM_EXECUTOR_IPP diff --git a/3rdparty/asio/include/asio/impl/thread_pool.hpp b/3rdparty/asio/include/asio/impl/thread_pool.hpp index db7d5c01e36..3aed249781a 100644 --- a/3rdparty/asio/include/asio/impl/thread_pool.hpp +++ b/3rdparty/asio/include/asio/impl/thread_pool.hpp @@ -2,7 +2,7 @@ // impl/thread_pool.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,9 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include "asio/detail/blocking_executor_op.hpp" #include "asio/detail/executor_op.hpp" #include "asio/detail/fenced_block.hpp" -#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/type_traits.hpp" #include "asio/execution_context.hpp" @@ -26,117 +27,248 @@ namespace asio { inline thread_pool::executor_type -thread_pool::get_executor() ASIO_NOEXCEPT +thread_pool::get_executor() noexcept { return executor_type(*this); } -inline thread_pool& -thread_pool::executor_type::context() const ASIO_NOEXCEPT +inline thread_pool::executor_type +thread_pool::executor() noexcept { - return pool_; + return executor_type(*this); } -inline void -thread_pool::executor_type::on_work_started() const ASIO_NOEXCEPT +template <typename Allocator, unsigned int Bits> +thread_pool::basic_executor_type<Allocator, Bits>& +thread_pool::basic_executor_type<Allocator, Bits>::operator=( + const basic_executor_type& other) noexcept { - pool_.scheduler_.work_started(); + if (this != &other) + { + thread_pool* old_thread_pool = pool_; + pool_ = other.pool_; + allocator_ = other.allocator_; + bits_ = other.bits_; + if (Bits & outstanding_work_tracked) + { + if (pool_) + pool_->scheduler_.work_started(); + if (old_thread_pool) + old_thread_pool->scheduler_.work_finished(); + } + } + return *this; } -inline void thread_pool::executor_type::on_work_finished() -const ASIO_NOEXCEPT +template <typename Allocator, unsigned int Bits> +thread_pool::basic_executor_type<Allocator, Bits>& +thread_pool::basic_executor_type<Allocator, Bits>::operator=( + basic_executor_type&& other) noexcept { - pool_.scheduler_.work_finished(); + if (this != &other) + { + thread_pool* old_thread_pool = pool_; + pool_ = other.pool_; + allocator_ = std::move(other.allocator_); + bits_ = other.bits_; + if (Bits & outstanding_work_tracked) + { + other.pool_ = 0; + if (old_thread_pool) + old_thread_pool->scheduler_.work_finished(); + } + } + return *this; } -template <typename Function, typename Allocator> -void thread_pool::executor_type::dispatch( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Allocator, unsigned int Bits> +inline bool thread_pool::basic_executor_type<Allocator, + Bits>::running_in_this_thread() const noexcept { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); + return pool_->scheduler_.can_dispatch(); +} - // Invoke immediately if we are already inside the thread pool. - if (pool_.scheduler_.can_dispatch()) +template <typename Allocator, unsigned int Bits> +template <typename Function> +void thread_pool::basic_executor_type<Allocator, + Bits>::do_execute(Function&& f, false_type) const +{ + typedef decay_t<Function> function_type; + + // Invoke immediately if the blocking.possibly property is enabled and we are + // already inside the thread pool. + if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch()) { - detail::fenced_block b(detail::fenced_block::full); - asio_handler_invoke_helpers::invoke(tmp, tmp); - return; - } + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(f)); - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif // !defined(ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + static_cast<function_type&&>(tmp)(); + return; +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + pool_->scheduler_.capture_current_exception(); + return; + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(allocator_), + op::ptr::allocate(allocator_), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), allocator_); - ASIO_HANDLER_CREATION((pool_, *p.p, - "thread_pool", &this->context(), 0, "dispatch")); + if ((bits_ & relationship_continuation) != 0) + { + ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "execute(blk=never,rel=cont)")); + } + else + { + ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "execute(blk=never,rel=fork)")); + } - pool_.scheduler_.post_immediate_completion(p.p, false); + pool_->scheduler_.post_immediate_completion(p.p, + (bits_ & relationship_continuation) != 0); p.v = p.p = 0; } -template <typename Function, typename Allocator> -void thread_pool::executor_type::post( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Allocator, unsigned int Bits> +template <typename Function> +void thread_pool::basic_executor_type<Allocator, + Bits>::do_execute(Function&& f, true_type) const { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); + // Obtain a non-const instance of the function. + detail::non_const_lvalue<Function> f2(f); + + // Invoke immediately if we are already inside the thread pool. + if (pool_->scheduler_.can_dispatch()) + { +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif // !defined(ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + static_cast<decay_t<Function>&&>(f2.value)(); + return; +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); + // Construct an operation to wrap the function. + typedef decay_t<Function> function_type; + detail::blocking_executor_op<function_type> op(f2.value); + + ASIO_HANDLER_CREATION((*pool_, op, + "thread_pool", pool_, 0, "execute(blk=always)")); + + pool_->scheduler_.post_immediate_completion(&op, false); + op.wait(); +} + +#if !defined(ASIO_NO_TS_EXECUTORS) +template <typename Allocator, unsigned int Bits> +inline thread_pool& thread_pool::basic_executor_type< + Allocator, Bits>::context() const noexcept +{ + return *pool_; +} + +template <typename Allocator, unsigned int Bits> +inline void thread_pool::basic_executor_type<Allocator, + Bits>::on_work_started() const noexcept +{ + pool_->scheduler_.work_started(); +} + +template <typename Allocator, unsigned int Bits> +inline void thread_pool::basic_executor_type<Allocator, + Bits>::on_work_finished() const noexcept +{ + pool_->scheduler_.work_finished(); +} + +template <typename Allocator, unsigned int Bits> +template <typename Function, typename OtherAllocator> +void thread_pool::basic_executor_type<Allocator, Bits>::dispatch( + Function&& f, const OtherAllocator& a) const +{ + typedef decay_t<Function> function_type; + + // Invoke immediately if we are already inside the thread pool. + if (pool_->scheduler_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(f)); + + detail::fenced_block b(detail::fenced_block::full); + static_cast<function_type&&>(tmp)(); + return; + } // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<function_type, OtherAllocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); - ASIO_HANDLER_CREATION((pool_, *p.p, - "thread_pool", &this->context(), 0, "post")); + ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "dispatch")); - pool_.scheduler_.post_immediate_completion(p.p, false); + pool_->scheduler_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template <typename Function, typename Allocator> -void thread_pool::executor_type::defer( - ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template <typename Allocator, unsigned int Bits> +template <typename Function, typename OtherAllocator> +void thread_pool::basic_executor_type<Allocator, Bits>::post( + Function&& f, const OtherAllocator& a) const { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(f)); - - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); + typedef decay_t<Function> function_type; // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef detail::executor_op<function_type, OtherAllocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); - ASIO_HANDLER_CREATION((pool_, *p.p, - "thread_pool", &this->context(), 0, "defer")); + ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "post")); - pool_.scheduler_.post_immediate_completion(p.p, true); + pool_->scheduler_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -inline bool -thread_pool::executor_type::running_in_this_thread() const ASIO_NOEXCEPT +template <typename Allocator, unsigned int Bits> +template <typename Function, typename OtherAllocator> +void thread_pool::basic_executor_type<Allocator, Bits>::defer( + Function&& f, const OtherAllocator& a) const { - return pool_.scheduler_.can_dispatch(); + typedef decay_t<Function> function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, OtherAllocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(f), a); + + ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "defer")); + + pool_->scheduler_.post_immediate_completion(p.p, true); + p.v = p.p = 0; } +#endif // !defined(ASIO_NO_TS_EXECUTORS) } // namespace asio diff --git a/3rdparty/asio/include/asio/impl/thread_pool.ipp b/3rdparty/asio/include/asio/impl/thread_pool.ipp index f56b94acb40..3f327e4610b 100644 --- a/3rdparty/asio/include/asio/impl/thread_pool.ipp +++ b/3rdparty/asio/include/asio/impl/thread_pool.ipp @@ -2,7 +2,7 @@ // impl/thread_pool.ipp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,7 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include <stdexcept> #include "asio/thread_pool.hpp" +#include "asio/detail/throw_exception.hpp" #include "asio/detail/push_options.hpp" @@ -28,34 +30,75 @@ struct thread_pool::thread_function void operator()() { - asio::error_code ec; - scheduler_->run(ec); +#if !defined(ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(ASIO_NO_EXCEPTIONS) + asio::error_code ec; + scheduler_->run(ec); +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(ASIO_NO_EXCEPTIONS) } }; +#if !defined(ASIO_NO_TS_EXECUTORS) +namespace detail { + +inline long default_thread_pool_size() +{ + std::size_t num_threads = thread::hardware_concurrency() * 2; + num_threads = num_threads == 0 ? 2 : num_threads; + return static_cast<long>(num_threads); +} + +} // namespace detail + thread_pool::thread_pool() - : scheduler_(use_service<detail::scheduler>(*this)) + : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))), + num_threads_(detail::default_thread_pool_size()) { scheduler_.work_started(); thread_function f = { &scheduler_ }; - std::size_t num_threads = detail::thread::hardware_concurrency() * 2; - threads_.create_threads(f, num_threads ? num_threads : 2); + threads_.create_threads(f, static_cast<std::size_t>(num_threads_)); +} +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +namespace detail { + +inline long clamp_thread_pool_size(std::size_t n) +{ + if (n > 0x7FFFFFFF) + { + std::out_of_range ex("thread pool size"); + asio::detail::throw_exception(ex); + } + return static_cast<long>(n & 0x7FFFFFFF); } +} // namespace detail + thread_pool::thread_pool(std::size_t num_threads) - : scheduler_(use_service<detail::scheduler>(*this)) + : scheduler_(add_scheduler(new detail::scheduler( + *this, num_threads == 1 ? 1 : 0, false))), + num_threads_(detail::clamp_thread_pool_size(num_threads)) { scheduler_.work_started(); thread_function f = { &scheduler_ }; - threads_.create_threads(f, num_threads); + threads_.create_threads(f, static_cast<std::size_t>(num_threads_)); } thread_pool::~thread_pool() { stop(); join(); + shutdown(); } void thread_pool::stop() @@ -63,8 +106,31 @@ void thread_pool::stop() scheduler_.stop(); } +void thread_pool::attach() +{ + ++num_threads_; + thread_function f = { &scheduler_ }; + f(); +} + void thread_pool::join() { + if (num_threads_) + scheduler_.work_finished(); + + if (!threads_.empty()) + threads_.join(); +} + +detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s) +{ + detail::scoped_ptr<detail::scheduler> scoped_impl(s); + asio::add_service<detail::scheduler>(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + +void thread_pool::wait() +{ scheduler_.work_finished(); threads_.join(); } diff --git a/3rdparty/asio/include/asio/impl/use_awaitable.hpp b/3rdparty/asio/include/asio/impl/use_awaitable.hpp new file mode 100644 index 00000000000..3cd95165c4f --- /dev/null +++ b/3rdparty/asio/include/asio/impl/use_awaitable.hpp @@ -0,0 +1,301 @@ +// +// impl/use_awaitable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IMPL_USE_AWAITABLE_HPP +#define ASIO_IMPL_USE_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/cancellation_signal.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +template <typename Executor, typename T> +class awaitable_handler_base + : public awaitable_thread<Executor> +{ +public: + typedef void result_type; + typedef awaitable<T, Executor> awaitable_type; + + // Construct from the entry point of a new thread of execution. + awaitable_handler_base(awaitable<awaitable_thread_entry_point, Executor> a, + const Executor& ex, cancellation_slot pcs, cancellation_state cs) + : awaitable_thread<Executor>(std::move(a), ex, pcs, cs) + { + } + + // Transfer ownership from another awaitable_thread. + explicit awaitable_handler_base(awaitable_thread<Executor>* h) + : awaitable_thread<Executor>(std::move(*h)) + { + } + +protected: + awaitable_frame<T, Executor>* frame() noexcept + { + return static_cast<awaitable_frame<T, Executor>*>( + this->entry_point()->top_of_stack_); + } +}; + +template <typename, typename...> +class awaitable_handler; + +template <typename Executor> +class awaitable_handler<Executor> + : public awaitable_handler_base<Executor, void> +{ +public: + using awaitable_handler_base<Executor, void>::awaitable_handler_base; + + void operator()() + { + this->frame()->attach_thread(this); + this->frame()->return_void(); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor> +class awaitable_handler<Executor, asio::error_code> + : public awaitable_handler_base<Executor, void> +{ +public: + using awaitable_handler_base<Executor, void>::awaitable_handler_base; + + void operator()(const asio::error_code& ec) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_void(); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor> +class awaitable_handler<Executor, std::exception_ptr> + : public awaitable_handler_base<Executor, void> +{ +public: + using awaitable_handler_base<Executor, void>::awaitable_handler_base; + + void operator()(std::exception_ptr ex) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_void(); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename T> +class awaitable_handler<Executor, T> + : public awaitable_handler_base<Executor, T> +{ +public: + using awaitable_handler_base<Executor, T>::awaitable_handler_base; + + template <typename Arg> + void operator()(Arg&& arg) + { + this->frame()->attach_thread(this); + this->frame()->return_value(std::forward<Arg>(arg)); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename T> +class awaitable_handler<Executor, asio::error_code, T> + : public awaitable_handler_base<Executor, T> +{ +public: + using awaitable_handler_base<Executor, T>::awaitable_handler_base; + + template <typename Arg> + void operator()(const asio::error_code& ec, Arg&& arg) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_value(std::forward<Arg>(arg)); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename T> +class awaitable_handler<Executor, std::exception_ptr, T> + : public awaitable_handler_base<Executor, T> +{ +public: + using awaitable_handler_base<Executor, T>::awaitable_handler_base; + + template <typename Arg> + void operator()(std::exception_ptr ex, Arg&& arg) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_value(std::forward<Arg>(arg)); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename... Ts> +class awaitable_handler + : public awaitable_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using awaitable_handler_base<Executor, + std::tuple<Ts...>>::awaitable_handler_base; + + template <typename... Args> + void operator()(Args&&... args) + { + this->frame()->attach_thread(this); + this->frame()->return_values(std::forward<Args>(args)...); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename... Ts> +class awaitable_handler<Executor, asio::error_code, Ts...> + : public awaitable_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using awaitable_handler_base<Executor, + std::tuple<Ts...>>::awaitable_handler_base; + + template <typename... Args> + void operator()(const asio::error_code& ec, Args&&... args) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_values(std::forward<Args>(args)...); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename... Ts> +class awaitable_handler<Executor, std::exception_ptr, Ts...> + : public awaitable_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using awaitable_handler_base<Executor, + std::tuple<Ts...>>::awaitable_handler_base; + + template <typename... Args> + void operator()(std::exception_ptr ex, Args&&... args) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_values(std::forward<Args>(args)...); + this->frame()->clear_cancellation_slot(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +#if defined(_MSC_VER) +template <typename T> +T dummy_return() +{ + return std::move(*static_cast<T*>(nullptr)); +} + +template <> +inline void dummy_return() +{ +} +#endif // defined(_MSC_VER) + +template <typename Executor, typename R, typename... Args> +class async_result<use_awaitable_t<Executor>, R(Args...)> +{ +public: + typedef typename detail::awaitable_handler< + Executor, decay_t<Args>...> handler_type; + typedef typename handler_type::awaitable_type return_type; + + template <typename Initiation, typename... InitArgs> +#if defined(__APPLE_CC__) && (__clang_major__ == 13) + __attribute__((noinline)) +#endif // defined(__APPLE_CC__) && (__clang_major__ == 13) + static handler_type* do_init( + detail::awaitable_frame_base<Executor>* frame, Initiation& initiation, + use_awaitable_t<Executor> u, InitArgs&... args) + { + (void)u; + ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_)); + handler_type handler(frame->detach_thread()); + std::move(initiation)(std::move(handler), std::move(args)...); + return nullptr; + } + + template <typename Initiation, typename... InitArgs> + static return_type initiate(Initiation initiation, + use_awaitable_t<Executor> u, InitArgs... args) + { + co_await [&] (auto* frame) + { + return do_init(frame, initiation, u, args...); + }; + + for (;;) {} // Never reached. +#if defined(_MSC_VER) + co_return dummy_return<typename return_type::value_type>(); +#endif // defined(_MSC_VER) + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_USE_AWAITABLE_HPP diff --git a/3rdparty/asio/include/asio/impl/use_future.hpp b/3rdparty/asio/include/asio/impl/use_future.hpp index e06c4001742..579b93f5f30 100644 --- a/3rdparty/asio/include/asio/impl/use_future.hpp +++ b/3rdparty/asio/include/asio/impl/use_future.hpp @@ -2,7 +2,7 @@ // impl/use_future.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,11 +16,12 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include <future> #include <tuple> #include "asio/async_result.hpp" #include "asio/detail/memory.hpp" +#include "asio/dispatch.hpp" #include "asio/error_code.hpp" +#include "asio/execution.hpp" #include "asio/packaged_task.hpp" #include "asio/system_error.hpp" #include "asio/system_executor.hpp" @@ -30,17 +31,15 @@ namespace asio { namespace detail { -#if defined(ASIO_HAS_VARIADIC_TEMPLATES) - template <typename T, typename F, typename... Args> inline void promise_invoke_and_set(std::promise<T>& p, - F& f, ASIO_MOVE_ARG(Args)... args) + F& f, Args&&... args) { #if !defined(ASIO_NO_EXCEPTIONS) try #endif // !defined(ASIO_NO_EXCEPTIONS) { - p.set_value(f(ASIO_MOVE_CAST(Args)(args)...)); + p.set_value(f(static_cast<Args&&>(args)...)); } #if !defined(ASIO_NO_EXCEPTIONS) catch (...) @@ -52,13 +51,13 @@ inline void promise_invoke_and_set(std::promise<T>& p, template <typename F, typename... Args> inline void promise_invoke_and_set(std::promise<void>& p, - F& f, ASIO_MOVE_ARG(Args)... args) + F& f, Args&&... args) { #if !defined(ASIO_NO_EXCEPTIONS) try #endif // !defined(ASIO_NO_EXCEPTIONS) { - f(ASIO_MOVE_CAST(Args)(args)...); + f(static_cast<Args&&>(args)...); p.set_value(); } #if !defined(ASIO_NO_EXCEPTIONS) @@ -69,112 +68,15 @@ inline void promise_invoke_and_set(std::promise<void>& p, #endif // !defined(ASIO_NO_EXCEPTIONS) } -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - -template <typename T, typename F> -inline void promise_invoke_and_set(std::promise<T>& p, F& f) -{ -#if !defined(ASIO_NO_EXCEPTIONS) - try -#endif // !defined(ASIO_NO_EXCEPTIONS) - { - p.set_value(f()); - } -#if !defined(ASIO_NO_EXCEPTIONS) - catch (...) - { - p.set_exception(std::current_exception()); - } -#endif // !defined(ASIO_NO_EXCEPTIONS) -} - -template <typename F, typename Args> -inline void promise_invoke_and_set(std::promise<void>& p, F& f) -{ -#if !defined(ASIO_NO_EXCEPTIONS) - try -#endif // !defined(ASIO_NO_EXCEPTIONS) - { - f(); - p.set_value(); -#if !defined(ASIO_NO_EXCEPTIONS) - } - catch (...) - { - p.set_exception(std::current_exception()); - } -#endif // !defined(ASIO_NO_EXCEPTIONS) -} - -#if defined(ASIO_NO_EXCEPTIONS) - -#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ - template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \ - inline void promise_invoke_and_set(std::promise<T>& p, \ - F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ - { \ - p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \ - } \ - \ - template <typename F, ASIO_VARIADIC_TPARAMS(n)> \ - inline void promise_invoke_and_set(std::promise<void>& p, \ - F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ - { \ - f(ASIO_VARIADIC_MOVE_ARGS(n)); \ - p.set_value(); \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF) -#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF - -#else // defined(ASIO_NO_EXCEPTIONS) - -#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ - template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \ - inline void promise_invoke_and_set(std::promise<T>& p, \ - F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ - { \ - try \ - { \ - p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \ - } \ - catch (...) \ - { \ - p.set_exception(std::current_exception()); \ - } \ - } \ - \ - template <typename F, ASIO_VARIADIC_TPARAMS(n)> \ - inline void promise_invoke_and_set(std::promise<void>& p, \ - F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ - { \ - try \ - { \ - f(ASIO_VARIADIC_MOVE_ARGS(n)); \ - p.set_value(); \ - } \ - catch (...) \ - { \ - p.set_exception(std::current_exception()); \ - } \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF) -#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF - -#endif // defined(ASIO_NO_EXCEPTIONS) - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) - // A function object adapter to invoke a nullary function object and capture // any exception thrown into a promise. template <typename T, typename F> class promise_invoker { public: - promise_invoker(const shared_ptr<std::promise<T> >& p, - ASIO_MOVE_ARG(F) f) - : p_(p), f_(f) + promise_invoker(const shared_ptr<std::promise<T>>& p, + F&& f) + : p_(p), f_(static_cast<F&&>(f)) { } @@ -195,63 +97,94 @@ public: } private: - shared_ptr<std::promise<T> > p_; - typename decay<F>::type f_; + shared_ptr<std::promise<T>> p_; + decay_t<F> f_; }; // An executor that adapts the system_executor to capture any exeption thrown // by a submitted function object and save it into a promise. -template <typename T> +template <typename T, typename Blocking = execution::blocking_t::possibly_t> class promise_executor { public: - explicit promise_executor(const shared_ptr<std::promise<T> >& p) + explicit promise_executor(const shared_ptr<std::promise<T>>& p) : p_(p) { } - execution_context& context() const ASIO_NOEXCEPT + execution_context& query(execution::context_t) const noexcept + { + return asio::query(system_executor(), execution::context); + } + + static constexpr Blocking query(execution::blocking_t) + { + return Blocking(); + } + + promise_executor<T, execution::blocking_t::possibly_t> + require(execution::blocking_t::possibly_t) const + { + return promise_executor<T, execution::blocking_t::possibly_t>(p_); + } + + promise_executor<T, execution::blocking_t::never_t> + require(execution::blocking_t::never_t) const + { + return promise_executor<T, execution::blocking_t::never_t>(p_); + } + + template <typename F> + void execute(F&& f) const + { + asio::require(system_executor(), Blocking()).execute( + promise_invoker<T, F>(p_, static_cast<F&&>(f))); + } + +#if !defined(ASIO_NO_TS_EXECUTORS) + execution_context& context() const noexcept { return system_executor().context(); } - void on_work_started() const ASIO_NOEXCEPT {} - void on_work_finished() const ASIO_NOEXCEPT {} + void on_work_started() const noexcept {} + void on_work_finished() const noexcept {} template <typename F, typename A> - void dispatch(ASIO_MOVE_ARG(F) f, const A&) const + void dispatch(F&& f, const A&) const { - promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f))(); + promise_invoker<T, F>(p_, static_cast<F&&>(f))(); } template <typename F, typename A> - void post(ASIO_MOVE_ARG(F) f, const A& a) const + void post(F&& f, const A& a) const { system_executor().post( - promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a); + promise_invoker<T, F>(p_, static_cast<F&&>(f)), a); } template <typename F, typename A> - void defer(ASIO_MOVE_ARG(F) f, const A& a) const + void defer(F&& f, const A& a) const { system_executor().defer( - promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a); + promise_invoker<T, F>(p_, static_cast<F&&>(f)), a); } +#endif // !defined(ASIO_NO_TS_EXECUTORS) friend bool operator==(const promise_executor& a, - const promise_executor& b) ASIO_NOEXCEPT + const promise_executor& b) noexcept { return a.p_ == b.p_; } friend bool operator!=(const promise_executor& a, - const promise_executor& b) ASIO_NOEXCEPT + const promise_executor& b) noexcept { return a.p_ != b.p_; } private: - shared_ptr<std::promise<T> > p_; + shared_ptr<std::promise<T>> p_; }; // The base class for all completion handlers that create promises. @@ -261,7 +194,7 @@ class promise_creator public: typedef promise_executor<T> executor_type; - executor_type get_executor() const ASIO_NOEXCEPT + executor_type get_executor() const noexcept { return executor_type(p_); } @@ -277,13 +210,11 @@ protected: template <typename Allocator> void create_promise(const Allocator& a) { - p_ = std::allocate_shared<std::promise<T>>( - typename Allocator::template rebind<char>::other(a), - std::allocator_arg, - typename Allocator::template rebind<char>::other(a)); + ASIO_REBIND_ALLOC(Allocator, char) b(a); + p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b); } - shared_ptr<std::promise<T> > p_; + shared_ptr<std::promise<T>> p_; }; // For completion signature void(). @@ -342,9 +273,9 @@ class promise_handler_1 { public: template <typename Arg> - void operator()(ASIO_MOVE_ARG(Arg) arg) + void operator()(Arg&& arg) { - this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg)); + this->p_->set_value(static_cast<Arg&&>(arg)); } }; @@ -356,7 +287,7 @@ class promise_handler_ec_1 public: template <typename Arg> void operator()(const asio::error_code& ec, - ASIO_MOVE_ARG(Arg) arg) + Arg&& arg) { if (ec) { @@ -365,7 +296,7 @@ public: asio::system_error(ec))); } else - this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg)); + this->p_->set_value(static_cast<Arg&&>(arg)); } }; @@ -377,12 +308,12 @@ class promise_handler_ex_1 public: template <typename Arg> void operator()(const std::exception_ptr& ex, - ASIO_MOVE_ARG(Arg) arg) + Arg&& arg) { if (ex) this->p_->set_exception(ex); else - this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg)); + this->p_->set_value(static_cast<Arg&&>(arg)); } }; @@ -392,31 +323,13 @@ class promise_handler_n : public promise_creator<T> { public: -#if defined(ASIO_HAS_VARIADIC_TEMPLATES) - template <typename... Args> - void operator()(ASIO_MOVE_ARG(Args)... args) + void operator()(Args&&... args) { this->p_->set_value( std::forward_as_tuple( - ASIO_MOVE_CAST(Args)(args)...)); + static_cast<Args&&>(args)...)); } - -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - -#define ASIO_PRIVATE_CALL_OP_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \ - {\ - this->p_->set_value( \ - std::forward_as_tuple( \ - ASIO_VARIADIC_MOVE_ARGS(n))); \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) -#undef ASIO_PRIVATE_CALL_OP_DEF - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) }; // For completion signature void(error_code, T1, ..., Tn); @@ -425,11 +338,8 @@ class promise_handler_ec_n : public promise_creator<T> { public: -#if defined(ASIO_HAS_VARIADIC_TEMPLATES) - template <typename... Args> - void operator()(const asio::error_code& ec, - ASIO_MOVE_ARG(Args)... args) + void operator()(const asio::error_code& ec, Args&&... args) { if (ec) { @@ -441,35 +351,9 @@ public: { this->p_->set_value( std::forward_as_tuple( - ASIO_MOVE_CAST(Args)(args)...)); + static_cast<Args&&>(args)...)); } } - -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - -#define ASIO_PRIVATE_CALL_OP_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - void operator()(const asio::error_code& ec, \ - ASIO_VARIADIC_MOVE_PARAMS(n)) \ - {\ - if (ec) \ - { \ - this->p_->set_exception( \ - std::make_exception_ptr( \ - asio::system_error(ec))); \ - } \ - else \ - { \ - this->p_->set_value( \ - std::forward_as_tuple( \ - ASIO_VARIADIC_MOVE_ARGS(n))); \ - } \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) -#undef ASIO_PRIVATE_CALL_OP_DEF - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) }; // For completion signature void(exception_ptr, T1, ..., Tn); @@ -478,11 +362,9 @@ class promise_handler_ex_n : public promise_creator<T> { public: -#if defined(ASIO_HAS_VARIADIC_TEMPLATES) - template <typename... Args> void operator()(const std::exception_ptr& ex, - ASIO_MOVE_ARG(Args)... args) + Args&&... args) { if (ex) this->p_->set_exception(ex); @@ -490,31 +372,9 @@ public: { this->p_->set_value( std::forward_as_tuple( - ASIO_MOVE_CAST(Args)(args)...)); + static_cast<Args&&>(args)...)); } } - -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - -#define ASIO_PRIVATE_CALL_OP_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - void operator()(const std::exception_ptr& ex, \ - ASIO_VARIADIC_MOVE_PARAMS(n)) \ - {\ - if (ex) \ - this->p_->set_exception(ex); \ - else \ - { \ - this->p_->set_value( \ - std::forward_as_tuple( \ - ASIO_VARIADIC_MOVE_ARGS(n))); \ - } \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) -#undef ASIO_PRIVATE_CALL_OP_DEF - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) }; // Helper template to choose the appropriate concrete promise handler @@ -547,15 +407,15 @@ class promise_handler_selector<void(std::exception_ptr, Arg)> template <typename... Arg> class promise_handler_selector<void(Arg...)> - : public promise_handler_n<std::tuple<Arg...> > {}; + : public promise_handler_n<std::tuple<Arg...>> {}; template <typename... Arg> class promise_handler_selector<void(asio::error_code, Arg...)> - : public promise_handler_ec_n<std::tuple<Arg...> > {}; + : public promise_handler_ec_n<std::tuple<Arg...>> {}; template <typename... Arg> class promise_handler_selector<void(std::exception_ptr, Arg...)> - : public promise_handler_ex_n<std::tuple<Arg...> > {}; + : public promise_handler_ex_n<std::tuple<Arg...>> {}; // Completion handlers produced from the use_future completion token, when not // using use_future::operator(). @@ -573,7 +433,7 @@ public: this->create_promise(allocator_); } - allocator_type get_allocator() const ASIO_NOEXCEPT + allocator_type get_allocator() const noexcept { return allocator_; } @@ -582,23 +442,26 @@ private: Allocator allocator_; }; -template <typename Function, typename Signature, typename Allocator> -inline void asio_handler_invoke(Function& f, - promise_handler<Signature, Allocator>* h) +template <typename Function> +struct promise_function_wrapper { - typename promise_handler<Signature, Allocator>::executor_type - ex(h->get_executor()); - ex.dispatch(ASIO_MOVE_CAST(Function)(f), std::allocator<void>()); -} + explicit promise_function_wrapper(Function& f) + : function_(static_cast<Function&&>(f)) + { + } -template <typename Function, typename Signature, typename Allocator> -inline void asio_handler_invoke(const Function& f, - promise_handler<Signature, Allocator>* h) -{ - typename promise_handler<Signature, Allocator>::executor_type - ex(h->get_executor()); - ex.dispatch(f, std::allocator<void>()); -} + explicit promise_function_wrapper(const Function& f) + : function_(f) + { + } + + void operator()() + { + function_(); + } + + Function function_; +}; // Helper base class for async_result specialisation. template <typename Signature, typename Allocator> @@ -615,7 +478,7 @@ public: return_type get() { - return ASIO_MOVE_CAST(return_type)(future_); + return static_cast<return_type&&>(future_); } private: @@ -628,7 +491,7 @@ class packaged_token { public: packaged_token(Function f, const Allocator& a) - : function_(ASIO_MOVE_CAST(Function)(f)), + : function_(static_cast<Function&&>(f)), allocator_(a) { } @@ -649,71 +512,29 @@ public: typedef void result_type; packaged_handler(packaged_token<Function, Allocator> t) - : function_(ASIO_MOVE_CAST(Function)(t.function_)), + : function_(static_cast<Function&&>(t.function_)), allocator_(t.allocator_) { this->create_promise(allocator_); } - allocator_type get_allocator() const ASIO_NOEXCEPT + allocator_type get_allocator() const noexcept { return allocator_; } -#if defined(ASIO_HAS_VARIADIC_TEMPLATES) - template <typename... Args> - void operator()(ASIO_MOVE_ARG(Args)... args) + void operator()(Args&&... args) { (promise_invoke_and_set)(*this->p_, - function_, ASIO_MOVE_CAST(Args)(args)...); - } - -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - - void operator()() - { - (promise_invoke_and_set)(*this->p_, function_); + function_, static_cast<Args&&>(args)...); } -#define ASIO_PRIVATE_CALL_OP_DEF(n) \ - template <ASIO_VARIADIC_TPARAMS(n)> \ - void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \ - {\ - (promise_invoke_and_set)(*this->p_, \ - function_, ASIO_VARIADIC_MOVE_ARGS(n)); \ - } \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) -#undef ASIO_PRIVATE_CALL_OP_DEF - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) - private: Function function_; Allocator allocator_; }; -template <typename Function, - typename Function1, typename Allocator, typename Result> -inline void asio_handler_invoke(Function& f, - packaged_handler<Function1, Allocator, Result>* h) -{ - typename packaged_handler<Function1, Allocator, Result>::executor_type - ex(h->get_executor()); - ex.dispatch(ASIO_MOVE_CAST(Function)(f), std::allocator<void>()); -} - -template <typename Function, - typename Function1, typename Allocator, typename Result> -inline void asio_handler_invoke(const Function& f, - packaged_handler<Function1, Allocator, Result>* h) -{ - typename packaged_handler<Function1, Allocator, Result>::executor_type - ex(h->get_executor()); - ex.dispatch(f, std::allocator<void>()); -} - // Helper base class for async_result specialisation. template <typename Function, typename Allocator, typename Result> class packaged_async_result @@ -729,7 +550,7 @@ public: return_type get() { - return ASIO_MOVE_CAST(return_type)(future_); + return static_cast<return_type&&>(future_); } private: @@ -739,28 +560,26 @@ private: } // namespace detail template <typename Allocator> template <typename Function> -inline detail::packaged_token<typename decay<Function>::type, Allocator> -use_future_t<Allocator>::operator()(ASIO_MOVE_ARG(Function) f) const +inline detail::packaged_token<decay_t<Function>, Allocator> +use_future_t<Allocator>::operator()(Function&& f) const { - return detail::packaged_token<typename decay<Function>::type, Allocator>( - ASIO_MOVE_CAST(Function)(f), allocator_); + return detail::packaged_token<decay_t<Function>, Allocator>( + static_cast<Function&&>(f), allocator_); } #if !defined(GENERATING_DOCUMENTATION) -#if defined(ASIO_HAS_VARIADIC_TEMPLATES) - template <typename Allocator, typename Result, typename... Args> class async_result<use_future_t<Allocator>, Result(Args...)> : public detail::promise_async_result< - void(typename decay<Args>::type...), Allocator> + void(decay_t<Args>...), Allocator> { public: explicit async_result( - typename detail::promise_async_result<void(typename decay<Args>::type...), + typename detail::promise_async_result<void(decay_t<Args>...), Allocator>::completion_handler_type& h) : detail::promise_async_result< - void(typename decay<Args>::type...), Allocator>(h) + void(decay_t<Args>...), Allocator>(h) { } }; @@ -769,139 +588,115 @@ template <typename Function, typename Allocator, typename Result, typename... Args> class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)> : public detail::packaged_async_result<Function, Allocator, - typename result_of<Function(Args...)>::type> + result_of_t<Function(Args...)>> { public: explicit async_result( typename detail::packaged_async_result<Function, Allocator, - typename result_of<Function(Args...)>::type>::completion_handler_type& h) + result_of_t<Function(Args...)>>::completion_handler_type& h) : detail::packaged_async_result<Function, Allocator, - typename result_of<Function(Args...)>::type>(h) + result_of_t<Function(Args...)>>(h) { } }; -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) +namespace traits { -template <typename Allocator, typename Result> -class async_result<use_future_t<Allocator>, Result()> - : public detail::promise_async_result<void(), Allocator> -{ -public: - explicit async_result( - typename detail::promise_async_result< - void(), Allocator>::completion_handler_type& h) - : detail::promise_async_result<void(), Allocator>(h) - { - } -}; +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) -template <typename Function, typename Allocator, typename Result> -class async_result<detail::packaged_token<Function, Allocator>, Result()> - : public detail::packaged_async_result<Function, Allocator, - typename result_of<Function()>::type> +template <typename T, typename Blocking> +struct equality_comparable< + asio::detail::promise_executor<T, Blocking>> { -public: - explicit async_result( - typename detail::packaged_async_result<Function, Allocator, - typename result_of<Function()>::type>::completion_handler_type& h) - : detail::packaged_async_result<Function, Allocator, - typename result_of<Function()>::type>(h) - { - } + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; }; -#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ - template <typename Allocator, \ - typename Result, ASIO_VARIADIC_TPARAMS(n)> \ - class async_result<use_future_t<Allocator>, \ - Result(ASIO_VARIADIC_TARGS(n))> \ - : public detail::promise_async_result< \ - void(ASIO_VARIADIC_DECAY(n)), Allocator> \ - { \ - public: \ - explicit async_result( \ - typename detail::promise_async_result< \ - void(ASIO_VARIADIC_DECAY(n)), \ - Allocator>::completion_handler_type& h) \ - : detail::promise_async_result< \ - void(ASIO_VARIADIC_DECAY(n)), Allocator>(h) \ - { \ - } \ - }; \ - \ - template <typename Function, typename Allocator, \ - typename Result, ASIO_VARIADIC_TPARAMS(n)> \ - class async_result<detail::packaged_token<Function, Allocator>, \ - Result(ASIO_VARIADIC_TARGS(n))> \ - : public detail::packaged_async_result<Function, Allocator, \ - typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type> \ - { \ - public: \ - explicit async_result( \ - typename detail::packaged_async_result<Function, Allocator, \ - typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type \ - >::completion_handler_type& h) \ - : detail::packaged_async_result<Function, Allocator, \ - typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type>(h) \ - { \ - } \ - }; \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF) -#undef ASIO_PRIVATE_ASYNC_RESULT_DEF - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) - -#if !defined(ASIO_NO_DEPRECATED) - -template <typename Allocator, typename Signature> -struct handler_type<use_future_t<Allocator>, Signature> +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename T, typename Blocking, typename Function> +struct execute_member< + asio::detail::promise_executor<T, Blocking>, Function> { - typedef typename async_result<use_future_t<Allocator>, - Signature>::completion_handler_type type; + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; }; -template <typename Signature, typename Allocator> -class async_result<detail::promise_handler<Signature, Allocator> > - : public detail::promise_async_result<Signature, Allocator> +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename T, typename Blocking, typename Property> +struct query_static_constexpr_member< + asio::detail::promise_executor<T, Blocking>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::blocking_t + >::value + >::type + > { -public: - typedef typename detail::promise_async_result< - Signature, Allocator>::return_type type; + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Blocking result_type; - explicit async_result( - typename detail::promise_async_result< - Signature, Allocator>::completion_handler_type& h) - : detail::promise_async_result<Signature, Allocator>(h) + static constexpr result_type value() noexcept { + return Blocking(); } }; -template <typename Function, typename Allocator, typename Signature> -struct handler_type<detail::packaged_token<Function, Allocator>, Signature> +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename T, typename Blocking> +struct query_member< + asio::detail::promise_executor<T, Blocking>, + execution::context_t + > { - typedef typename async_result<detail::packaged_token<Function, Allocator>, - Signature>::completion_handler_type type; + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::system_context& result_type; }; -template <typename Function, typename Allocator, typename Result> -class async_result<detail::packaged_handler<Function, Allocator, Result> > - : public detail::packaged_async_result<Function, Allocator, Result> +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename T, typename Blocking> +struct require_member< + asio::detail::promise_executor<T, Blocking>, + execution::blocking_t::possibly_t + > { -public: - typedef typename detail::packaged_async_result< - Function, Allocator, Result>::return_type type; + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::detail::promise_executor<T, + execution::blocking_t::possibly_t> result_type; +}; - explicit async_result( - typename detail::packaged_async_result< - Function, Allocator, Result>::completion_handler_type& h) - : detail::packaged_async_result<Function, Allocator, Result>(h) - { - } +template <typename T, typename Blocking> +struct require_member< + asio::detail::promise_executor<T, Blocking>, + execution::blocking_t::never_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::detail::promise_executor<T, + execution::blocking_t::never_t> result_type; }; -#endif // !defined(ASIO_NO_DEPRECATED) +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits #endif // !defined(GENERATING_DOCUMENTATION) diff --git a/3rdparty/asio/include/asio/impl/write.hpp b/3rdparty/asio/include/asio/impl/write.hpp index 8250aa30361..af2bb5544bb 100644 --- a/3rdparty/asio/include/asio/impl/write.hpp +++ b/3rdparty/asio/include/asio/impl/write.hpp @@ -2,7 +2,7 @@ // impl/write.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,19 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" +#include "asio/associator.hpp" #include "asio/buffer.hpp" -#include "asio/completion_condition.hpp" #include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/dependent_type.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_tracking.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" @@ -38,7 +37,7 @@ namespace detail { template <typename SyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition> - std::size_t write_buffer_sequence(SyncWriteStream& s, + std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, const ConstBufferIterator&, CompletionCondition completion_condition, asio::error_code& ec) { @@ -53,7 +52,7 @@ namespace detail else break; } - return tmp.total_consumed();; + return tmp.total_consumed(); } } // namespace detail @@ -61,19 +60,20 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type*) + >) { - return detail::write_buffer_sequence(s, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, ec); + return detail::write(s, buffers, + asio::buffer_sequence_begin(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); } template <typename SyncWriteStream, typename ConstBufferSequence> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type*) + >) { asio::error_code ec; std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); @@ -84,9 +84,9 @@ inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, template <typename SyncWriteStream, typename ConstBufferSequence> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, asio::error_code& ec, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type*) + >) { return write(s, buffers, transfer_all(), ec); } @@ -95,73 +95,89 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type*) + >) { asio::error_code ec; - std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); + std::size_t bytes_transferred = write(s, buffers, + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "write"); return bytes_transferred; } -template <typename SyncWriteStream, typename DynamicBuffer, +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - typename decay<DynamicBuffer>::type b( - ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + decay_t<DynamicBuffer_v1> b( + static_cast<DynamicBuffer_v1&&>(buffers)); - std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); + std::size_t bytes_transferred = write(s, b.data(), + static_cast<CompletionCondition&&>(completion_condition), ec); b.consume(bytes_transferred); return bytes_transferred; } -template <typename SyncWriteStream, typename DynamicBuffer> +template <typename SyncWriteStream, typename DynamicBuffer_v1> inline std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + DynamicBuffer_v1&& buffers, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = write(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), + static_cast<DynamicBuffer_v1&&>(buffers), transfer_all(), ec); asio::detail::throw_error(ec, "write"); return bytes_transferred; } -template <typename SyncWriteStream, typename DynamicBuffer> +template <typename SyncWriteStream, typename DynamicBuffer_v1> inline std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { - return write(s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + return write(s, static_cast<DynamicBuffer_v1&&>(buffers), transfer_all(), ec); } -template <typename SyncWriteStream, typename DynamicBuffer, +template <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) { asio::error_code ec; std::size_t bytes_transferred = write(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, ec); + static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "write"); return bytes_transferred; } @@ -175,7 +191,8 @@ inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, asio::error_code& ec) { - return write(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); + return write(s, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition), ec); } template <typename SyncWriteStream, typename Allocator> @@ -199,11 +216,68 @@ inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - return write(s, basic_streambuf_ref<Allocator>(b), completion_condition); + return write(s, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition)); } #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + std::size_t bytes_transferred = write(s, buffers.data(0, buffers.size()), + static_cast<CompletionCondition&&>(completion_condition), ec); + buffers.consume(bytes_transferred); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBuffer_v2> +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, + static_cast<DynamicBuffer_v2&&>(buffers), + transfer_all(), ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBuffer_v2> +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + return write(s, static_cast<DynamicBuffer_v2&&>(buffers), + transfer_all(), ec); +} + +template <typename SyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, + static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} namespace detail { @@ -211,23 +285,25 @@ namespace detail typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> class write_op - : detail::base_from_completion_cond<CompletionCondition> + : public base_from_cancellation_state<WriteHandler>, + base_from_completion_cond<CompletionCondition> { public: write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), + CompletionCondition& completion_condition, WriteHandler& handler) + : base_from_cancellation_state<WriteHandler>( + handler, enable_partial_cancellation()), + base_from_completion_cond<CompletionCondition>(completion_condition), stream_(stream), buffers_(buffers), start_(0), - handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + handler_(static_cast<WriteHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) write_op(const write_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<WriteHandler>(other), + base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), @@ -236,16 +312,18 @@ namespace detail } write_op(write_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<WriteHandler>( + static_cast<base_from_cancellation_state<WriteHandler>&&>(other)), + base_from_completion_cond<CompletionCondition>( + static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), stream_(other.stream_), - buffers_(other.buffers_), + buffers_(static_cast<buffers_type&&>(other.buffers_)), start_(other.start_), - handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + handler_(static_cast<WriteHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size; @@ -253,25 +331,39 @@ namespace detail { case 1: max_size = this->check_for_completion(ec, buffers_.total_consumed()); - do + for (;;) { - stream_.async_write_some(buffers_.prepare(max_size), - ASIO_MOVE_CAST(write_op)(*this)); + { + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write")); + stream_.async_write_some(buffers_.prepare(max_size), + static_cast<write_op&&>(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; max_size = this->check_for_completion(ec, buffers_.total_consumed()); - } while (max_size > 0); + if (max_size == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = error::operation_aborted; + break; + } + } - handler_(ec, buffers_.total_consumed()); + static_cast<WriteHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), + static_cast<const std::size_t&>(buffers_.total_consumed())); } } //private: + typedef asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_type; + AsyncWriteStream& stream_; - asio::detail::consuming_buffers<const_buffer, - ConstBufferSequence, ConstBufferIterator> buffers_; + buffers_type buffers_; int start_; WriteHandler handler_; }; @@ -279,28 +371,6 @@ namespace detail template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> - inline void* asio_handler_allocate(std::size_t size, - write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, - CompletionCondition, WriteHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncWriteStream, typename ConstBufferSequence, - typename ConstBufferIterator, typename CompletionCondition, - typename WriteHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, - CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncWriteStream, typename ConstBufferSequence, - typename ConstBufferIterator, typename CompletionCondition, - typename WriteHandler> inline bool asio_handler_is_continuation( write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) @@ -310,34 +380,12 @@ namespace detail this_handler->handler_); } - template <typename Function, typename AsyncWriteStream, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler> - inline void asio_handler_invoke(Function& function, - write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, - CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - - template <typename Function, typename AsyncWriteStream, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler> - inline void asio_handler_invoke(const Function& function, - write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, - CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> - inline void start_write_buffer_sequence_op(AsyncWriteStream& stream, + inline void start_write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, const ConstBufferIterator&, - CompletionCondition completion_condition, WriteHandler& handler) + CompletionCondition& completion_condition, WriteHandler& handler) { detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>( @@ -345,120 +393,140 @@ namespace detail asio::error_code(), 0, 1); } + template <typename AsyncWriteStream> + class initiate_async_write + { + public: + typedef typename AsyncWriteStream::executor_type executor_type; + + explicit initiate_async_write(AsyncWriteStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence, + typename CompletionCondition> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_write_op(stream_, buffers, + asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + + private: + AsyncWriteStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncWriteStream, typename ConstBufferSequence, +template <template <typename, typename> class Associator, + typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, - typename WriteHandler, typename Allocator> -struct associated_allocator< + typename WriteHandler, typename DefaultCandidate> +struct associator<Associator, detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>, - Allocator> + DefaultCandidate> + : Associator<WriteHandler, DefaultCandidate> { - typedef typename associated_allocator<WriteHandler, Allocator>::type type; - - static type get( + static typename Associator<WriteHandler, DefaultCandidate>::type get( const detail::write_op<AsyncWriteStream, ConstBufferSequence, - ConstBufferIterator, CompletionCondition, WriteHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + ConstBufferIterator, CompletionCondition, WriteHandler>& h) noexcept { - return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename AsyncWriteStream, typename ConstBufferSequence, - typename ConstBufferIterator, typename CompletionCondition, - typename WriteHandler, typename Executor> -struct associated_executor< - detail::write_op<AsyncWriteStream, ConstBufferSequence, - ConstBufferIterator, CompletionCondition, WriteHandler>, - Executor> -{ - typedef typename associated_executor<WriteHandler, Executor>::type type; - static type get( + static auto get( const detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncWriteStream, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< +template <typename AsyncWriteStream, + typename ConstBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteToken&& token, + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type*) + >) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write<AsyncWriteStream>>(), + token, buffers, + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_write_buffer_sequence_op(s, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write<AsyncWriteStream>(s), + token, buffers, + static_cast<CompletionCondition&&>(completion_condition)); } template <typename AsyncWriteStream, typename ConstBufferSequence, - typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, + const ConstBufferSequence& buffers, WriteToken&& token, + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type*) + >) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write<AsyncWriteStream>>(), + token, buffers, transfer_all())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_write_buffer_sequence_op(s, buffers, - asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write<AsyncWriteStream>(s), + token, buffers, transfer_all()); } +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + namespace detail { - template <typename AsyncWriteStream, typename DynamicBuffer, + template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> - class write_dynbuf_op + class write_dynbuf_v1_op { public: template <typename BufferSequence> - write_dynbuf_op(AsyncWriteStream& stream, - ASIO_MOVE_ARG(BufferSequence) buffers, - CompletionCondition completion_condition, WriteHandler& handler) + write_dynbuf_v1_op(AsyncWriteStream& stream, + BufferSequence&& buffers, + CompletionCondition& completion_condition, WriteHandler& handler) : stream_(stream), - buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + buffers_(static_cast<BufferSequence&&>(buffers)), completion_condition_( - ASIO_MOVE_CAST(CompletionCondition)(completion_condition)), - handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + static_cast<CompletionCondition&&>(completion_condition)), + handler_(static_cast<WriteHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) - write_dynbuf_op(const write_dynbuf_op& other) + write_dynbuf_v1_op(const write_dynbuf_v1_op& other) : stream_(other.stream_), buffers_(other.buffers_), completion_condition_(other.completion_condition_), @@ -466,16 +534,15 @@ namespace detail { } - write_dynbuf_op(write_dynbuf_op&& other) + write_dynbuf_v1_op(write_dynbuf_v1_op&& other) : stream_(other.stream_), - buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)), completion_condition_( - ASIO_MOVE_CAST(CompletionCondition)( + static_cast<CompletionCondition&&>( other.completion_condition_)), - handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + handler_(static_cast<WriteHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) @@ -483,189 +550,387 @@ namespace detail switch (start) { case 1: - async_write(stream_, buffers_.data(), completion_condition_, - ASIO_MOVE_CAST(write_dynbuf_op)(*this)); + async_write(stream_, buffers_.data(), + static_cast<CompletionCondition&&>(completion_condition_), + static_cast<write_dynbuf_v1_op&&>(*this)); return; default: buffers_.consume(bytes_transferred); - handler_(ec, static_cast<const std::size_t&>(bytes_transferred)); + static_cast<WriteHandler&&>(handler_)(ec, + static_cast<const std::size_t&>(bytes_transferred)); } } //private: AsyncWriteStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; CompletionCondition completion_condition_; WriteHandler handler_; }; - template <typename AsyncWriteStream, typename DynamicBuffer, - typename CompletionCondition, typename WriteHandler> - inline void* asio_handler_allocate(std::size_t size, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, - CompletionCondition, WriteHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncWriteStream, typename DynamicBuffer, - typename CompletionCondition, typename WriteHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, - CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncWriteStream, typename DynamicBuffer, + template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { return asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncWriteStream, - typename DynamicBuffer, typename CompletionCondition, - typename WriteHandler> - inline void asio_handler_invoke(Function& function, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, - CompletionCondition, WriteHandler>* this_handler) + template <typename AsyncWriteStream> + class initiate_async_write_dynbuf_v1 { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncWriteStream::executor_type executor_type; - template <typename Function, typename AsyncWriteStream, - typename DynamicBuffer, typename CompletionCondition, - typename WriteHandler> - inline void asio_handler_invoke(const Function& function, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, - CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_write_dynbuf_v1(AsyncWriteStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename WriteHandler, typename DynamicBuffer_v1, + typename CompletionCondition> + void operator()(WriteHandler&& handler, + DynamicBuffer_v1&& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + write_dynbuf_v1_op<AsyncWriteStream, + decay_t<DynamicBuffer_v1>, + CompletionCondition, decay_t<WriteHandler>>( + stream_, static_cast<DynamicBuffer_v1&&>(buffers), + completion_cond2.value, handler2.value)( + asio::error_code(), 0, 1); + } + + private: + AsyncWriteStream& stream_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncWriteStream, typename DynamicBuffer, - typename CompletionCondition, typename WriteHandler, typename Allocator> -struct associated_allocator< - detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>, - Allocator> +template <template <typename, typename> class Associator, + typename AsyncWriteStream, typename DynamicBuffer_v1, + typename CompletionCondition, typename WriteHandler, + typename DefaultCandidate> +struct associator<Associator, + detail::write_dynbuf_v1_op<AsyncWriteStream, + DynamicBuffer_v1, CompletionCondition, WriteHandler>, + DefaultCandidate> + : Associator<WriteHandler, DefaultCandidate> { - typedef typename associated_allocator<WriteHandler, Allocator>::type type; - - static type get( - const detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<WriteHandler, DefaultCandidate>::type get( + const detail::write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, + CompletionCondition, WriteHandler>& h) noexcept { - return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename AsyncWriteStream, typename DynamicBuffer, - typename CompletionCondition, typename WriteHandler, typename Executor> -struct associated_executor< - detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>, - Executor> -{ - typedef typename associated_executor<WriteHandler, Executor>::type type; - static type get( - const detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get( + const detail::write_dynbuf_v1_op<AsyncWriteStream, + DynamicBuffer_v1, CompletionCondition, WriteHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncWriteStream, - typename DynamicBuffer, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) +template <typename AsyncWriteStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, + DynamicBuffer_v1&& buffers, WriteToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + transfer_all())) { - return async_write(s, - ASIO_MOVE_CAST(DynamicBuffer)(buffers), - transfer_all(), ASIO_MOVE_CAST(WriteHandler)(handler)); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), + transfer_all()); } -template <typename AsyncWriteStream, typename DynamicBuffer, - typename CompletionCondition, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type*) +template <typename AsyncWriteStream, + typename DynamicBuffer_v1, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, DynamicBuffer_v1&& buffers, + CompletionCondition completion_condition, WriteToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + >, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + >) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::write_dynbuf_op<AsyncWriteStream, - typename decay<DynamicBuffer>::type, - CompletionCondition, ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, init.completion_handler)( - asio::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition)); } #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) -template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, +template <typename AsyncWriteStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, asio::basic_streambuf<Allocator>& b, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, basic_streambuf_ref<Allocator>(b), transfer_all())) { - return async_write(s, basic_streambuf_ref<Allocator>(b), - ASIO_MOVE_CAST(WriteHandler)(handler)); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), + token, basic_streambuf_ref<Allocator>(b), transfer_all()); } -template <typename AsyncWriteStream, typename Allocator, - typename CompletionCondition, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, +template <typename AsyncWriteStream, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, asio::basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler) + CompletionCondition completion_condition, WriteToken&& token) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition))) { - return async_write(s, basic_streambuf_ref<Allocator>(b), - completion_condition, ASIO_MOVE_CAST(WriteHandler)(handler)); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), + token, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition)); } #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler> + class write_dynbuf_v2_op + { + public: + template <typename BufferSequence> + write_dynbuf_v2_op(AsyncWriteStream& stream, + BufferSequence&& buffers, + CompletionCondition& completion_condition, WriteHandler& handler) + : stream_(stream), + buffers_(static_cast<BufferSequence&&>(buffers)), + completion_condition_( + static_cast<CompletionCondition&&>(completion_condition)), + handler_(static_cast<WriteHandler&&>(handler)) + { + } + + write_dynbuf_v2_op(const write_dynbuf_v2_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + completion_condition_(other.completion_condition_), + handler_(other.handler_) + { + } + + write_dynbuf_v2_op(write_dynbuf_v2_op&& other) + : stream_(other.stream_), + buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)), + completion_condition_( + static_cast<CompletionCondition&&>( + other.completion_condition_)), + handler_(static_cast<WriteHandler&&>(other.handler_)) + { + } + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + async_write(stream_, buffers_.data(0, buffers_.size()), + static_cast<CompletionCondition&&>(completion_condition_), + static_cast<write_dynbuf_v2_op&&>(*this)); + return; default: + buffers_.consume(bytes_transferred); + static_cast<WriteHandler&&>(handler_)(ec, + static_cast<const std::size_t&>(bytes_transferred)); + } + } + + //private: + AsyncWriteStream& stream_; + DynamicBuffer_v2 buffers_; + CompletionCondition completion_condition_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler> + inline bool asio_handler_is_continuation( + write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, + CompletionCondition, WriteHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename AsyncWriteStream> + class initiate_async_write_dynbuf_v2 + { + public: + typedef typename AsyncWriteStream::executor_type executor_type; + + explicit initiate_async_write_dynbuf_v2(AsyncWriteStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const noexcept + { + return stream_.get_executor(); + } + + template <typename WriteHandler, typename DynamicBuffer_v2, + typename CompletionCondition> + void operator()(WriteHandler&& handler, + DynamicBuffer_v2&& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + write_dynbuf_v2_op<AsyncWriteStream, decay_t<DynamicBuffer_v2>, + CompletionCondition, decay_t<WriteHandler>>( + stream_, static_cast<DynamicBuffer_v2&&>(buffers), + completion_cond2.value, handler2.value)( + asio::error_code(), 0, 1); + } + + private: + AsyncWriteStream& stream_; + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <template <typename, typename> class Associator, + typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler, + typename DefaultCandidate> +struct associator<Associator, + detail::write_dynbuf_v2_op<AsyncWriteStream, + DynamicBuffer_v2, CompletionCondition, WriteHandler>, + DefaultCandidate> + : Associator<WriteHandler, DefaultCandidate> +{ + static typename Associator<WriteHandler, DefaultCandidate>::type get( + const detail::write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, + CompletionCondition, WriteHandler>& h) noexcept + { + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); + } + + static auto get( + const detail::write_dynbuf_v2_op<AsyncWriteStream, + DynamicBuffer_v2, CompletionCondition, WriteHandler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) + { + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, + DynamicBuffer_v2 buffers, WriteToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + transfer_all())) +{ + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), + transfer_all()); +} + +template <typename AsyncWriteStream, + typename DynamicBuffer_v2, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, WriteToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))) +{ + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>(s), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition)); +} } // namespace asio diff --git a/3rdparty/asio/include/asio/impl/write_at.hpp b/3rdparty/asio/include/asio/impl/write_at.hpp index 9e06bd28861..b5a67e30051 100644 --- a/3rdparty/asio/include/asio/impl/write_at.hpp +++ b/3rdparty/asio/include/asio/impl/write_at.hpp @@ -2,7 +2,7 @@ // impl/write_at.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,19 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/associated_allocator.hpp" -#include "asio/associated_executor.hpp" +#include "asio/associator.hpp" #include "asio/buffer.hpp" -#include "asio/completion_condition.hpp" #include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/dependent_type.hpp" -#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_tracking.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" @@ -57,7 +56,7 @@ namespace detail else break; } - return tmp.total_consumed();; + return tmp.total_consumed(); } } // namespace detail @@ -68,7 +67,8 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, CompletionCondition completion_condition, asio::error_code& ec) { return detail::write_at_buffer_sequence(d, offset, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, ec); + asio::buffer_sequence_begin(buffers), + static_cast<CompletionCondition&&>(completion_condition), ec); } template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> @@ -97,8 +97,8 @@ inline std::size_t write_at(SyncRandomAccessWriteDevice& d, CompletionCondition completion_condition) { asio::error_code ec; - std::size_t bytes_transferred = write_at( - d, offset, buffers, completion_condition, ec); + std::size_t bytes_transferred = write_at(d, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "write_at"); return bytes_transferred; } @@ -112,8 +112,8 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, asio::error_code& ec) { - std::size_t bytes_transferred = write_at( - d, offset, b.data(), completion_condition, ec); + std::size_t bytes_transferred = write_at(d, offset, b.data(), + static_cast<CompletionCondition&&>(completion_condition), ec); b.consume(bytes_transferred); return bytes_transferred; } @@ -143,8 +143,8 @@ inline std::size_t write_at(SyncRandomAccessWriteDevice& d, CompletionCondition completion_condition) { asio::error_code ec; - std::size_t bytes_transferred = write_at( - d, offset, b, completion_condition, ec); + std::size_t bytes_transferred = write_at(d, offset, b, + static_cast<CompletionCondition&&>(completion_condition), ec); asio::detail::throw_error(ec, "write_at"); return bytes_transferred; } @@ -158,25 +158,27 @@ namespace detail typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> class write_at_op - : detail::base_from_completion_cond<CompletionCondition> + : public base_from_cancellation_state<WriteHandler>, + base_from_completion_cond<CompletionCondition> { public: write_at_op(AsyncRandomAccessWriteDevice& device, uint64_t offset, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), + CompletionCondition& completion_condition, WriteHandler& handler) + : base_from_cancellation_state<WriteHandler>( + handler, enable_partial_cancellation()), + base_from_completion_cond<CompletionCondition>(completion_condition), device_(device), offset_(offset), buffers_(buffers), start_(0), - handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + handler_(static_cast<WriteHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) write_at_op(const write_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<WriteHandler>(other), + base_from_completion_cond<CompletionCondition>(other), device_(other.device_), offset_(other.offset_), buffers_(other.buffers_), @@ -186,17 +188,19 @@ namespace detail } write_at_op(write_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : base_from_cancellation_state<WriteHandler>( + static_cast<base_from_cancellation_state<WriteHandler>&&>(other)), + base_from_completion_cond<CompletionCondition>( + static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), device_(other.device_), offset_(other.offset_), - buffers_(other.buffers_), + buffers_(static_cast<buffers_type&&>(other.buffers_)), start_(other.start_), - handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + handler_(static_cast<WriteHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) - void operator()(const asio::error_code& ec, + void operator()(asio::error_code ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size; @@ -204,27 +208,41 @@ namespace detail { case 1: max_size = this->check_for_completion(ec, buffers_.total_consumed()); - do + for (;;) { - device_.async_write_some_at( - offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), - ASIO_MOVE_CAST(write_at_op)(*this)); + { + ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write_at")); + device_.async_write_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + static_cast<write_at_op&&>(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; max_size = this->check_for_completion(ec, buffers_.total_consumed()); - } while (max_size > 0); + if (max_size == 0) + break; + if (this->cancelled() != cancellation_type::none) + { + ec = asio::error::operation_aborted; + break; + } + } - handler_(ec, buffers_.total_consumed()); + static_cast<WriteHandler&&>(handler_)( + static_cast<const asio::error_code&>(ec), + static_cast<const std::size_t&>(buffers_.total_consumed())); } } //private: + typedef asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_type; + AsyncRandomAccessWriteDevice& device_; uint64_t offset_; - asio::detail::consuming_buffers<const_buffer, - ConstBufferSequence, ConstBufferIterator> buffers_; + buffers_type buffers_; int start_; WriteHandler handler_; }; @@ -232,28 +250,6 @@ namespace detail template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> - inline void* asio_handler_allocate(std::size_t size, - write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) @@ -263,34 +259,12 @@ namespace detail this_handler->handler_); } - template <typename Function, typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler> - inline void asio_handler_invoke(Function& function, - write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - - template <typename Function, typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler> - inline void asio_handler_invoke(const Function& function, - write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } - template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> - inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d, + inline void start_write_at_op(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, - const ConstBufferIterator&, CompletionCondition completion_condition, + const ConstBufferIterator&, CompletionCondition& completion_condition, WriteHandler& handler) { detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, @@ -298,95 +272,116 @@ namespace detail d, offset, buffers, completion_condition, handler)( asio::error_code(), 0, 1); } + + template <typename AsyncRandomAccessWriteDevice> + class initiate_async_write_at + { + public: + typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type; + + explicit initiate_async_write_at(AsyncRandomAccessWriteDevice& device) + : device_(device) + { + } + + executor_type get_executor() const noexcept + { + return device_.get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence, + typename CompletionCondition> + void operator()(WriteHandler&& handler, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition&& completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_write_at_op(device_, offset, buffers, + asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + + private: + AsyncRandomAccessWriteDevice& device_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler, typename Allocator> -struct associated_allocator< +template <template <typename, typename> class Associator, + typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler, typename DefaultCandidate> +struct associator<Associator, detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>, - Allocator> + DefaultCandidate> + : Associator<WriteHandler, DefaultCandidate> { - typedef typename associated_allocator<WriteHandler, Allocator>::type type; - - static type get( + static typename Associator<WriteHandler, DefaultCandidate>::type get( const detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, - CompletionCondition, WriteHandler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + CompletionCondition, WriteHandler>& h) noexcept { - return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename ConstBufferIterator, - typename CompletionCondition, typename WriteHandler, typename Executor> -struct associated_executor< - detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - ConstBufferIterator, CompletionCondition, WriteHandler>, - Executor> -{ - typedef typename associated_executor<WriteHandler, Executor>::type type; - static type get( + static auto get( const detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, +template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler) + CompletionCondition completion_condition, WriteToken&& token) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at< + AsyncRandomAccessWriteDevice>>(), + token, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_write_at_buffer_sequence_op(d, offset, buffers, - asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_at<AsyncRandomAccessWriteDevice>(d), + token, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition)); } template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, - typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, - uint64_t offset, const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, WriteToken&& token) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at< + AsyncRandomAccessWriteDevice>>(), + token, offset, buffers, transfer_all())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::start_write_at_buffer_sequence_op(d, offset, buffers, - asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_at<AsyncRandomAccessWriteDevice>(d), + token, offset, buffers, transfer_all()); } #if !defined(ASIO_NO_EXTENSIONS) @@ -402,11 +397,10 @@ namespace detail asio::basic_streambuf<Allocator>& streambuf, WriteHandler& handler) : streambuf_(streambuf), - handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + handler_(static_cast<WriteHandler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) write_at_streambuf_op(const write_at_streambuf_op& other) : streambuf_(other.streambuf_), handler_(other.handler_) @@ -415,16 +409,15 @@ namespace detail write_at_streambuf_op(write_at_streambuf_op&& other) : streambuf_(other.streambuf_), - handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + handler_(static_cast<WriteHandler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()(const asio::error_code& ec, const std::size_t bytes_transferred) { streambuf_.consume(bytes_transferred); - handler_(ec, bytes_transferred); + static_cast<WriteHandler&&>(handler_)(ec, bytes_transferred); } //private: @@ -433,22 +426,6 @@ namespace detail }; template <typename Allocator, typename WriteHandler> - inline void* asio_handler_allocate(std::size_t size, - write_at_streambuf_op<Allocator, WriteHandler>* this_handler) - { - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template <typename Allocator, typename WriteHandler> - inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_at_streambuf_op<Allocator, WriteHandler>* this_handler) - { - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template <typename Allocator, typename WriteHandler> inline bool asio_handler_is_continuation( write_at_streambuf_op<Allocator, WriteHandler>* this_handler) { @@ -456,110 +433,112 @@ namespace detail this_handler->handler_); } - template <typename Function, typename Allocator, typename WriteHandler> - inline void asio_handler_invoke(Function& function, - write_at_streambuf_op<Allocator, WriteHandler>* this_handler) + template <typename AsyncRandomAccessWriteDevice> + class initiate_async_write_at_streambuf { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + public: + typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type; - template <typename Function, typename Allocator, typename WriteHandler> - inline void asio_handler_invoke(const Function& function, - write_at_streambuf_op<Allocator, WriteHandler>* this_handler) - { - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } + explicit initiate_async_write_at_streambuf( + AsyncRandomAccessWriteDevice& device) + : device_(device) + { + } - template <typename Allocator, typename WriteHandler> - inline write_at_streambuf_op<Allocator, WriteHandler> - make_write_at_streambuf_op( - asio::basic_streambuf<Allocator>& b, WriteHandler handler) - { - return write_at_streambuf_op<Allocator, WriteHandler>(b, handler); - } + executor_type get_executor() const noexcept + { + return device_.get_executor(); + } + + template <typename WriteHandler, + typename Allocator, typename CompletionCondition> + void operator()(WriteHandler&& handler, + uint64_t offset, basic_streambuf<Allocator>* b, + CompletionCondition&& completion_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + async_write_at(device_, offset, b->data(), + static_cast<CompletionCondition&&>(completion_condition), + write_at_streambuf_op<Allocator, decay_t<WriteHandler>>( + *b, handler2.value)); + } + + private: + AsyncRandomAccessWriteDevice& device_; + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename Allocator, typename WriteHandler, typename Allocator1> -struct associated_allocator< - detail::write_at_streambuf_op<Allocator, WriteHandler>, - Allocator1> +template <template <typename, typename> class Associator, + typename Executor, typename WriteHandler, typename DefaultCandidate> +struct associator<Associator, + detail::write_at_streambuf_op<Executor, WriteHandler>, + DefaultCandidate> + : Associator<WriteHandler, DefaultCandidate> { - typedef typename associated_allocator<WriteHandler, Allocator1>::type type; - - static type get( - const detail::write_at_streambuf_op<Allocator, WriteHandler>& h, - const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + static typename Associator<WriteHandler, DefaultCandidate>::type get( + const detail::write_at_streambuf_op<Executor, WriteHandler>& h) noexcept { - return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); } -}; -template <typename Executor, typename WriteHandler, typename Executor1> -struct associated_executor< - detail::write_at_streambuf_op<Executor, WriteHandler>, - Executor1> -{ - typedef typename associated_executor<WriteHandler, Executor1>::type type; - - static type get( + static auto get( const detail::write_at_streambuf_op<Executor, WriteHandler>& h, - const Executor1& ex = Executor1()) ASIO_NOEXCEPT + const DefaultCandidate& c) noexcept + -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex); + return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncRandomAccessWriteDevice, typename Allocator, - typename CompletionCondition, typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, +template <typename AsyncRandomAccessWriteDevice, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, asio::basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler) + CompletionCondition completion_condition, WriteToken&& token) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>>(), + token, offset, &b, + static_cast<CompletionCondition&&>(completion_condition))) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - async_write_at(d, offset, b.data(), completion_condition, - detail::write_at_streambuf_op<Allocator, ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - b, init.completion_handler)); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>(d), + token, offset, &b, + static_cast<CompletionCondition&&>(completion_condition)); } template <typename AsyncRandomAccessWriteDevice, typename Allocator, - typename WriteHandler> -inline ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +inline auto async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, asio::basic_streambuf<Allocator>& b, - ASIO_MOVE_ARG(WriteHandler) handler) + WriteToken&& token) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>>(), + token, offset, &b, transfer_all())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - async_write_at(d, offset, b.data(), transfer_all(), - detail::write_at_streambuf_op<Allocator, ASIO_HANDLER_TYPE( - WriteHandler, void (asio::error_code, std::size_t))>( - b, init.completion_handler)); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>(d), + token, offset, &b, transfer_all()); } #endif // !defined(ASIO_NO_IOSTREAM) diff --git a/3rdparty/asio/include/asio/io_context.hpp b/3rdparty/asio/include/asio/io_context.hpp index 44fe432c76c..5de125685fc 100644 --- a/3rdparty/asio/include/asio/io_context.hpp +++ b/3rdparty/asio/include/asio/io_context.hpp @@ -2,7 +2,7 @@ // io_context.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -20,15 +20,14 @@ #include <stdexcept> #include <typeinfo> #include "asio/async_result.hpp" -#include "asio/detail/noncopyable.hpp" +#include "asio/detail/chrono.hpp" +#include "asio/detail/concurrency_hint.hpp" +#include "asio/detail/cstdint.hpp" #include "asio/detail/wrapped_handler.hpp" #include "asio/error_code.hpp" +#include "asio/execution.hpp" #include "asio/execution_context.hpp" -#if defined(ASIO_HAS_CHRONO) -# include "asio/detail/chrono.hpp" -#endif // defined(ASIO_HAS_CHRONO) - #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) # include "asio/detail/winsock_init.hpp" #elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ @@ -36,17 +35,31 @@ # include "asio/detail/signal_init.hpp" #endif +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else +# include "asio/detail/scheduler.hpp" +#endif + #include "asio/detail/push_options.hpp" namespace asio { namespace detail { #if defined(ASIO_HAS_IOCP) - typedef class win_iocp_io_context io_context_impl; + typedef win_iocp_io_context io_context_impl; class win_iocp_overlapped_ptr; #else - typedef class scheduler io_context_impl; + typedef scheduler io_context_impl; #endif + + struct io_context_bits + { + static constexpr uintptr_t blocking_never = 1; + static constexpr uintptr_t relationship_continuation = 2; + static constexpr uintptr_t outstanding_work_tracked = 4; + static constexpr uintptr_t runtime_bits = 3; + }; } // namespace detail /// Provides core I/O functionality. @@ -64,12 +77,12 @@ namespace detail { * * @par Thread Safety * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Safe, with the specific exceptions of the restart() and - * notify_fork() functions. Calling restart() while there are unfinished run(), - * run_one(), poll() or poll_one() calls results in undefined behaviour. The - * notify_fork() function should not be called while any io_context function, - * or any function on an I/O object that is associated with the io_context, is - * being called in another thread. + * @e Shared @e objects: Safe, with the specific exceptions of the restart() + * and notify_fork() functions. Calling restart() while there are unfinished + * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results + * in undefined behaviour. The notify_fork() function should not be called + * while any io_context function, or any function on an I/O object that is + * associated with the io_context, is being called in another thread. * * @par Concepts: * Dispatcher. @@ -78,25 +91,26 @@ namespace detail { * * Synchronous operations on I/O objects implicitly run the io_context object * for an individual operation. The io_context functions run(), run_one(), - * poll() or poll_one() must be called for the io_context to perform - * asynchronous operations on behalf of a C++ program. Notification that an - * asynchronous operation has completed is delivered by invocation of the - * associated handler. Handlers are invoked only by a thread that is currently - * calling any overload of run(), run_one(), poll() or poll_one() for the - * io_context. + * run_for(), run_until(), poll() or poll_one() must be called for the + * io_context to perform asynchronous operations on behalf of a C++ program. + * Notification that an asynchronous operation has completed is delivered by + * invocation of the associated handler. Handlers are invoked only by a thread + * that is currently calling any overload of run(), run_one(), run_for(), + * run_until(), poll() or poll_one() for the io_context. * * @par Effect of exceptions thrown from handlers * * If an exception is thrown from a handler, the exception is allowed to * propagate through the throwing thread's invocation of run(), run_one(), - * poll() or poll_one(). No other threads that are calling any of these - * functions are affected. It is then the responsibility of the application to - * catch the exception. + * run_for(), run_until(), poll() or poll_one(). No other threads that are + * calling any of these functions are affected. It is then the responsibility + * of the application to catch the exception. * - * After the exception has been caught, the run(), run_one(), poll() or - * poll_one() call may be restarted @em without the need for an intervening - * call to restart(). This allows the thread to rejoin the io_context object's - * thread pool without impacting any other threads in the pool. + * After the exception has been caught, the run(), run_one(), run_for(), + * run_until(), poll() or poll_one() call may be restarted @em without the need + * for an intervening call to restart(). This allows the thread to rejoin the + * io_context object's thread pool without impacting any other threads in the + * pool. * * For example: * @@ -117,13 +131,42 @@ namespace detail { * } * @endcode * + * @par Submitting arbitrary tasks to the io_context + * + * To submit functions to the io_context, use the @ref asio::dispatch, + * @ref asio::post or @ref asio::defer free functions. + * + * For example: + * + * @code void my_task() + * { + * ... + * } + * + * ... + * + * asio::io_context io_context; + * + * // Submit a function to the io_context. + * asio::post(io_context, my_task); + * + * // Submit a lambda object to the io_context. + * asio::post(io_context, + * []() + * { + * ... + * }); + * + * // Run the io_context until it runs out of work. + * io_context.run(); @endcode + * * @par Stopping the io_context from running out of work * * Some applications may need to prevent an io_context object's run() call from * returning when there is no more work to do. For example, the io_context may * be being run in a background thread that is launched prior to the * application's asynchronous operations. The run() call may be kept running by - * creating an object of type + * using the @ref make_work_guard function to create an object of type * asio::executor_work_guard<io_context::executor_type>: * * @code asio::io_context io_context; @@ -154,9 +197,20 @@ private: friend class detail::win_iocp_overlapped_ptr; #endif +#if !defined(ASIO_NO_DEPRECATED) + struct initiate_dispatch; + struct initiate_post; +#endif // !defined(ASIO_NO_DEPRECATED) + public: - class executor_type; - friend class executor_type; + template <typename Allocator, uintptr_t Bits> + class basic_executor_type; + + template <typename Allocator, uintptr_t Bits> + friend class basic_executor_type; + + /// Executor used to submit functions to an io_context. + typedef basic_executor_type<std::allocator<void>, 0> executor_type; #if !defined(ASIO_NO_DEPRECATED) class work; @@ -165,9 +219,11 @@ public: class service; -#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_EXTENSIONS) \ + && !defined(ASIO_NO_TS_EXECUTORS) class strand; #endif // !defined(ASIO_NO_EXTENSIONS) + // && !defined(ASIO_NO_TS_EXECUTORS) /// The type used to count the number of handlers executed by the context. typedef std::size_t count_type; @@ -219,7 +275,7 @@ public: ASIO_DECL ~io_context(); /// Obtains the executor associated with the io_context. - executor_type get_executor() ASIO_NOEXCEPT; + executor_type get_executor() noexcept; /// Run the io_context object's event processing loop. /** @@ -238,9 +294,10 @@ public: * * @return The number of handlers that were executed. * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_context object. + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. * * The poll() function may also be used to dispatch ready handlers, but * without blocking. @@ -268,9 +325,10 @@ public: * * @return The number of handlers that were executed. * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_context object. + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. * * The poll() function may also be used to dispatch ready handlers, but * without blocking. @@ -278,7 +336,6 @@ public: ASIO_DECL count_type run(asio::error_code& ec); #endif // !defined(ASIO_NO_DEPRECATED) -#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) /// Run the io_context object's event processing loop for a specified /// duration. /** @@ -305,7 +362,6 @@ public: */ template <typename Clock, typename Duration> std::size_t run_until(const chrono::time_point<Clock, Duration>& abs_time); -#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) /// Run the io_context object's event processing loop to execute at most one /// handler. @@ -318,11 +374,16 @@ public: * returns @c true). Subsequent calls to run(), run_one(), poll() or * poll_one() will return immediately unless there is a prior call to * restart(). + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. */ ASIO_DECL count_type run_one(); #if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use non-error_code overlaod.) Run the io_context object's + /// (Deprecated: Use non-error_code overload.) Run the io_context object's /// event processing loop to execute at most one handler. /** * The run_one() function blocks until one handler has been dispatched, or @@ -335,11 +396,15 @@ public: * restart(). * * @return The number of handlers that were executed. + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. */ ASIO_DECL count_type run_one(asio::error_code& ec); #endif // !defined(ASIO_NO_DEPRECATED) -#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) /// Run the io_context object's event processing loop for a specified duration /// to execute at most one handler. /** @@ -368,7 +433,6 @@ public: template <typename Clock, typename Duration> std::size_t run_one_until( const chrono::time_point<Clock, Duration>& abs_time); -#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) /// Run the io_context object's event processing loop to execute ready /// handlers. @@ -483,15 +547,17 @@ public: * * @note This function throws an exception only if: * - * @li the handler's @c asio_handler_allocate function; or + * @li the handler's associated allocator; or * * @li the handler's copy constructor * * throws an exception. */ - template <typename CompletionHandler> - ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - dispatch(ASIO_MOVE_ARG(CompletionHandler) handler); + template <typename LegacyCompletionHandler> + auto dispatch(LegacyCompletionHandler&& handler) + -> decltype( + async_initiate<LegacyCompletionHandler, void ()>( + declval<initiate_dispatch>(), handler, this)); /// (Deprecated: Use asio::post().) Request the io_context to invoke /// the given handler and return immediately. @@ -510,15 +576,17 @@ public: * * @note This function throws an exception only if: * - * @li the handler's @c asio_handler_allocate function; or + * @li the handler's associated allocator; or * * @li the handler's copy constructor * * throws an exception. */ - template <typename CompletionHandler> - ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - post(ASIO_MOVE_ARG(CompletionHandler) handler); + template <typename LegacyCompletionHandler> + auto post(LegacyCompletionHandler&& handler) + -> decltype( + async_initiate<LegacyCompletionHandler, void ()>( + declval<initiate_post>(), handler, this)); /// (Deprecated: Use asio::bind_executor().) Create a new handler that /// automatically dispatches the wrapped handler on the io_context. @@ -552,6 +620,9 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) private: + io_context(const io_context&) = delete; + io_context& operator=(const io_context&) = delete; + // Helper function to add the implementation. ASIO_DECL impl_type& add_impl(impl_type* impl); @@ -571,12 +642,351 @@ private: impl_type& impl_; }; -/// Executor used to submit functions to an io_context. -class io_context::executor_type +/// Executor implementation type used to submit functions to an io_context. +template <typename Allocator, uintptr_t Bits> +class io_context::basic_executor_type : + detail::io_context_bits, Allocator { public: + /// Copy constructor. + basic_executor_type(const basic_executor_type& other) noexcept + : Allocator(static_cast<const Allocator&>(other)), + target_(other.target_) + { + if (Bits & outstanding_work_tracked) + if (context_ptr()) + context_ptr()->impl_.work_started(); + } + + /// Move constructor. + basic_executor_type(basic_executor_type&& other) noexcept + : Allocator(static_cast<Allocator&&>(other)), + target_(other.target_) + { + if (Bits & outstanding_work_tracked) + other.target_ = 0; + } + + /// Destructor. + ~basic_executor_type() noexcept + { + if (Bits & outstanding_work_tracked) + if (context_ptr()) + context_ptr()->impl_.work_finished(); + } + + /// Assignment operator. + basic_executor_type& operator=(const basic_executor_type& other) noexcept; + + /// Move assignment operator. + basic_executor_type& operator=(basic_executor_type&& other) noexcept; + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_require_fn::impl; + friend struct asio_prefer_fn::impl; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Obtain an executor with the @c blocking.possibly property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.possibly); @endcode + */ + constexpr basic_executor_type require(execution::blocking_t::possibly_t) const + { + return basic_executor_type(context_ptr(), + *this, bits() & ~blocking_never); + } + + /// Obtain an executor with the @c blocking.never property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.never); @endcode + */ + constexpr basic_executor_type require(execution::blocking_t::never_t) const + { + return basic_executor_type(context_ptr(), + *this, bits() | blocking_never); + } + + /// Obtain an executor with the @c relationship.fork property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.fork); @endcode + */ + constexpr basic_executor_type require(execution::relationship_t::fork_t) const + { + return basic_executor_type(context_ptr(), + *this, bits() & ~relationship_continuation); + } + + /// Obtain an executor with the @c relationship.continuation property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.continuation); @endcode + */ + constexpr basic_executor_type require( + execution::relationship_t::continuation_t) const + { + return basic_executor_type(context_ptr(), + *this, bits() | relationship_continuation); + } + + /// Obtain an executor with the @c outstanding_work.tracked property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::outstanding_work.tracked); @endcode + */ + constexpr basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)> + require(execution::outstanding_work_t::tracked_t) const + { + return basic_executor_type<Allocator, Bits | outstanding_work_tracked>( + context_ptr(), *this, bits()); + } + + /// Obtain an executor with the @c outstanding_work.untracked property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::outstanding_work.untracked); @endcode + */ + constexpr basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)> + require(execution::outstanding_work_t::untracked_t) const + { + return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>( + context_ptr(), *this, bits()); + } + + /// Obtain an executor with the specified @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::allocator(my_allocator)); @endcode + */ + template <typename OtherAllocator> + constexpr basic_executor_type<OtherAllocator, Bits> + require(execution::allocator_t<OtherAllocator> a) const + { + return basic_executor_type<OtherAllocator, Bits>( + context_ptr(), a.value(), bits()); + } + + /// Obtain an executor with the default @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_io_context.get_executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::allocator); @endcode + */ + constexpr basic_executor_type<std::allocator<void>, Bits> + require(execution::allocator_t<void>) const + { + return basic_executor_type<std::allocator<void>, Bits>( + context_ptr(), std::allocator<void>(), bits()); + } + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_query_fn::impl; + friend struct asio::execution::detail::mapping_t<0>; + friend struct asio::execution::detail::outstanding_work_t<0>; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Query the current value of the @c mapping property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::mapping) + * == asio::execution::mapping.thread) + * ... @endcode + */ + static constexpr execution::mapping_t query(execution::mapping_t) noexcept + { + return execution::mapping.thread; + } + + /// Query the current value of the @c context property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * asio::io_context& ctx = asio::query( + * ex, asio::execution::context); @endcode + */ + io_context& query(execution::context_t) const noexcept + { + return *context_ptr(); + } + + /// Query the current value of the @c blocking property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::blocking) + * == asio::execution::blocking.always) + * ... @endcode + */ + constexpr execution::blocking_t query(execution::blocking_t) const noexcept + { + return (bits() & blocking_never) + ? execution::blocking_t(execution::blocking.never) + : execution::blocking_t(execution::blocking.possibly); + } + + /// Query the current value of the @c relationship property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::relationship) + * == asio::execution::relationship.continuation) + * ... @endcode + */ + constexpr execution::relationship_t query( + execution::relationship_t) const noexcept + { + return (bits() & relationship_continuation) + ? execution::relationship_t(execution::relationship.continuation) + : execution::relationship_t(execution::relationship.fork); + } + + /// Query the current value of the @c outstanding_work property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * if (asio::query(ex, asio::execution::outstanding_work) + * == asio::execution::outstanding_work.tracked) + * ... @endcode + */ + static constexpr execution::outstanding_work_t query( + execution::outstanding_work_t) noexcept + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + template <typename OtherAllocator> + constexpr Allocator query( + execution::allocator_t<OtherAllocator>) const noexcept + { + return static_cast<const Allocator&>(*this); + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_io_context.get_executor(); + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + constexpr Allocator query(execution::allocator_t<void>) const noexcept + { + return static_cast<const Allocator&>(*this); + } + +public: + /// Determine whether the io_context is running in the current thread. + /** + * @return @c true if the current thread is running the io_context. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const noexcept; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator==(const basic_executor_type& a, + const basic_executor_type& b) noexcept + { + return a.target_ == b.target_ + && static_cast<const Allocator&>(a) == static_cast<const Allocator&>(b); + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator!=(const basic_executor_type& a, + const basic_executor_type& b) noexcept + { + return a.target_ != b.target_ + || static_cast<const Allocator&>(a) != static_cast<const Allocator&>(b); + } + + /// Execution function. + template <typename Function> + void execute(Function&& f) const; + +#if !defined(ASIO_NO_TS_EXECUTORS) +public: /// Obtain the underlying execution context. - io_context& context() const ASIO_NOEXCEPT; + io_context& context() const noexcept; /// Inform the io_context that it has some outstanding work to do. /** @@ -584,7 +994,7 @@ public: * This ensures that the io_context's run() and run_one() functions do not * exit while the work is underway. */ - void on_work_started() const ASIO_NOEXCEPT; + void on_work_started() const noexcept; /// Inform the io_context that some work is no longer outstanding. /** @@ -592,7 +1002,7 @@ public: * finished. Once the count of unfinished work reaches zero, the io_context * is stopped and the run() and run_one() functions may exit. */ - void on_work_finished() const ASIO_NOEXCEPT; + void on_work_finished() const noexcept; /// Request the io_context to invoke the given function object. /** @@ -608,8 +1018,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void dispatch(Function&& f, const OtherAllocator& a) const; /// Request the io_context to invoke the given function object. /** @@ -624,8 +1034,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void post(Function&& f, const OtherAllocator& a) const; /// Request the io_context to invoke the given function object. /** @@ -644,44 +1054,46 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void defer(Function&& f, const OtherAllocator& a) const; +#endif // !defined(ASIO_NO_TS_EXECUTORS) - /// Determine whether the io_context is running in the current thread. - /** - * @return @c true if the current thread is running the io_context. Otherwise - * returns @c false. - */ - bool running_in_this_thread() const ASIO_NOEXCEPT; +private: + friend class io_context; + template <typename, uintptr_t> friend class basic_executor_type; - /// Compare two executors for equality. - /** - * Two executors are equal if they refer to the same underlying io_context. - */ - friend bool operator==(const executor_type& a, - const executor_type& b) ASIO_NOEXCEPT + // Constructor used by io_context::get_executor(). + explicit basic_executor_type(io_context& i) noexcept + : Allocator(), + target_(reinterpret_cast<uintptr_t>(&i)) { - return &a.io_context_ == &b.io_context_; + if (Bits & outstanding_work_tracked) + context_ptr()->impl_.work_started(); } - /// Compare two executors for inequality. - /** - * Two executors are equal if they refer to the same underlying io_context. - */ - friend bool operator!=(const executor_type& a, - const executor_type& b) ASIO_NOEXCEPT + // Constructor used by require(). + basic_executor_type(io_context* i, + const Allocator& a, uintptr_t bits) noexcept + : Allocator(a), + target_(reinterpret_cast<uintptr_t>(i) | bits) { - return &a.io_context_ != &b.io_context_; + if (Bits & outstanding_work_tracked) + if (context_ptr()) + context_ptr()->impl_.work_started(); } -private: - friend class io_context; + io_context* context_ptr() const noexcept + { + return reinterpret_cast<io_context*>(target_ & ~runtime_bits); + } - // Constructor. - explicit executor_type(io_context& i) : io_context_(i) {} + uintptr_t bits() const noexcept + { + return target_ & runtime_bits; + } - // The underlying io_context. - io_context& io_context_; + // The underlying io_context and runtime bits. + uintptr_t target_; }; #if !defined(ASIO_NO_DEPRECATED) @@ -726,10 +1138,6 @@ public: /// Get the io_context associated with the work. asio::io_context& get_io_context(); - /// (Deprecated: Use get_io_context().) Get the io_context associated with the - /// work. - asio::io_context& get_io_service(); - private: // Prevent assignment. void operator=(const work& other); @@ -747,11 +1155,6 @@ public: /// Get the io_context object that owns the service. asio::io_context& get_io_context(); -#if !defined(ASIO_NO_DEPRECATED) - /// Get the io_context object that owns the service. - asio::io_context& get_io_service(); -#endif // !defined(ASIO_NO_DEPRECATED) - private: /// Destroy all user-defined handler objects owned by the service. ASIO_DECL virtual void shutdown(); @@ -814,6 +1217,274 @@ template <typename Type> asio::detail::service_id<Type> service_base<Type>::id; } // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename Allocator, uintptr_t Bits> +struct equality_comparable< + asio::io_context::basic_executor_type<Allocator, Bits> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename Allocator, uintptr_t Bits, typename Function> +struct execute_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Function + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Allocator, uintptr_t Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::blocking_t::possibly_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::blocking_t::never_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::relationship_t::fork_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::relationship_t::continuation_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::outstanding_work_t::tracked_t + > : asio::detail::io_context_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + Allocator, Bits | outstanding_work_tracked> result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::outstanding_work_t::untracked_t + > : asio::detail::io_context_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + Allocator, Bits & ~outstanding_work_tracked> result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<void> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + std::allocator<void>, Bits> result_type; +}; + +template <uintptr_t Bits, + typename Allocator, typename OtherAllocator> +struct require_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<OtherAllocator> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::io_context::basic_executor_type< + OtherAllocator, Bits> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename Allocator, uintptr_t Bits, typename Property> +struct query_static_constexpr_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::outstanding_work_t + >::value + >::type + > : asio::detail::io_context_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::outstanding_work_t result_type; + + static constexpr result_type value() noexcept + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } +}; + +template <typename Allocator, uintptr_t Bits, typename Property> +struct query_static_constexpr_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::mapping_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::mapping_t::thread_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Allocator, uintptr_t Bits, typename Property> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::blocking_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::blocking_t result_type; +}; + +template <typename Allocator, uintptr_t Bits, typename Property> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::relationship_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::relationship_t result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::context_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::io_context& result_type; +}; + +template <typename Allocator, uintptr_t Bits> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<void> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Allocator result_type; +}; + +template <typename Allocator, uintptr_t Bits, typename OtherAllocator> +struct query_member< + asio::io_context::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<OtherAllocator> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Allocator result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits + +namespace execution { + +template <> +struct is_executor<io_context> : false_type +{ +}; + +} // namespace execution + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/io_context_strand.hpp b/3rdparty/asio/include/asio/io_context_strand.hpp index 53a6c4690c2..288ac238feb 100644 --- a/3rdparty/asio/include/asio/io_context_strand.hpp +++ b/3rdparty/asio/include/asio/io_context_strand.hpp @@ -2,7 +2,7 @@ // io_context_strand.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,7 +17,8 @@ #include "asio/detail/config.hpp" -#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_EXTENSIONS) \ + && !defined(ASIO_NO_TS_EXECUTORS) #include "asio/async_result.hpp" #include "asio/detail/handler_type_requirements.hpp" @@ -63,8 +64,7 @@ namespace asio { * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are * performed outside the strand * - * then @c asio_handler_invoke(a1, &a1) happens-before - * @c asio_handler_invoke(b1, &b1). + * then @c a() happens-before @c b() * * Note that in the following case: * @code async_op_1(..., s.wrap(a)); @@ -87,6 +87,12 @@ namespace asio { */ class io_context::strand { +private: +#if !defined(ASIO_NO_DEPRECATED) + struct initiate_dispatch; + struct initiate_post; +#endif // !defined(ASIO_NO_DEPRECATED) + public: /// Constructor. /** @@ -102,49 +108,30 @@ public: service_.construct(impl_); } - /// Destructor. + /// Copy constructor. /** - * Destroys a strand. - * - * Handlers posted through the strand that have not yet been invoked will - * still be dispatched in a way that meets the guarantee of non-concurrency. - */ - ~strand() - { - } - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use context().) Get the io_context associated with the - /// strand. - /** - * This function may be used to obtain the io_context object that the strand - * uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the strand will use to - * dispatch handlers. Ownership is not transferred to the caller. + * Creates a copy such that both strand objects share the same underlying + * state. */ - asio::io_context& get_io_context() + strand(const strand& other) noexcept + : service_(other.service_), + impl_(other.impl_) { - return service_.get_io_context(); } - /// (Deprecated: Use context().) Get the io_context associated with the - /// strand. + /// Destructor. /** - * This function may be used to obtain the io_context object that the strand - * uses to dispatch handlers for asynchronous operations. + * Destroys a strand. * - * @return A reference to the io_context object that the strand will use to - * dispatch handlers. Ownership is not transferred to the caller. + * Handlers posted through the strand that have not yet been invoked will + * still be dispatched in a way that meets the guarantee of non-concurrency. */ - asio::io_context& get_io_service() + ~strand() { - return service_.get_io_context(); } -#endif // !defined(ASIO_NO_DEPRECATED) /// Obtain the underlying execution context. - asio::io_context& context() ASIO_NOEXCEPT + asio::io_context& context() const noexcept { return service_.get_io_context(); } @@ -153,7 +140,7 @@ public: /** * The strand delegates this call to its underlying io_context. */ - void on_work_started() ASIO_NOEXCEPT + void on_work_started() const noexcept { context().get_executor().on_work_started(); } @@ -162,7 +149,7 @@ public: /** * The strand delegates this call to its underlying io_context. */ - void on_work_finished() ASIO_NOEXCEPT + void on_work_finished() const noexcept { context().get_executor().on_work_finished(); } @@ -183,9 +170,9 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) + void dispatch(Function&& f, const Allocator& a) const { - typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f)); + decay_t<Function> tmp(static_cast<Function&&>(f)); service_.dispatch(impl_, tmp); (void)a; } @@ -211,19 +198,14 @@ public: * handler object as required. The function signature of the handler must be: * @code void handler(); @endcode */ - template <typename CompletionHandler> - ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - dispatch(ASIO_MOVE_ARG(CompletionHandler) handler) + template <typename LegacyCompletionHandler> + auto dispatch(LegacyCompletionHandler&& handler) + -> decltype( + async_initiate<LegacyCompletionHandler, void ()>( + declval<initiate_dispatch>(), handler, this)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; - - async_completion<CompletionHandler, void ()> init(handler); - - service_.dispatch(impl_, init.completion_handler); - - return init.result.get(); + return async_initiate<LegacyCompletionHandler, void ()>( + initiate_dispatch(), handler, this); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -241,9 +223,9 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) + void post(Function&& f, const Allocator& a) const { - typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f)); + decay_t<Function> tmp(static_cast<Function&&>(f)); service_.post(impl_, tmp); (void)a; } @@ -265,19 +247,14 @@ public: * handler object as required. The function signature of the handler must be: * @code void handler(); @endcode */ - template <typename CompletionHandler> - ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - post(ASIO_MOVE_ARG(CompletionHandler) handler) + template <typename LegacyCompletionHandler> + auto post(LegacyCompletionHandler&& handler) + -> decltype( + async_initiate<LegacyCompletionHandler, void ()>( + declval<initiate_post>(), handler, this)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; - - async_completion<CompletionHandler, void ()> init(handler); - - service_.post(impl_, init.completion_handler); - - return init.result.get(); + return async_initiate<LegacyCompletionHandler, void ()>( + initiate_post(), handler, this); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -295,9 +272,9 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) + void defer(Function&& f, const Allocator& a) const { - typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f)); + decay_t<Function> tmp(static_cast<Function&&>(f)); service_.post(impl_, tmp); (void)a; } @@ -343,7 +320,7 @@ public: * submitted to the strand using post(), dispatch() or wrap(). Otherwise * returns @c false. */ - bool running_in_this_thread() const ASIO_NOEXCEPT + bool running_in_this_thread() const noexcept { return service_.running_in_this_thread(impl_); } @@ -353,7 +330,7 @@ public: * Two strands are equal if they refer to the same ordered, non-concurrent * state. */ - friend bool operator==(const strand& a, const strand& b) ASIO_NOEXCEPT + friend bool operator==(const strand& a, const strand& b) noexcept { return a.impl_ == b.impl_; } @@ -363,14 +340,50 @@ public: * Two strands are equal if they refer to the same ordered, non-concurrent * state. */ - friend bool operator!=(const strand& a, const strand& b) ASIO_NOEXCEPT + friend bool operator!=(const strand& a, const strand& b) noexcept { return a.impl_ != b.impl_; } private: +#if !defined(ASIO_NO_DEPRECATED) + struct initiate_dispatch + { + template <typename LegacyCompletionHandler> + void operator()(LegacyCompletionHandler&& handler, + strand* self) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for a + // LegacyCompletionHandler. + ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); + self->service_.dispatch(self->impl_, handler2.value); + } + }; + + struct initiate_post + { + template <typename LegacyCompletionHandler> + void operator()(LegacyCompletionHandler&& handler, + strand* self) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for a + // LegacyCompletionHandler. + ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); + self->service_.post(self->impl_, handler2.value); + } + }; +#endif // !defined(ASIO_NO_DEPRECATED) + asio::detail::strand_service& service_; - asio::detail::strand_service::implementation_type impl_; + mutable asio::detail::strand_service::implementation_type impl_; }; } // namespace asio @@ -378,5 +391,6 @@ private: #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_NO_EXTENSIONS) + // && !defined(ASIO_NO_TS_EXECUTORS) #endif // ASIO_IO_CONTEXT_STRAND_HPP diff --git a/3rdparty/asio/include/asio/io_service.hpp b/3rdparty/asio/include/asio/io_service.hpp index 73772a0fbcf..748d8a6a323 100644 --- a/3rdparty/asio/include/asio/io_service.hpp +++ b/3rdparty/asio/include/asio/io_service.hpp @@ -2,7 +2,7 @@ // io_service.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/io_service_strand.hpp b/3rdparty/asio/include/asio/io_service_strand.hpp index 49f6f3b244d..65bb8db2dd3 100644 --- a/3rdparty/asio/include/asio/io_service_strand.hpp +++ b/3rdparty/asio/include/asio/io_service_strand.hpp @@ -2,7 +2,7 @@ // io_service_strand.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/address.hpp b/3rdparty/asio/include/asio/ip/address.hpp index 351a815cfcd..337abe7fd69 100644 --- a/3rdparty/asio/include/asio/ip/address.hpp +++ b/3rdparty/asio/include/asio/ip/address.hpp @@ -2,7 +2,7 @@ // ip/address.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,6 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include <functional> #include <string> #include "asio/detail/throw_exception.hpp" #include "asio/detail/string_view.hpp" @@ -47,46 +48,44 @@ class address { public: /// Default constructor. - ASIO_DECL address(); + ASIO_DECL address() noexcept; /// Construct an address from an IPv4 address. - ASIO_DECL address(const asio::ip::address_v4& ipv4_address); + ASIO_DECL address( + const asio::ip::address_v4& ipv4_address) noexcept; /// Construct an address from an IPv6 address. - ASIO_DECL address(const asio::ip::address_v6& ipv6_address); + ASIO_DECL address( + const asio::ip::address_v6& ipv6_address) noexcept; /// Copy constructor. - ASIO_DECL address(const address& other); + ASIO_DECL address(const address& other) noexcept; -#if defined(ASIO_HAS_MOVE) /// Move constructor. - ASIO_DECL address(address&& other); -#endif // defined(ASIO_HAS_MOVE) + ASIO_DECL address(address&& other) noexcept; /// Assign from another address. - ASIO_DECL address& operator=(const address& other); + ASIO_DECL address& operator=(const address& other) noexcept; -#if defined(ASIO_HAS_MOVE) /// Move-assign from another address. - ASIO_DECL address& operator=(address&& other); -#endif // defined(ASIO_HAS_MOVE) + ASIO_DECL address& operator=(address&& other) noexcept; /// Assign from an IPv4 address. ASIO_DECL address& operator=( - const asio::ip::address_v4& ipv4_address); + const asio::ip::address_v4& ipv4_address) noexcept; /// Assign from an IPv6 address. ASIO_DECL address& operator=( - const asio::ip::address_v6& ipv6_address); + const asio::ip::address_v6& ipv6_address) noexcept; /// Get whether the address is an IP version 4 address. - bool is_v4() const + bool is_v4() const noexcept { return type_ == ipv4; } /// Get whether the address is an IP version 6 address. - bool is_v6() const + bool is_v6() const noexcept { return type_ == ipv6; } @@ -127,40 +126,46 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. - ASIO_DECL bool is_loopback() const; + ASIO_DECL bool is_loopback() const noexcept; /// Determine whether the address is unspecified. - ASIO_DECL bool is_unspecified() const; + ASIO_DECL bool is_unspecified() const noexcept; /// Determine whether the address is a multicast address. - ASIO_DECL bool is_multicast() const; + ASIO_DECL bool is_multicast() const noexcept; /// Compare two addresses for equality. - ASIO_DECL friend bool operator==(const address& a1, const address& a2); + ASIO_DECL friend bool operator==(const address& a1, + const address& a2) noexcept; /// Compare two addresses for inequality. - friend bool operator!=(const address& a1, const address& a2) + friend bool operator!=(const address& a1, + const address& a2) noexcept { return !(a1 == a2); } /// Compare addresses for ordering. - ASIO_DECL friend bool operator<(const address& a1, const address& a2); + ASIO_DECL friend bool operator<(const address& a1, + const address& a2) noexcept; /// Compare addresses for ordering. - friend bool operator>(const address& a1, const address& a2) + friend bool operator>(const address& a1, + const address& a2) noexcept { return a2 < a1; } /// Compare addresses for ordering. - friend bool operator<=(const address& a1, const address& a2) + friend bool operator<=(const address& a1, + const address& a2) noexcept { return !(a2 < a1); } /// Compare addresses for ordering. - friend bool operator>=(const address& a1, const address& a2) + friend bool operator>=(const address& a1, + const address& a2) noexcept { return !(a1 < a2); } @@ -188,8 +193,8 @@ ASIO_DECL address make_address(const char* str); /** * @relates address */ -ASIO_DECL address make_address( - const char* str, asio::error_code& ec); +ASIO_DECL address make_address(const char* str, + asio::error_code& ec) noexcept; /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. @@ -203,10 +208,10 @@ ASIO_DECL address make_address(const std::string& str); /** * @relates address */ -ASIO_DECL address make_address( - const std::string& str, asio::error_code& ec); +ASIO_DECL address make_address(const std::string& str, + asio::error_code& ec) noexcept; -#if defined(ASIO_HAS_STD_STRING_VIEW) \ +#if defined(ASIO_HAS_STRING_VIEW) \ || defined(GENERATING_DOCUMENTATION) /// Create an address from an IPv4 address string in dotted decimal form, @@ -221,10 +226,10 @@ ASIO_DECL address make_address(string_view str); /** * @relates address */ -ASIO_DECL address make_address( - string_view str, asio::error_code& ec); +ASIO_DECL address make_address(string_view str, + asio::error_code& ec) noexcept; -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) // || defined(GENERATING_DOCUMENTATION) #if !defined(ASIO_NO_IOSTREAM) @@ -250,6 +255,22 @@ std::basic_ostream<Elem, Traits>& operator<<( } // namespace ip } // namespace asio +namespace std { + +template <> +struct hash<asio::ip::address> +{ + std::size_t operator()(const asio::ip::address& addr) + const noexcept + { + return addr.is_v4() + ? std::hash<asio::ip::address_v4>()(addr.to_v4()) + : std::hash<asio::ip::address_v6>()(addr.to_v6()); + } +}; + +} // namespace std + #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/address.hpp" diff --git a/3rdparty/asio/include/asio/ip/address_v4.hpp b/3rdparty/asio/include/asio/ip/address_v4.hpp index 6e16313d6e9..ccef6c80cda 100644 --- a/3rdparty/asio/include/asio/ip/address_v4.hpp +++ b/3rdparty/asio/include/asio/ip/address_v4.hpp @@ -2,7 +2,7 @@ // ip/address_v4.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,6 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include <functional> #include <string> #include "asio/detail/array.hpp" #include "asio/detail/cstdint.hpp" @@ -60,55 +61,68 @@ public: #endif /// Default constructor. - address_v4() + /** + * Initialises the @c address_v4 object such that: + * @li <tt>to_bytes()</tt> yields <tt>{0, 0, 0, 0}</tt>; and + * @li <tt>to_uint() == 0</tt>. + */ + address_v4() noexcept { addr_.s_addr = 0; } /// Construct an address from raw bytes. + /** + * Initialises the @c address_v4 object such that <tt>to_bytes() == + * bytes</tt>. + * + * @throws out_of_range Thrown if any element in @c bytes is not in the range + * <tt>0 - 0xFF</tt>. Note that no range checking is required for platforms + * where <tt>std::numeric_limits<unsigned char>::max()</tt> is <tt>0xFF</tt>. + */ ASIO_DECL explicit address_v4(const bytes_type& bytes); /// Construct an address from an unsigned integer in host byte order. + /** + * Initialises the @c address_v4 object such that <tt>to_uint() == addr</tt>. + */ ASIO_DECL explicit address_v4(uint_type addr); /// Copy constructor. - address_v4(const address_v4& other) + address_v4(const address_v4& other) noexcept : addr_(other.addr_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. - address_v4(address_v4&& other) + address_v4(address_v4&& other) noexcept : addr_(other.addr_) { } -#endif // defined(ASIO_HAS_MOVE) /// Assign from another address. - address_v4& operator=(const address_v4& other) + address_v4& operator=(const address_v4& other) noexcept { addr_ = other.addr_; return *this; } -#if defined(ASIO_HAS_MOVE) /// Move-assign from another address. - address_v4& operator=(address_v4&& other) + address_v4& operator=(address_v4&& other) noexcept { addr_ = other.addr_; return *this; } -#endif // defined(ASIO_HAS_MOVE) /// Get the address in bytes, in network byte order. - ASIO_DECL bytes_type to_bytes() const; + ASIO_DECL bytes_type to_bytes() const noexcept; - /// Get the address as an unsigned integer in host byte order - ASIO_DECL uint_type to_uint() const; + /// Get the address as an unsigned integer in host byte order. + ASIO_DECL uint_type to_uint() const noexcept; #if !defined(ASIO_NO_DEPRECATED) - /// Get the address as an unsigned long in host byte order + /// (Deprecated: Use to_uint().) Get the address as an unsigned long in host + /// byte order. ASIO_DECL unsigned long to_ulong() const; #endif // !defined(ASIO_NO_DEPRECATED) @@ -140,10 +154,23 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. - ASIO_DECL bool is_loopback() const; + /** + * This function tests whether the address is in the address block + * <tt>127.0.0.0/8</tt>, which corresponds to the address range + * <tt>127.0.0.0 - 127.255.255.255</tt>. + * + * @returns <tt>(to_uint() & 0xFF000000) == 0x7F000000</tt>. + */ + ASIO_DECL bool is_loopback() const noexcept; /// Determine whether the address is unspecified. - ASIO_DECL bool is_unspecified() const; + /** + * This function tests whether the address is the unspecified address + * <tt>0.0.0.0</tt>. + * + * @returns <tt>to_uint() == 0</tt>. + */ + ASIO_DECL bool is_unspecified() const noexcept; #if !defined(ASIO_NO_DEPRECATED) /// (Deprecated: Use network_v4 class.) Determine whether the address is a @@ -160,58 +187,109 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) /// Determine whether the address is a multicast address. - ASIO_DECL bool is_multicast() const; + /** + * This function tests whether the address is in the multicast address block + * <tt>224.0.0.0/4</tt>, which corresponds to the address range + * <tt>224.0.0.0 - 239.255.255.255</tt>. + * + * @returns <tt>(to_uint() & 0xF0000000) == 0xE0000000</tt>. + */ + ASIO_DECL bool is_multicast() const noexcept; /// Compare two addresses for equality. - friend bool operator==(const address_v4& a1, const address_v4& a2) + friend bool operator==(const address_v4& a1, + const address_v4& a2) noexcept { return a1.addr_.s_addr == a2.addr_.s_addr; } /// Compare two addresses for inequality. - friend bool operator!=(const address_v4& a1, const address_v4& a2) + friend bool operator!=(const address_v4& a1, + const address_v4& a2) noexcept { return a1.addr_.s_addr != a2.addr_.s_addr; } /// Compare addresses for ordering. - friend bool operator<(const address_v4& a1, const address_v4& a2) + /** + * Compares two addresses in host byte order. + * + * @returns <tt>a1.to_uint() < a2.to_uint()</tt>. + */ + friend bool operator<(const address_v4& a1, + const address_v4& a2) noexcept { return a1.to_uint() < a2.to_uint(); } /// Compare addresses for ordering. - friend bool operator>(const address_v4& a1, const address_v4& a2) + /** + * Compares two addresses in host byte order. + * + * @returns <tt>a1.to_uint() > a2.to_uint()</tt>. + */ + friend bool operator>(const address_v4& a1, + const address_v4& a2) noexcept { return a1.to_uint() > a2.to_uint(); } /// Compare addresses for ordering. - friend bool operator<=(const address_v4& a1, const address_v4& a2) + /** + * Compares two addresses in host byte order. + * + * @returns <tt>a1.to_uint() <= a2.to_uint()</tt>. + */ + friend bool operator<=(const address_v4& a1, + const address_v4& a2) noexcept { return a1.to_uint() <= a2.to_uint(); } /// Compare addresses for ordering. - friend bool operator>=(const address_v4& a1, const address_v4& a2) + /** + * Compares two addresses in host byte order. + * + * @returns <tt>a1.to_uint() >= a2.to_uint()</tt>. + */ + friend bool operator>=(const address_v4& a1, + const address_v4& a2) noexcept { return a1.to_uint() >= a2.to_uint(); } /// Obtain an address object that represents any address. - static address_v4 any() + /** + * This functions returns an address that represents the "any" address + * <tt>0.0.0.0</tt>. + * + * @returns A default-constructed @c address_v4 object. + */ + static address_v4 any() noexcept { return address_v4(); } /// Obtain an address object that represents the loopback address. - static address_v4 loopback() + /** + * This function returns an address that represents the well-known loopback + * address <tt>127.0.0.1</tt>. + * + * @returns <tt>address_v4(0x7F000001)</tt>. + */ + static address_v4 loopback() noexcept { return address_v4(0x7F000001); } /// Obtain an address object that represents the broadcast address. - static address_v4 broadcast() + /** + * This function returns an address that represents the broadcast address + * <tt>255.255.255.255</tt>. + * + * @returns <tt>address_v4(0xFFFFFFFF)</tt>. + */ + static address_v4 broadcast() noexcept { return address_v4(0xFFFFFFFF); } @@ -261,8 +339,8 @@ ASIO_DECL address_v4 make_address_v4(const char* str); /** * @relates address_v4 */ -ASIO_DECL address_v4 make_address_v4( - const char* str, asio::error_code& ec); +ASIO_DECL address_v4 make_address_v4(const char* str, + asio::error_code& ec) noexcept; /// Create an IPv4 address from an IP address string in dotted decimal form. /** @@ -274,10 +352,10 @@ ASIO_DECL address_v4 make_address_v4(const std::string& str); /** * @relates address_v4 */ -ASIO_DECL address_v4 make_address_v4( - const std::string& str, asio::error_code& ec); +ASIO_DECL address_v4 make_address_v4(const std::string& str, + asio::error_code& ec) noexcept; -#if defined(ASIO_HAS_STD_STRING_VIEW) \ +#if defined(ASIO_HAS_STRING_VIEW) \ || defined(GENERATING_DOCUMENTATION) /// Create an IPv4 address from an IP address string in dotted decimal form. @@ -290,10 +368,10 @@ ASIO_DECL address_v4 make_address_v4(string_view str); /** * @relates address_v4 */ -ASIO_DECL address_v4 make_address_v4( - string_view str, asio::error_code& ec); +ASIO_DECL address_v4 make_address_v4(string_view str, + asio::error_code& ec) noexcept; -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) // || defined(GENERATING_DOCUMENTATION) #if !defined(ASIO_NO_IOSTREAM) @@ -319,6 +397,20 @@ std::basic_ostream<Elem, Traits>& operator<<( } // namespace ip } // namespace asio +namespace std { + +template <> +struct hash<asio::ip::address_v4> +{ + std::size_t operator()(const asio::ip::address_v4& addr) + const noexcept + { + return std::hash<unsigned int>()(addr.to_uint()); + } +}; + +} // namespace std + #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/address_v4.hpp" diff --git a/3rdparty/asio/include/asio/ip/address_v4_iterator.hpp b/3rdparty/asio/include/asio/ip/address_v4_iterator.hpp index ad0889c9385..5b91f400ac1 100644 --- a/3rdparty/asio/include/asio/ip/address_v4_iterator.hpp +++ b/3rdparty/asio/include/asio/ip/address_v4_iterator.hpp @@ -2,7 +2,7 @@ // ip/address_v4_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -53,65 +53,59 @@ public: typedef std::input_iterator_tag iterator_category; /// Construct an iterator that points to the specified address. - basic_address_iterator(const address_v4& addr) ASIO_NOEXCEPT + basic_address_iterator(const address_v4& addr) noexcept : address_(addr) { } /// Copy constructor. - basic_address_iterator( - const basic_address_iterator& other) ASIO_NOEXCEPT + basic_address_iterator(const basic_address_iterator& other) noexcept : address_(other.address_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. - basic_address_iterator(basic_address_iterator&& other) ASIO_NOEXCEPT - : address_(ASIO_MOVE_CAST(address_v4)(other.address_)) + basic_address_iterator(basic_address_iterator&& other) noexcept + : address_(static_cast<address_v4&&>(other.address_)) { } -#endif // defined(ASIO_HAS_MOVE) /// Assignment operator. basic_address_iterator& operator=( - const basic_address_iterator& other) ASIO_NOEXCEPT + const basic_address_iterator& other) noexcept { address_ = other.address_; return *this; } -#if defined(ASIO_HAS_MOVE) /// Move assignment operator. - basic_address_iterator& operator=( - basic_address_iterator&& other) ASIO_NOEXCEPT + basic_address_iterator& operator=(basic_address_iterator&& other) noexcept { - address_ = ASIO_MOVE_CAST(address_v4)(other.address_); + address_ = static_cast<address_v4&&>(other.address_); return *this; } -#endif // defined(ASIO_HAS_MOVE) /// Dereference the iterator. - const address_v4& operator*() const ASIO_NOEXCEPT + const address_v4& operator*() const noexcept { return address_; } /// Dereference the iterator. - const address_v4* operator->() const ASIO_NOEXCEPT + const address_v4* operator->() const noexcept { return &address_; } /// Pre-increment operator. - basic_address_iterator& operator++() ASIO_NOEXCEPT + basic_address_iterator& operator++() noexcept { address_ = address_v4((address_.to_uint() + 1) & 0xFFFFFFFF); return *this; } /// Post-increment operator. - basic_address_iterator operator++(int) ASIO_NOEXCEPT + basic_address_iterator operator++(int) noexcept { basic_address_iterator tmp(*this); ++*this; @@ -119,7 +113,7 @@ public: } /// Pre-decrement operator. - basic_address_iterator& operator--() ASIO_NOEXCEPT + basic_address_iterator& operator--() noexcept { address_ = address_v4((address_.to_uint() - 1) & 0xFFFFFFFF); return *this; diff --git a/3rdparty/asio/include/asio/ip/address_v4_range.hpp b/3rdparty/asio/include/asio/ip/address_v4_range.hpp index 06f3bd1818a..5fb5e65e2aa 100644 --- a/3rdparty/asio/include/asio/ip/address_v4_range.hpp +++ b/3rdparty/asio/include/asio/ip/address_v4_range.hpp @@ -2,7 +2,7 @@ // ip/address_v4_range.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -38,7 +38,7 @@ public: typedef basic_address_iterator<address_v4> iterator; /// Construct an empty range. - basic_address_range() ASIO_NOEXCEPT + basic_address_range() noexcept : begin_(address_v4()), end_(address_v4()) { @@ -46,74 +46,68 @@ public: /// Construct an range that represents the given range of addresses. explicit basic_address_range(const iterator& first, - const iterator& last) ASIO_NOEXCEPT + const iterator& last) noexcept : begin_(first), end_(last) { } /// Copy constructor. - basic_address_range(const basic_address_range& other) ASIO_NOEXCEPT + basic_address_range(const basic_address_range& other) noexcept : begin_(other.begin_), end_(other.end_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. - basic_address_range(basic_address_range&& other) ASIO_NOEXCEPT - : begin_(ASIO_MOVE_CAST(iterator)(other.begin_)), - end_(ASIO_MOVE_CAST(iterator)(other.end_)) + basic_address_range(basic_address_range&& other) noexcept + : begin_(static_cast<iterator&&>(other.begin_)), + end_(static_cast<iterator&&>(other.end_)) { } -#endif // defined(ASIO_HAS_MOVE) /// Assignment operator. - basic_address_range& operator=( - const basic_address_range& other) ASIO_NOEXCEPT + basic_address_range& operator=(const basic_address_range& other) noexcept { begin_ = other.begin_; end_ = other.end_; return *this; } -#if defined(ASIO_HAS_MOVE) /// Move assignment operator. - basic_address_range& operator=( - basic_address_range&& other) ASIO_NOEXCEPT + basic_address_range& operator=(basic_address_range&& other) noexcept { - begin_ = ASIO_MOVE_CAST(iterator)(other.begin_); - end_ = ASIO_MOVE_CAST(iterator)(other.end_); + begin_ = static_cast<iterator&&>(other.begin_); + end_ = static_cast<iterator&&>(other.end_); return *this; } -#endif // defined(ASIO_HAS_MOVE) /// Obtain an iterator that points to the start of the range. - iterator begin() const ASIO_NOEXCEPT + iterator begin() const noexcept { return begin_; } /// Obtain an iterator that points to the end of the range. - iterator end() const ASIO_NOEXCEPT + iterator end() const noexcept { return end_; } /// Determine whether the range is empty. - bool empty() const ASIO_NOEXCEPT + bool empty() const noexcept { return size() == 0; } /// Return the size of the range. - std::size_t size() const ASIO_NOEXCEPT + std::size_t size() const noexcept { return end_->to_uint() - begin_->to_uint(); } /// Find an address in the range. - iterator find(const address_v4& addr) const ASIO_NOEXCEPT + iterator find(const address_v4& addr) const noexcept { return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_; } diff --git a/3rdparty/asio/include/asio/ip/address_v6.hpp b/3rdparty/asio/include/asio/ip/address_v6.hpp index 663601d4c4d..aa650825cf3 100644 --- a/3rdparty/asio/include/asio/ip/address_v6.hpp +++ b/3rdparty/asio/include/asio/ip/address_v6.hpp @@ -2,7 +2,7 @@ // ip/address_v6.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,8 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include <functional> #include <string> #include "asio/detail/array.hpp" +#include "asio/detail/cstdint.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/string_view.hpp" #include "asio/detail/winsock_init.hpp" @@ -35,6 +37,9 @@ namespace ip { template <typename> class basic_address_iterator; +/// Type used for storing IPv6 scope IDs. +typedef uint_least32_t scope_id_type; + /// Implements IP version 6 style addresses. /** * The asio::ip::address_v6 class provides the ability to use and @@ -59,33 +64,44 @@ public: #endif /// Default constructor. - ASIO_DECL address_v6(); + /** + * Initialises the @c address_v6 object such that: + * @li <tt>to_bytes()</tt> yields <tt>{0, 0, ..., 0}</tt>; and + * @li <tt>scope_id() == 0</tt>. + */ + ASIO_DECL address_v6() noexcept; /// Construct an address from raw bytes and scope ID. + /** + * Initialises the @c address_v6 object such that: + * @li <tt>to_bytes() == bytes</tt>; and + * @li <tt>this->scope_id() == scope_id</tt>. + * + * @throws out_of_range Thrown if any element in @c bytes is not in the range + * <tt>0 - 0xFF</tt>. Note that no range checking is required for platforms + * where <tt>std::numeric_limits<unsigned char>::max()</tt> is <tt>0xFF</tt>. + */ ASIO_DECL explicit address_v6(const bytes_type& bytes, - unsigned long scope_id = 0); + scope_id_type scope_id = 0); /// Copy constructor. - ASIO_DECL address_v6(const address_v6& other); + ASIO_DECL address_v6(const address_v6& other) noexcept; -#if defined(ASIO_HAS_MOVE) /// Move constructor. - ASIO_DECL address_v6(address_v6&& other); -#endif // defined(ASIO_HAS_MOVE) + ASIO_DECL address_v6(address_v6&& other) noexcept; /// Assign from another address. - ASIO_DECL address_v6& operator=(const address_v6& other); + ASIO_DECL address_v6& operator=( + const address_v6& other) noexcept; -#if defined(ASIO_HAS_MOVE) /// Move-assign from another address. - ASIO_DECL address_v6& operator=(address_v6&& other); -#endif // defined(ASIO_HAS_MOVE) + ASIO_DECL address_v6& operator=(address_v6&& other) noexcept; /// The scope ID of the address. /** * Returns the scope ID associated with the IPv6 address. */ - unsigned long scope_id() const + scope_id_type scope_id() const noexcept { return scope_id_; } @@ -93,14 +109,16 @@ public: /// The scope ID of the address. /** * Modifies the scope ID associated with the IPv6 address. + * + * @param id The new scope ID. */ - void scope_id(unsigned long id) + void scope_id(scope_id_type id) noexcept { scope_id_ = id; } /// Get the address in bytes, in network byte order. - ASIO_DECL bytes_type to_bytes() const; + ASIO_DECL bytes_type to_bytes() const noexcept; /// Get the address as a string. ASIO_DECL std::string to_string() const; @@ -133,19 +151,27 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. - ASIO_DECL bool is_loopback() const; + /** + * This function tests whether the address is the loopback address + * <tt>::1</tt>. + */ + ASIO_DECL bool is_loopback() const noexcept; /// Determine whether the address is unspecified. - ASIO_DECL bool is_unspecified() const; + /** + * This function tests whether the address is the loopback address + * <tt>::</tt>. + */ + ASIO_DECL bool is_unspecified() const noexcept; /// Determine whether the address is link local. - ASIO_DECL bool is_link_local() const; + ASIO_DECL bool is_link_local() const noexcept; /// Determine whether the address is site local. - ASIO_DECL bool is_site_local() const; + ASIO_DECL bool is_site_local() const noexcept; /// Determine whether the address is a mapped IPv4 address. - ASIO_DECL bool is_v4_mapped() const; + ASIO_DECL bool is_v4_mapped() const noexcept; #if !defined(ASIO_NO_DEPRECATED) /// (Deprecated: No replacement.) Determine whether the address is an @@ -154,63 +180,77 @@ public: #endif // !defined(ASIO_NO_DEPRECATED) /// Determine whether the address is a multicast address. - ASIO_DECL bool is_multicast() const; + ASIO_DECL bool is_multicast() const noexcept; /// Determine whether the address is a global multicast address. - ASIO_DECL bool is_multicast_global() const; + ASIO_DECL bool is_multicast_global() const noexcept; /// Determine whether the address is a link-local multicast address. - ASIO_DECL bool is_multicast_link_local() const; + ASIO_DECL bool is_multicast_link_local() const noexcept; /// Determine whether the address is a node-local multicast address. - ASIO_DECL bool is_multicast_node_local() const; + ASIO_DECL bool is_multicast_node_local() const noexcept; /// Determine whether the address is a org-local multicast address. - ASIO_DECL bool is_multicast_org_local() const; + ASIO_DECL bool is_multicast_org_local() const noexcept; /// Determine whether the address is a site-local multicast address. - ASIO_DECL bool is_multicast_site_local() const; + ASIO_DECL bool is_multicast_site_local() const noexcept; /// Compare two addresses for equality. - ASIO_DECL friend bool operator==( - const address_v6& a1, const address_v6& a2); + ASIO_DECL friend bool operator==(const address_v6& a1, + const address_v6& a2) noexcept; /// Compare two addresses for inequality. - friend bool operator!=(const address_v6& a1, const address_v6& a2) + friend bool operator!=(const address_v6& a1, + const address_v6& a2) noexcept { return !(a1 == a2); } /// Compare addresses for ordering. - ASIO_DECL friend bool operator<( - const address_v6& a1, const address_v6& a2); + ASIO_DECL friend bool operator<(const address_v6& a1, + const address_v6& a2) noexcept; /// Compare addresses for ordering. - friend bool operator>(const address_v6& a1, const address_v6& a2) + friend bool operator>(const address_v6& a1, + const address_v6& a2) noexcept { return a2 < a1; } /// Compare addresses for ordering. - friend bool operator<=(const address_v6& a1, const address_v6& a2) + friend bool operator<=(const address_v6& a1, + const address_v6& a2) noexcept { return !(a2 < a1); } /// Compare addresses for ordering. - friend bool operator>=(const address_v6& a1, const address_v6& a2) + friend bool operator>=(const address_v6& a1, + const address_v6& a2) noexcept { return !(a1 < a2); } /// Obtain an address object that represents any address. - static address_v6 any() + /** + * This functions returns an address that represents the "any" address + * <tt>::</tt>. + * + * @returns A default-constructed @c address_v6 object. + */ + static address_v6 any() noexcept { return address_v6(); } /// Obtain an address object that represents the loopback address. - ASIO_DECL static address_v6 loopback(); + /** + * This function returns an address that represents the well-known loopback + * address <tt>::1</tt>. + */ + ASIO_DECL static address_v6 loopback() noexcept; #if !defined(ASIO_NO_DEPRECATED) /// (Deprecated: Use make_address_v6().) Create an IPv4-mapped IPv6 address. @@ -227,7 +267,7 @@ private: asio::detail::in6_addr_type addr_; // The scope ID associated with the address. - unsigned long scope_id_; + scope_id_type scope_id_; }; /// Create an IPv6 address from raw bytes and scope ID. @@ -235,7 +275,7 @@ private: * @relates address_v6 */ inline address_v6 make_address_v6(const address_v6::bytes_type& bytes, - unsigned long scope_id = 0) + scope_id_type scope_id = 0) { return address_v6(bytes, scope_id); } @@ -250,8 +290,8 @@ ASIO_DECL address_v6 make_address_v6(const char* str); /** * @relates address_v6 */ -ASIO_DECL address_v6 make_address_v6( - const char* str, asio::error_code& ec); +ASIO_DECL address_v6 make_address_v6(const char* str, + asio::error_code& ec) noexcept; /// Createan IPv6 address from an IP address string. /** @@ -263,10 +303,10 @@ ASIO_DECL address_v6 make_address_v6(const std::string& str); /** * @relates address_v6 */ -ASIO_DECL address_v6 make_address_v6( - const std::string& str, asio::error_code& ec); +ASIO_DECL address_v6 make_address_v6(const std::string& str, + asio::error_code& ec) noexcept; -#if defined(ASIO_HAS_STD_STRING_VIEW) \ +#if defined(ASIO_HAS_STRING_VIEW) \ || defined(GENERATING_DOCUMENTATION) /// Create an IPv6 address from an IP address string. @@ -279,10 +319,10 @@ ASIO_DECL address_v6 make_address_v6(string_view str); /** * @relates address_v6 */ -ASIO_DECL address_v6 make_address_v6( - string_view str, asio::error_code& ec); +ASIO_DECL address_v6 make_address_v6(string_view str, + asio::error_code& ec) noexcept; -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) // || defined(GENERATING_DOCUMENTATION) /// Tag type used for distinguishing overloads that deal in IPv4-mapped IPv6 @@ -326,6 +366,37 @@ std::basic_ostream<Elem, Traits>& operator<<( } // namespace ip } // namespace asio +namespace std { + +template <> +struct hash<asio::ip::address_v6> +{ + std::size_t operator()(const asio::ip::address_v6& addr) + const noexcept + { + const asio::ip::address_v6::bytes_type bytes = addr.to_bytes(); + std::size_t result = static_cast<std::size_t>(addr.scope_id()); + combine_4_bytes(result, &bytes[0]); + combine_4_bytes(result, &bytes[4]); + combine_4_bytes(result, &bytes[8]); + combine_4_bytes(result, &bytes[12]); + return result; + } + +private: + static void combine_4_bytes(std::size_t& seed, const unsigned char* bytes) + { + const std::size_t bytes_hash = + (static_cast<std::size_t>(bytes[0]) << 24) | + (static_cast<std::size_t>(bytes[1]) << 16) | + (static_cast<std::size_t>(bytes[2]) << 8) | + (static_cast<std::size_t>(bytes[3])); + seed ^= bytes_hash + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } +}; + +} // namespace std + #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/address_v6.hpp" diff --git a/3rdparty/asio/include/asio/ip/address_v6_iterator.hpp b/3rdparty/asio/include/asio/ip/address_v6_iterator.hpp index 947af07b028..5116f614f08 100644 --- a/3rdparty/asio/include/asio/ip/address_v6_iterator.hpp +++ b/3rdparty/asio/include/asio/ip/address_v6_iterator.hpp @@ -2,7 +2,7 @@ // ip/address_v6_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Oliver Kowalke (oliver dot kowalke at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -54,58 +54,53 @@ public: typedef std::input_iterator_tag iterator_category; /// Construct an iterator that points to the specified address. - basic_address_iterator(const address_v6& addr) ASIO_NOEXCEPT + basic_address_iterator(const address_v6& addr) noexcept : address_(addr) { } /// Copy constructor. basic_address_iterator( - const basic_address_iterator& other) ASIO_NOEXCEPT + const basic_address_iterator& other) noexcept : address_(other.address_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. - basic_address_iterator(basic_address_iterator&& other) ASIO_NOEXCEPT - : address_(ASIO_MOVE_CAST(address_v6)(other.address_)) + basic_address_iterator(basic_address_iterator&& other) noexcept + : address_(static_cast<address_v6&&>(other.address_)) { } -#endif // defined(ASIO_HAS_MOVE) /// Assignment operator. basic_address_iterator& operator=( - const basic_address_iterator& other) ASIO_NOEXCEPT + const basic_address_iterator& other) noexcept { address_ = other.address_; return *this; } -#if defined(ASIO_HAS_MOVE) /// Move assignment operator. - basic_address_iterator& operator=( - basic_address_iterator&& other) ASIO_NOEXCEPT + basic_address_iterator& operator=(basic_address_iterator&& other) noexcept { - address_ = ASIO_MOVE_CAST(address_v6)(other.address_); + address_ = static_cast<address_v6&&>(other.address_); return *this; } -#endif // defined(ASIO_HAS_MOVE) /// Dereference the iterator. - const address_v6& operator*() const ASIO_NOEXCEPT + const address_v6& operator*() const noexcept { return address_; } /// Dereference the iterator. - const address_v6* operator->() const ASIO_NOEXCEPT + const address_v6* operator->() const noexcept { return &address_; } /// Pre-increment operator. - basic_address_iterator& operator++() ASIO_NOEXCEPT + basic_address_iterator& operator++() noexcept { for (int i = 15; i >= 0; --i) { @@ -122,7 +117,7 @@ public: } /// Post-increment operator. - basic_address_iterator operator++(int) ASIO_NOEXCEPT + basic_address_iterator operator++(int) noexcept { basic_address_iterator tmp(*this); ++*this; @@ -130,7 +125,7 @@ public: } /// Pre-decrement operator. - basic_address_iterator& operator--() ASIO_NOEXCEPT + basic_address_iterator& operator--() noexcept { for (int i = 15; i >= 0; --i) { diff --git a/3rdparty/asio/include/asio/ip/address_v6_range.hpp b/3rdparty/asio/include/asio/ip/address_v6_range.hpp index 4dc7a30e06c..7f89773383d 100644 --- a/3rdparty/asio/include/asio/ip/address_v6_range.hpp +++ b/3rdparty/asio/include/asio/ip/address_v6_range.hpp @@ -2,7 +2,7 @@ // ip/address_v6_range.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Oliver Kowalke (oliver dot kowalke at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -39,7 +39,7 @@ public: typedef basic_address_iterator<address_v6> iterator; /// Construct an empty range. - basic_address_range() ASIO_NOEXCEPT + basic_address_range() noexcept : begin_(address_v6()), end_(address_v6()) { @@ -47,68 +47,63 @@ public: /// Construct an range that represents the given range of addresses. explicit basic_address_range(const iterator& first, - const iterator& last) ASIO_NOEXCEPT + const iterator& last) noexcept : begin_(first), end_(last) { } /// Copy constructor. - basic_address_range(const basic_address_range& other) ASIO_NOEXCEPT + basic_address_range(const basic_address_range& other) noexcept : begin_(other.begin_), end_(other.end_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. - basic_address_range(basic_address_range&& other) ASIO_NOEXCEPT - : begin_(ASIO_MOVE_CAST(iterator)(other.begin_)), - end_(ASIO_MOVE_CAST(iterator)(other.end_)) + basic_address_range(basic_address_range&& other) noexcept + : begin_(static_cast<iterator&&>(other.begin_)), + end_(static_cast<iterator&&>(other.end_)) { } -#endif // defined(ASIO_HAS_MOVE) /// Assignment operator. basic_address_range& operator=( - const basic_address_range& other) ASIO_NOEXCEPT + const basic_address_range& other) noexcept { begin_ = other.begin_; end_ = other.end_; return *this; } -#if defined(ASIO_HAS_MOVE) /// Move assignment operator. - basic_address_range& operator=( - basic_address_range&& other) ASIO_NOEXCEPT + basic_address_range& operator=(basic_address_range&& other) noexcept { - begin_ = ASIO_MOVE_CAST(iterator)(other.begin_); - end_ = ASIO_MOVE_CAST(iterator)(other.end_); + begin_ = static_cast<iterator&&>(other.begin_); + end_ = static_cast<iterator&&>(other.end_); return *this; } -#endif // defined(ASIO_HAS_MOVE) /// Obtain an iterator that points to the start of the range. - iterator begin() const ASIO_NOEXCEPT + iterator begin() const noexcept { return begin_; } /// Obtain an iterator that points to the end of the range. - iterator end() const ASIO_NOEXCEPT + iterator end() const noexcept { return end_; } /// Determine whether the range is empty. - bool empty() const ASIO_NOEXCEPT + bool empty() const noexcept { return begin_ == end_; } /// Find an address in the range. - iterator find(const address_v6& addr) const ASIO_NOEXCEPT + iterator find(const address_v6& addr) const noexcept { return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_; } diff --git a/3rdparty/asio/include/asio/ip/bad_address_cast.hpp b/3rdparty/asio/include/asio/ip/bad_address_cast.hpp index 6c479146595..3d242f07048 100644 --- a/3rdparty/asio/include/asio/ip/bad_address_cast.hpp +++ b/3rdparty/asio/include/asio/ip/bad_address_cast.hpp @@ -2,7 +2,7 @@ // ip/bad_address_cast.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -24,17 +24,32 @@ namespace asio { namespace ip { /// Thrown to indicate a failed address conversion. -class bad_address_cast : public std::bad_cast +class bad_address_cast : +#if defined(ASIO_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS + public std::exception +#else + public std::bad_cast +#endif { public: /// Default constructor. bad_address_cast() {} + /// Copy constructor. + bad_address_cast(const bad_address_cast& other) noexcept +#if defined(ASIO_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS + : std::exception(static_cast<const std::exception&>(other)) +#else + : std::bad_cast(static_cast<const std::bad_cast&>(other)) +#endif + { + } + /// Destructor. - virtual ~bad_address_cast() ASIO_NOEXCEPT_OR_NOTHROW {} + virtual ~bad_address_cast() noexcept {} /// Get the message associated with the exception. - virtual const char* what() const ASIO_NOEXCEPT_OR_NOTHROW + virtual const char* what() const noexcept { return "bad address cast"; } diff --git a/3rdparty/asio/include/asio/ip/basic_endpoint.hpp b/3rdparty/asio/include/asio/ip/basic_endpoint.hpp index d48f6441a6e..3dfb1248db7 100644 --- a/3rdparty/asio/include/asio/ip/basic_endpoint.hpp +++ b/3rdparty/asio/include/asio/ip/basic_endpoint.hpp @@ -2,7 +2,7 @@ // ip/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,6 +16,8 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include <functional> +#include "asio/detail/cstdint.hpp" #include "asio/ip/address.hpp" #include "asio/ip/detail/endpoint.hpp" @@ -28,6 +30,9 @@ namespace asio { namespace ip { +/// Type used for storing port numbers. +typedef uint_least16_t port_type; + /// Describes an endpoint for a version-independent IP socket. /** * The asio::ip::basic_endpoint class template describes an endpoint that @@ -56,7 +61,7 @@ public: #endif /// Default constructor. - basic_endpoint() + basic_endpoint() noexcept : impl_() { } @@ -78,7 +83,7 @@ public: * @endcode */ basic_endpoint(const InternetProtocol& internet_protocol, - unsigned short port_num) + port_type port_num) noexcept : impl_(internet_protocol.family(), port_num) { } @@ -86,43 +91,40 @@ public: /// Construct an endpoint using a port number and an IP address. This /// constructor may be used for accepting connections on a specific interface /// or for making a connection to a remote endpoint. - basic_endpoint(const asio::ip::address& addr, unsigned short port_num) + basic_endpoint(const asio::ip::address& addr, + port_type port_num) noexcept : impl_(addr, port_num) { } /// Copy constructor. - basic_endpoint(const basic_endpoint& other) + basic_endpoint(const basic_endpoint& other) noexcept : impl_(other.impl_) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. - basic_endpoint(basic_endpoint&& other) + basic_endpoint(basic_endpoint&& other) noexcept : impl_(other.impl_) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Assign from another endpoint. - basic_endpoint& operator=(const basic_endpoint& other) + basic_endpoint& operator=(const basic_endpoint& other) noexcept { impl_ = other.impl_; return *this; } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-assign from another endpoint. - basic_endpoint& operator=(basic_endpoint&& other) + basic_endpoint& operator=(basic_endpoint&& other) noexcept { impl_ = other.impl_; return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// The protocol associated with the endpoint. - protocol_type protocol() const + protocol_type protocol() const noexcept { if (impl_.is_v4()) return InternetProtocol::v4(); @@ -130,19 +132,19 @@ public: } /// Get the underlying endpoint in the native type. - data_type* data() + data_type* data() noexcept { return impl_.data(); } /// Get the underlying endpoint in the native type. - const data_type* data() const + const data_type* data() const noexcept { return impl_.data(); } /// Get the underlying size of the endpoint in the native type. - std::size_t size() const + std::size_t size() const noexcept { return impl_.size(); } @@ -154,75 +156,75 @@ public: } /// Get the capacity of the endpoint in the native type. - std::size_t capacity() const + std::size_t capacity() const noexcept { return impl_.capacity(); } /// Get the port associated with the endpoint. The port number is always in /// the host's byte order. - unsigned short port() const + port_type port() const noexcept { return impl_.port(); } /// Set the port associated with the endpoint. The port number is always in /// the host's byte order. - void port(unsigned short port_num) + void port(port_type port_num) noexcept { impl_.port(port_num); } /// Get the IP address associated with the endpoint. - asio::ip::address address() const + asio::ip::address address() const noexcept { return impl_.address(); } /// Set the IP address associated with the endpoint. - void address(const asio::ip::address& addr) + void address(const asio::ip::address& addr) noexcept { impl_.address(addr); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint<InternetProtocol>& e1, - const basic_endpoint<InternetProtocol>& e2) + const basic_endpoint<InternetProtocol>& e2) noexcept { return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint<InternetProtocol>& e1, - const basic_endpoint<InternetProtocol>& e2) + const basic_endpoint<InternetProtocol>& e2) noexcept { return !(e1 == e2); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint<InternetProtocol>& e1, - const basic_endpoint<InternetProtocol>& e2) + const basic_endpoint<InternetProtocol>& e2) noexcept { return e1.impl_ < e2.impl_; } /// Compare endpoints for ordering. friend bool operator>(const basic_endpoint<InternetProtocol>& e1, - const basic_endpoint<InternetProtocol>& e2) + const basic_endpoint<InternetProtocol>& e2) noexcept { return e2.impl_ < e1.impl_; } /// Compare endpoints for ordering. friend bool operator<=(const basic_endpoint<InternetProtocol>& e1, - const basic_endpoint<InternetProtocol>& e2) + const basic_endpoint<InternetProtocol>& e2) noexcept { return !(e2 < e1); } /// Compare endpoints for ordering. friend bool operator>=(const basic_endpoint<InternetProtocol>& e1, - const basic_endpoint<InternetProtocol>& e2) + const basic_endpoint<InternetProtocol>& e2) noexcept { return !(e1 < e2); } @@ -256,6 +258,23 @@ std::basic_ostream<Elem, Traits>& operator<<( } // namespace ip } // namespace asio +namespace std { + +template <typename InternetProtocol> +struct hash<asio::ip::basic_endpoint<InternetProtocol>> +{ + std::size_t operator()( + const asio::ip::basic_endpoint<InternetProtocol>& ep) + const noexcept + { + std::size_t hash1 = std::hash<asio::ip::address>()(ep.address()); + std::size_t hash2 = std::hash<unsigned short>()(ep.port()); + return hash1 ^ (hash2 + 0x9e3779b9 + (hash1 << 6) + (hash1 >> 2)); + } +}; + +} // namespace std + #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/basic_endpoint.hpp" diff --git a/3rdparty/asio/include/asio/ip/basic_resolver.hpp b/3rdparty/asio/include/asio/ip/basic_resolver.hpp index 3aa61fb8dac..4d41bfde090 100644 --- a/3rdparty/asio/include/asio/ip/basic_resolver.hpp +++ b/3rdparty/asio/include/asio/ip/basic_resolver.hpp @@ -2,7 +2,7 @@ // ip/basic_resolver.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,41 +17,40 @@ #include "asio/detail/config.hpp" #include <string> +#include <utility> +#include "asio/any_io_executor.hpp" #include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/string_view.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" -#include "asio/io_context.hpp" +#include "asio/execution_context.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/ip/basic_resolver_results.hpp" #include "asio/ip/resolver_base.hpp" - -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/ip/resolver_service.hpp" -#else // defined(ASIO_ENABLE_OLD_SERVICES) -# if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/winrt_resolver_service.hpp" -# define ASIO_SVC_T \ - asio::detail::winrt_resolver_service<InternetProtocol> -# else -# include "asio/detail/resolver_service.hpp" -# define ASIO_SVC_T \ - asio::detail::resolver_service<InternetProtocol> -# endif -#endif // defined(ASIO_ENABLE_OLD_SERVICES) +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/winrt_resolver_service.hpp" +#else +# include "asio/detail/resolver_service.hpp" +#endif #include "asio/detail/push_options.hpp" namespace asio { namespace ip { +#if !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL) +#define ASIO_IP_BASIC_RESOLVER_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename InternetProtocol, typename Executor = any_io_executor> +class basic_resolver; + +#endif // !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL) + /// Provides endpoint resolution functionality. /** * The basic_resolver class template provides the ability to resolve a query @@ -61,15 +60,24 @@ namespace ip { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename InternetProtocol - ASIO_SVC_TPARAM_DEF1(= resolver_service<InternetProtocol>)> +template <typename InternetProtocol, typename Executor> class basic_resolver - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>, - public resolver_base + : public resolver_base { +private: + class initiate_async_resolve; + public: /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; + typedef Executor executor_type; + + /// Rebinds the resolver type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The resolver type when rebound to the specified executor. + typedef basic_resolver<InternetProtocol, Executor1> other; + }; /// The protocol type. typedef InternetProtocol protocol_type; @@ -88,20 +96,36 @@ public: /// The results type. typedef basic_resolver_results<InternetProtocol> results_type; - /// Constructor. + /// Construct with executor. /** * This constructor creates a basic_resolver. * - * @param io_context The io_context object that the resolver will use to + * @param ex The I/O executor that the resolver will use, by default, to * dispatch handlers for any asynchronous operations performed on the * resolver. */ - explicit basic_resolver(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) + explicit basic_resolver(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct with execution context. + /** + * This constructor creates a basic_resolver. + * + * @param context An execution context which provides the I/O executor that + * the resolver will use, by default, to dispatch handlers for any + * asynchronous operations performed on the resolver. + */ + template <typename ExecutionContext> + explicit basic_resolver(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_resolver from another. /** * This constructor moves a resolver from one object to another. @@ -110,10 +134,33 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_resolver(io_context&) constructor. + * constructed using the @c basic_resolver(const executor_type&) constructor. */ basic_resolver(basic_resolver&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) + : impl_(std::move(other.impl_)) + { + } + + // All resolvers have access to each other's implementations. + template <typename InternetProtocol1, typename Executor1> + friend class basic_resolver; + + /// Move-construct a basic_resolver from another. + /** + * This constructor moves a resolver from one object to another. + * + * @param other The other basic_resolver object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_resolver(const executor_type&) constructor. + */ + template <typename Executor1> + basic_resolver(basic_resolver<InternetProtocol, Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value + > = 0) + : impl_(std::move(other.impl_)) { } @@ -127,64 +174,52 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_resolver(io_context&) constructor. + * constructed using the @c basic_resolver(const executor_type&) constructor. */ basic_resolver& operator=(basic_resolver&& other) { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); + impl_ = std::move(other.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroys the resolver. - /** - * This function destroys the resolver, cancelling any outstanding - * asynchronous wait operations associated with the resolver as if by calling - * @c cancel. - */ - ~basic_resolver() - { - } -#if defined(ASIO_ENABLE_OLD_SERVICES) - // These functions are provided by basic_io_object<>. -#else // defined(ASIO_ENABLE_OLD_SERVICES) -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. + /// Move-assign a basic_resolver from another. /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. + * This assignment operator moves a resolver from one object to another. + * Cancels any outstanding asynchronous operations associated with the target + * object. + * + * @param other The other basic_resolver object from which the move will + * occur. * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_resolver(const executor_type&) constructor. */ - asio::io_context& get_io_context() + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_resolver& + > operator=(basic_resolver<InternetProtocol, Executor1>&& other) { - return basic_io_object<ASIO_SVC_T>::get_io_context(); + basic_resolver tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; } - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. + /// Destroys the resolver. /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. + * This function destroys the resolver, cancelling any outstanding + * asynchronous wait operations associated with the resolver as if by calling + * @c cancel. */ - asio::io_context& get_io_service() + ~basic_resolver() { - return basic_io_object<ASIO_SVC_T>::get_io_service(); } -#endif // !defined(ASIO_NO_DEPRECATED) /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + executor_type get_executor() noexcept { - return basic_io_object<ASIO_SVC_T>::get_executor(); + return impl_.get_executor(); } -#endif // defined(ASIO_ENABLE_OLD_SERVICES) /// Cancel any asynchronous operations that are waiting on the resolver. /** @@ -194,11 +229,12 @@ public: */ void cancel() { - return this->get_service().cancel(this->get_implementation()); + return impl_.get_service().cancel(impl_.get_implementation()); } #if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated.) Perform forward resolution of a query to a list of entries. + /// (Deprecated: Use overload with separate host and service parameters.) + /// Perform forward resolution of a query to a list of entries. /** * This function is used to resolve a query into a list of endpoint entries. * @@ -213,13 +249,14 @@ public: results_type resolve(const query& q) { asio::error_code ec; - results_type r = this->get_service().resolve( - this->get_implementation(), q, ec); + results_type r = impl_.get_service().resolve( + impl_.get_implementation(), q, ec); asio::detail::throw_error(ec, "resolve"); return r; } - /// (Deprecated.) Perform forward resolution of a query to a list of entries. + /// (Deprecated: Use overload with separate host and service parameters.) + /// Perform forward resolution of a query to a list of entries. /** * This function is used to resolve a query into a list of endpoint entries. * @@ -233,7 +270,7 @@ public: */ results_type resolve(const query& q, asio::error_code& ec) { - return this->get_service().resolve(this->get_implementation(), q, ec); + return impl_.get_service().resolve(impl_.get_implementation(), q, ec); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -333,7 +370,8 @@ public: * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with - * remote hosts. + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. * * @returns A range object representing the list of endpoint entries. A * successful call to this function is guaranteed to return a non-empty @@ -358,8 +396,8 @@ public: asio::error_code ec; basic_resolver_query<protocol_type> q(static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); - results_type r = this->get_service().resolve( - this->get_implementation(), q, ec); + results_type r = impl_.get_service().resolve( + impl_.get_implementation(), q, ec); asio::detail::throw_error(ec, "resolve"); return r; } @@ -382,7 +420,8 @@ public: * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with - * remote hosts. + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. * * @param ec Set to indicate what error occurred, if any. * @@ -407,7 +446,7 @@ public: { basic_resolver_query<protocol_type> q(static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); - return this->get_service().resolve(this->get_implementation(), q, ec); + return impl_.get_service().resolve(impl_.get_implementation(), q, ec); } /// Perform forward resolution of a query to a list of entries. @@ -516,7 +555,8 @@ public: * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with - * remote hosts. + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. * * @returns A range object representing the list of endpoint entries. A * successful call to this function is guaranteed to return a non-empty @@ -543,8 +583,8 @@ public: basic_resolver_query<protocol_type> q( protocol, static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); - results_type r = this->get_service().resolve( - this->get_implementation(), q, ec); + results_type r = impl_.get_service().resolve( + impl_.get_implementation(), q, ec); asio::detail::throw_error(ec, "resolve"); return r; } @@ -570,7 +610,8 @@ public: * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with - * remote hosts. + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. * * @param ec Set to indicate what error occurred, if any. * @@ -596,56 +637,52 @@ public: basic_resolver_query<protocol_type> q( protocol, static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); - return this->get_service().resolve(this->get_implementation(), q, ec); + return impl_.get_service().resolve(impl_.get_implementation(), q, ec); } #if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated.) Asynchronously perform forward resolution of a query to a - /// list of entries. + /// (Deprecated: Use overload with separate host and service parameters.) + /// Asynchronously perform forward resolution of a query to a list of entries. /** * This function is used to asynchronously resolve a query into a list of - * endpoint entries. + * endpoint entries. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param q A query object that determines what endpoints will be returned. * - * @param handler The handler to be called when the resolve operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the resolve completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::results_type results // Resolved endpoints as a range. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. + * + * @par Completion Signature + * @code void(asio::error_code, results_type) @endcode */ - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(const query& q, - ASIO_MOVE_ARG(ResolveHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + results_type)) ResolveToken = default_completion_token_t<executor_type>> + auto async_resolve(const query& q, + ResolveToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + declval<initiate_async_resolve>(), token, q)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ResolveHandler. - ASIO_RESOLVE_HANDLER_CHECK( - ResolveHandler, handler, results_type) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_resolve(this->get_implementation(), q, - ASIO_MOVE_CAST(ResolveHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - asio::async_completion<ResolveHandler, - void (asio::error_code, results_type)> init(handler); - - this->get_service().async_resolve( - this->get_implementation(), q, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + initiate_async_resolve(this), token, q); } #endif // !defined(ASIO_NO_DEPRECATED) @@ -665,21 +702,26 @@ public: * be an empty string, in which case all resolved endpoints will have a port * number of 0. * - * @param handler The handler to be called when the resolve operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the resolve completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::results_type results // Resolved endpoints as a range. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. * + * @par Completion Signature + * @code void(asio::error_code, results_type) @endcode + * * @note On POSIX systems, host names may be locally defined in the file * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name @@ -691,21 +733,27 @@ public: * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(ASIO_STRING_VIEW_PARAM host, + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + results_type)) ResolveToken = default_completion_token_t<executor_type>> + auto async_resolve(ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service, - ASIO_MOVE_ARG(ResolveHandler) handler) + ResolveToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + declval<initiate_async_resolve>(), token, + declval<basic_resolver_query<protocol_type>&>())) { return async_resolve(host, service, resolver_base::flags(), - ASIO_MOVE_CAST(ResolveHandler)(handler)); + static_cast<ResolveToken&&>(token)); } /// Asynchronously perform forward resolution of a query to a list of entries. /** * This function is used to resolve host and service names into a list of - * endpoint entries. + * endpoint entries. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param host A string identifying a location. May be a descriptive name or * a numeric address string. If an empty string and the passive flag has been @@ -720,23 +768,29 @@ public: * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with - * remote hosts. - * - * @param handler The handler to be called when the resolve operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the resolve completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::results_type results // Resolved endpoints as a range. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. * + * @par Completion Signature + * @code void(asio::error_code, results_type) @endcode + * * @note On POSIX systems, host names may be locally defined in the file * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name @@ -748,40 +802,31 @@ public: * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(ASIO_STRING_VIEW_PARAM host, - ASIO_STRING_VIEW_PARAM service, - resolver_base::flags resolve_flags, - ASIO_MOVE_ARG(ResolveHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + results_type)) ResolveToken = default_completion_token_t<executor_type>> + auto async_resolve(ASIO_STRING_VIEW_PARAM host, + ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags, + ResolveToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + declval<initiate_async_resolve>(), token, + declval<basic_resolver_query<protocol_type>&>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ResolveHandler. - ASIO_RESOLVE_HANDLER_CHECK( - ResolveHandler, handler, results_type) type_check; - basic_resolver_query<protocol_type> q(static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_resolve(this->get_implementation(), q, - ASIO_MOVE_CAST(ResolveHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - asio::async_completion<ResolveHandler, - void (asio::error_code, results_type)> init(handler); - - this->get_service().async_resolve( - this->get_implementation(), q, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + initiate_async_resolve(this), token, q); } /// Asynchronously perform forward resolution of a query to a list of entries. /** * This function is used to resolve host and service names into a list of - * endpoint entries. + * endpoint entries. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param protocol A protocol object, normally representing either the IPv4 or * IPv6 version of an internet protocol. @@ -797,21 +842,26 @@ public: * be an empty string, in which case all resolved endpoints will have a port * number of 0. * - * @param handler The handler to be called when the resolve operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the resolve completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::results_type results // Resolved endpoints as a range. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. * + * @par Completion Signature + * @code void(asio::error_code, results_type) @endcode + * * @note On POSIX systems, host names may be locally defined in the file * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name @@ -823,21 +873,27 @@ public: * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(const protocol_type& protocol, + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + results_type)) ResolveToken = default_completion_token_t<executor_type>> + auto async_resolve(const protocol_type& protocol, ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service, - ASIO_MOVE_ARG(ResolveHandler) handler) + ResolveToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + declval<initiate_async_resolve>(), token, + declval<basic_resolver_query<protocol_type>&>())) { return async_resolve(protocol, host, service, resolver_base::flags(), - ASIO_MOVE_CAST(ResolveHandler)(handler)); + static_cast<ResolveToken&&>(token)); } /// Asynchronously perform forward resolution of a query to a list of entries. /** * This function is used to resolve host and service names into a list of - * endpoint entries. + * endpoint entries. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param protocol A protocol object, normally representing either the IPv4 or * IPv6 version of an internet protocol. @@ -855,23 +911,29 @@ public: * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with - * remote hosts. - * - * @param handler The handler to be called when the resolve operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the resolve completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::results_type results // Resolved endpoints as a range. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. * + * @par Completion Signature + * @code void(asio::error_code, results_type) @endcode + * * @note On POSIX systems, host names may be locally defined in the file * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name @@ -883,35 +945,26 @@ public: * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(const protocol_type& protocol, + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + results_type)) ResolveToken = default_completion_token_t<executor_type>> + auto async_resolve(const protocol_type& protocol, ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags, - ASIO_MOVE_ARG(ResolveHandler) handler) + ResolveToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + declval<initiate_async_resolve>(), token, + declval<basic_resolver_query<protocol_type>&>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ResolveHandler. - ASIO_RESOLVE_HANDLER_CHECK( - ResolveHandler, handler, results_type) type_check; - basic_resolver_query<protocol_type> q( protocol, static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_resolve(this->get_implementation(), q, - ASIO_MOVE_CAST(ResolveHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - asio::async_completion<ResolveHandler, - void (asio::error_code, results_type)> init(handler); - - this->get_service().async_resolve( - this->get_implementation(), q, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + initiate_async_resolve(this), token, q); } /// Perform reverse resolution of an endpoint to a list of entries. @@ -931,8 +984,8 @@ public: results_type resolve(const endpoint_type& e) { asio::error_code ec; - results_type i = this->get_service().resolve( - this->get_implementation(), e, ec); + results_type i = impl_.get_service().resolve( + impl_.get_implementation(), e, ec); asio::detail::throw_error(ec, "resolve"); return i; } @@ -953,57 +1006,102 @@ public: */ results_type resolve(const endpoint_type& e, asio::error_code& ec) { - return this->get_service().resolve(this->get_implementation(), e, ec); + return impl_.get_service().resolve(impl_.get_implementation(), e, ec); } /// Asynchronously perform reverse resolution of an endpoint to a list of /// entries. /** * This function is used to asynchronously resolve an endpoint into a list of - * endpoint entries. + * endpoint entries. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param e An endpoint object that determines what endpoints will be * returned. * - * @param handler The handler to be called when the resolve operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the resolve completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::results_type results // Resolved endpoints as a range. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. + * + * @par Completion Signature + * @code void(asio::error_code, results_type) @endcode */ - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(const endpoint_type& e, - ASIO_MOVE_ARG(ResolveHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + results_type)) ResolveToken = default_completion_token_t<executor_type>> + auto async_resolve(const endpoint_type& e, + ResolveToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + declval<initiate_async_resolve>(), token, e)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ResolveHandler. - ASIO_RESOLVE_HANDLER_CHECK( - ResolveHandler, handler, results_type) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_resolve(this->get_implementation(), e, - ASIO_MOVE_CAST(ResolveHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - asio::async_completion<ResolveHandler, - void (asio::error_code, results_type)> init(handler); - - this->get_service().async_resolve( - this->get_implementation(), e, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return asio::async_initiate<ResolveToken, + void (asio::error_code, results_type)>( + initiate_async_resolve(this), token, e); } + +private: + // Disallow copying and assignment. + basic_resolver(const basic_resolver&) = delete; + basic_resolver& operator=(const basic_resolver&) = delete; + + class initiate_async_resolve + { + public: + typedef Executor executor_type; + + explicit initiate_async_resolve(basic_resolver* self) + : self_(self) + { + } + + executor_type get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ResolveHandler, typename Query> + void operator()(ResolveHandler&& handler, + const Query& q) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ResolveHandler. + ASIO_RESOLVE_HANDLER_CHECK( + ResolveHandler, handler, results_type) type_check; + + asio::detail::non_const_lvalue<ResolveHandler> handler2(handler); + self_->impl_.get_service().async_resolve( + self_->impl_.get_implementation(), q, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_resolver* self_; + }; + +# if defined(ASIO_WINDOWS_RUNTIME) + asio::detail::io_object_impl< + asio::detail::winrt_resolver_service<InternetProtocol>, + Executor> impl_; +# else + asio::detail::io_object_impl< + asio::detail::resolver_service<InternetProtocol>, + Executor> impl_; +# endif }; } // namespace ip @@ -1011,8 +1109,4 @@ public: #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_IP_BASIC_RESOLVER_HPP diff --git a/3rdparty/asio/include/asio/ip/basic_resolver_entry.hpp b/3rdparty/asio/include/asio/ip/basic_resolver_entry.hpp index ce689aa7480..a65af27af50 100644 --- a/3rdparty/asio/include/asio/ip/basic_resolver_entry.hpp +++ b/3rdparty/asio/include/asio/ip/basic_resolver_entry.hpp @@ -2,7 +2,7 @@ // ip/basic_resolver_entry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/basic_resolver_iterator.hpp b/3rdparty/asio/include/asio/ip/basic_resolver_iterator.hpp index 8cab75d1d63..b494f7ae02c 100644 --- a/3rdparty/asio/include/asio/ip/basic_resolver_iterator.hpp +++ b/3rdparty/asio/include/asio/ip/basic_resolver_iterator.hpp @@ -2,7 +2,7 @@ // ip/basic_resolver_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -79,15 +79,13 @@ public: { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. basic_resolver_iterator(basic_resolver_iterator&& other) - : values_(ASIO_MOVE_CAST(values_ptr_type)(other.values_)), + : values_(static_cast<values_ptr_type&&>(other.values_)), index_(other.index_) { other.index_ = 0; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Assignment operator. basic_resolver_iterator& operator=(const basic_resolver_iterator& other) @@ -97,20 +95,18 @@ public: return *this; } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-assignment operator. basic_resolver_iterator& operator=(basic_resolver_iterator&& other) { if (this != &other) { - values_ = ASIO_MOVE_CAST(values_ptr_type)(other.values_); + values_ = static_cast<values_ptr_type&&>(other.values_); index_ = other.index_; other.index_ = 0; } return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Dereference an iterator. const basic_resolver_entry<InternetProtocol>& operator*() const @@ -178,7 +174,7 @@ protected: return (*values_)[index_]; } - typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type; + typedef std::vector<basic_resolver_entry<InternetProtocol>> values_type; typedef asio::detail::shared_ptr<values_type> values_ptr_type; values_ptr_type values_; std::size_t index_; diff --git a/3rdparty/asio/include/asio/ip/basic_resolver_query.hpp b/3rdparty/asio/include/asio/ip/basic_resolver_query.hpp index 9bde9fea228..ada5a4f3802 100644 --- a/3rdparty/asio/include/asio/ip/basic_resolver_query.hpp +++ b/3rdparty/asio/include/asio/ip/basic_resolver_query.hpp @@ -2,7 +2,7 @@ // ip/basic_resolver_query.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -212,6 +212,22 @@ public: hints_.ai_next = 0; } + /// Copy construct a @c basic_resolver_query from another. + basic_resolver_query(const basic_resolver_query& other) + : hints_(other.hints_), + host_name_(other.host_name_), + service_name_(other.service_name_) + { + } + + /// Move construct a @c basic_resolver_query from another. + basic_resolver_query(basic_resolver_query&& other) + : hints_(other.hints_), + host_name_(static_cast<std::string&&>(other.host_name_)), + service_name_(static_cast<std::string&&>(other.service_name_)) + { + } + /// Get the hints associated with the query. const asio::detail::addrinfo_type& hints() const { diff --git a/3rdparty/asio/include/asio/ip/basic_resolver_results.hpp b/3rdparty/asio/include/asio/ip/basic_resolver_results.hpp index dec2c7e955a..7a461f13bc4 100644 --- a/3rdparty/asio/include/asio/ip/basic_resolver_results.hpp +++ b/3rdparty/asio/include/asio/ip/basic_resolver_results.hpp @@ -2,7 +2,7 @@ // ip/basic_resolver_results.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -62,7 +62,7 @@ public: typedef typename protocol_type::endpoint endpoint_type; /// The type of a value in the results range. - typedef basic_resolver_entry<endpoint_type> value_type; + typedef basic_resolver_entry<protocol_type> value_type; /// The type of a const reference to a value in the range. typedef const value_type& const_reference; @@ -93,14 +93,12 @@ public: { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. basic_resolver_results(basic_resolver_results&& other) : basic_resolver_iterator<InternetProtocol>( - ASIO_MOVE_CAST(basic_resolver_results)(other)) + static_cast<basic_resolver_results&&>(other)) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Assignment operator. basic_resolver_results& operator=(const basic_resolver_results& other) @@ -109,15 +107,13 @@ public: return *this; } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-assignment operator. basic_resolver_results& operator=(basic_resolver_results&& other) { basic_resolver_iterator<InternetProtocol>::operator=( - ASIO_MOVE_CAST(basic_resolver_results)(other)); + static_cast<basic_resolver_results&&>(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) #if !defined(GENERATING_DOCUMENTATION) // Create results from an addrinfo list returned by getaddrinfo. @@ -230,21 +226,21 @@ public: #endif // !defined(GENERATING_DOCUMENTATION) /// Get the number of entries in the results range. - size_type size() const ASIO_NOEXCEPT + size_type size() const noexcept { - return this->values_->size(); + return this->values_ ? this->values_->size() : 0; } /// Get the maximum number of entries permitted in a results range. - size_type max_size() const ASIO_NOEXCEPT + size_type max_size() const noexcept { - return this->values_->max_size(); + return this->values_ ? this->values_->max_size() : values_type().max_size(); } /// Determine whether the results range is empty. - bool empty() const ASIO_NOEXCEPT + bool empty() const noexcept { - return this->values_->empty(); + return this->values_ ? this->values_->empty() : true; } /// Obtain a begin iterator for the results range. @@ -252,7 +248,7 @@ public: { basic_resolver_results tmp(*this); tmp.index_ = 0; - return tmp; + return static_cast<basic_resolver_results&&>(tmp); } /// Obtain an end iterator for the results range. @@ -274,7 +270,7 @@ public: } /// Swap the results range with another. - void swap(basic_resolver_results& that) ASIO_NOEXCEPT + void swap(basic_resolver_results& that) noexcept { if (this != &that) { @@ -300,7 +296,7 @@ public: } private: - typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type; + typedef std::vector<basic_resolver_entry<InternetProtocol>> values_type; }; } // namespace ip diff --git a/3rdparty/asio/include/asio/ip/detail/endpoint.hpp b/3rdparty/asio/include/asio/ip/detail/endpoint.hpp index 82875a4440c..2c4e3cd43f3 100644 --- a/3rdparty/asio/include/asio/ip/detail/endpoint.hpp +++ b/3rdparty/asio/include/asio/ip/detail/endpoint.hpp @@ -2,7 +2,7 @@ // ip/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -33,42 +33,43 @@ class endpoint { public: // Default constructor. - ASIO_DECL endpoint(); + ASIO_DECL endpoint() noexcept; // Construct an endpoint using a family and port number. - ASIO_DECL endpoint(int family, unsigned short port_num); + ASIO_DECL endpoint(int family, + unsigned short port_num) noexcept; // Construct an endpoint using an address and port number. ASIO_DECL endpoint(const asio::ip::address& addr, - unsigned short port_num); + unsigned short port_num) noexcept; // Copy constructor. - endpoint(const endpoint& other) + endpoint(const endpoint& other) noexcept : data_(other.data_) { } // Assign from another endpoint. - endpoint& operator=(const endpoint& other) + endpoint& operator=(const endpoint& other) noexcept { data_ = other.data_; return *this; } // Get the underlying endpoint in the native type. - asio::detail::socket_addr_type* data() + asio::detail::socket_addr_type* data() noexcept { return &data_.base; } // Get the underlying endpoint in the native type. - const asio::detail::socket_addr_type* data() const + const asio::detail::socket_addr_type* data() const noexcept { return &data_.base; } // Get the underlying size of the endpoint in the native type. - std::size_t size() const + std::size_t size() const noexcept { if (is_v4()) return sizeof(asio::detail::sockaddr_in4_type); @@ -80,33 +81,34 @@ public: ASIO_DECL void resize(std::size_t new_size); // Get the capacity of the endpoint in the native type. - std::size_t capacity() const + std::size_t capacity() const noexcept { return sizeof(data_); } // Get the port associated with the endpoint. - ASIO_DECL unsigned short port() const; + ASIO_DECL unsigned short port() const noexcept; // Set the port associated with the endpoint. - ASIO_DECL void port(unsigned short port_num); + ASIO_DECL void port(unsigned short port_num) noexcept; // Get the IP address associated with the endpoint. - ASIO_DECL asio::ip::address address() const; + ASIO_DECL asio::ip::address address() const noexcept; // Set the IP address associated with the endpoint. - ASIO_DECL void address(const asio::ip::address& addr); + ASIO_DECL void address( + const asio::ip::address& addr) noexcept; // Compare two endpoints for equality. - ASIO_DECL friend bool operator==( - const endpoint& e1, const endpoint& e2); + ASIO_DECL friend bool operator==(const endpoint& e1, + const endpoint& e2) noexcept; // Compare endpoints for ordering. - ASIO_DECL friend bool operator<( - const endpoint& e1, const endpoint& e2); + ASIO_DECL friend bool operator<(const endpoint& e1, + const endpoint& e2) noexcept; // Determine whether the endpoint is IPv4. - bool is_v4() const + bool is_v4() const noexcept { return data_.base.sa_family == ASIO_OS_DEF(AF_INET); } diff --git a/3rdparty/asio/include/asio/ip/detail/impl/endpoint.ipp b/3rdparty/asio/include/asio/ip/detail/impl/endpoint.ipp index 2f76137ef61..ef61208e234 100644 --- a/3rdparty/asio/include/asio/ip/detail/impl/endpoint.ipp +++ b/3rdparty/asio/include/asio/ip/detail/impl/endpoint.ipp @@ -2,7 +2,7 @@ // ip/detail/impl/endpoint.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -31,7 +31,7 @@ namespace asio { namespace ip { namespace detail { -endpoint::endpoint() +endpoint::endpoint() noexcept : data_() { data_.v4.sin_family = ASIO_OS_DEF(AF_INET); @@ -39,7 +39,7 @@ endpoint::endpoint() data_.v4.sin_addr.s_addr = ASIO_OS_DEF(INADDR_ANY); } -endpoint::endpoint(int family, unsigned short port_num) +endpoint::endpoint(int family, unsigned short port_num) noexcept : data_() { using namespace std; // For memcpy. @@ -57,19 +57,19 @@ endpoint::endpoint(int family, unsigned short port_num) asio::detail::socket_ops::host_to_network_short(port_num); data_.v6.sin6_flowinfo = 0; data_.v6.sin6_addr.s6_addr[0] = 0; data_.v6.sin6_addr.s6_addr[1] = 0; - data_.v6.sin6_addr.s6_addr[2] = 0, data_.v6.sin6_addr.s6_addr[3] = 0; - data_.v6.sin6_addr.s6_addr[4] = 0, data_.v6.sin6_addr.s6_addr[5] = 0; - data_.v6.sin6_addr.s6_addr[6] = 0, data_.v6.sin6_addr.s6_addr[7] = 0; - data_.v6.sin6_addr.s6_addr[8] = 0, data_.v6.sin6_addr.s6_addr[9] = 0; - data_.v6.sin6_addr.s6_addr[10] = 0, data_.v6.sin6_addr.s6_addr[11] = 0; - data_.v6.sin6_addr.s6_addr[12] = 0, data_.v6.sin6_addr.s6_addr[13] = 0; - data_.v6.sin6_addr.s6_addr[14] = 0, data_.v6.sin6_addr.s6_addr[15] = 0; + data_.v6.sin6_addr.s6_addr[2] = 0; data_.v6.sin6_addr.s6_addr[3] = 0; + data_.v6.sin6_addr.s6_addr[4] = 0; data_.v6.sin6_addr.s6_addr[5] = 0; + data_.v6.sin6_addr.s6_addr[6] = 0; data_.v6.sin6_addr.s6_addr[7] = 0; + data_.v6.sin6_addr.s6_addr[8] = 0; data_.v6.sin6_addr.s6_addr[9] = 0; + data_.v6.sin6_addr.s6_addr[10] = 0; data_.v6.sin6_addr.s6_addr[11] = 0; + data_.v6.sin6_addr.s6_addr[12] = 0; data_.v6.sin6_addr.s6_addr[13] = 0; + data_.v6.sin6_addr.s6_addr[14] = 0; data_.v6.sin6_addr.s6_addr[15] = 0; data_.v6.sin6_scope_id = 0; } } endpoint::endpoint(const asio::ip::address& addr, - unsigned short port_num) + unsigned short port_num) noexcept : data_() { using namespace std; // For memcpy. @@ -106,7 +106,7 @@ void endpoint::resize(std::size_t new_size) } } -unsigned short endpoint::port() const +unsigned short endpoint::port() const noexcept { if (is_v4()) { @@ -120,7 +120,7 @@ unsigned short endpoint::port() const } } -void endpoint::port(unsigned short port_num) +void endpoint::port(unsigned short port_num) noexcept { if (is_v4()) { @@ -134,7 +134,7 @@ void endpoint::port(unsigned short port_num) } } -asio::ip::address endpoint::address() const +asio::ip::address endpoint::address() const noexcept { using namespace std; // For memcpy. if (is_v4()) @@ -146,27 +146,23 @@ asio::ip::address endpoint::address() const else { asio::ip::address_v6::bytes_type bytes; -#if defined(ASIO_HAS_STD_ARRAY) memcpy(bytes.data(), data_.v6.sin6_addr.s6_addr, 16); -#else // defined(ASIO_HAS_STD_ARRAY) - memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); -#endif // defined(ASIO_HAS_STD_ARRAY) return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); } } -void endpoint::address(const asio::ip::address& addr) +void endpoint::address(const asio::ip::address& addr) noexcept { endpoint tmp_endpoint(addr, port()); data_ = tmp_endpoint.data_; } -bool operator==(const endpoint& e1, const endpoint& e2) +bool operator==(const endpoint& e1, const endpoint& e2) noexcept { return e1.address() == e2.address() && e1.port() == e2.port(); } -bool operator<(const endpoint& e1, const endpoint& e2) +bool operator<(const endpoint& e1, const endpoint& e2) noexcept { if (e1.address() < e2.address()) return true; diff --git a/3rdparty/asio/include/asio/ip/detail/socket_option.hpp b/3rdparty/asio/include/asio/ip/detail/socket_option.hpp index d555a408965..c9883ae033e 100644 --- a/3rdparty/asio/include/asio/ip/detail/socket_option.hpp +++ b/3rdparty/asio/include/asio/ip/detail/socket_option.hpp @@ -2,7 +2,7 @@ // detail/socket_option.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/host_name.hpp b/3rdparty/asio/include/asio/ip/host_name.hpp index 6e556c62bd2..f9cb1852cae 100644 --- a/3rdparty/asio/include/asio/ip/host_name.hpp +++ b/3rdparty/asio/include/asio/ip/host_name.hpp @@ -2,7 +2,7 @@ // ip/host_name.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/icmp.hpp b/3rdparty/asio/include/asio/ip/icmp.hpp index 752a82c809c..9e4e8e4cb5b 100644 --- a/3rdparty/asio/include/asio/ip/icmp.hpp +++ b/3rdparty/asio/include/asio/ip/icmp.hpp @@ -2,7 +2,7 @@ // ip/icmp.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -46,33 +46,33 @@ public: typedef basic_endpoint<icmp> endpoint; /// Construct to represent the IPv4 ICMP protocol. - static icmp v4() + static icmp v4() noexcept { return icmp(ASIO_OS_DEF(IPPROTO_ICMP), ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 ICMP protocol. - static icmp v6() + static icmp v6() noexcept { return icmp(ASIO_OS_DEF(IPPROTO_ICMPV6), ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return ASIO_OS_DEF(SOCK_RAW); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return family_; } @@ -97,7 +97,7 @@ public: private: // Construct with a specific family. - explicit icmp(int protocol_id, int protocol_family) + explicit icmp(int protocol_id, int protocol_family) noexcept : protocol_(protocol_id), family_(protocol_family) { diff --git a/3rdparty/asio/include/asio/ip/impl/address.hpp b/3rdparty/asio/include/asio/ip/impl/address.hpp index c64fb023723..5780f320067 100644 --- a/3rdparty/asio/include/asio/ip/impl/address.hpp +++ b/3rdparty/asio/include/asio/ip/impl/address.hpp @@ -2,7 +2,7 @@ // ip/impl/address.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/impl/address.ipp b/3rdparty/asio/include/asio/ip/impl/address.ipp index c558d9a0a4f..9893b4ce9c2 100644 --- a/3rdparty/asio/include/asio/ip/impl/address.ipp +++ b/3rdparty/asio/include/asio/ip/impl/address.ipp @@ -2,7 +2,7 @@ // ip/impl/address.ipp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -29,44 +29,44 @@ namespace asio { namespace ip { -address::address() +address::address() noexcept : type_(ipv4), ipv4_address_(), ipv6_address_() { } -address::address(const asio::ip::address_v4& ipv4_address) +address::address( + const asio::ip::address_v4& ipv4_address) noexcept : type_(ipv4), ipv4_address_(ipv4_address), ipv6_address_() { } -address::address(const asio::ip::address_v6& ipv6_address) +address::address( + const asio::ip::address_v6& ipv6_address) noexcept : type_(ipv6), ipv4_address_(), ipv6_address_(ipv6_address) { } -address::address(const address& other) +address::address(const address& other) noexcept : type_(other.type_), ipv4_address_(other.ipv4_address_), ipv6_address_(other.ipv6_address_) { } -#if defined(ASIO_HAS_MOVE) -address::address(address&& other) +address::address(address&& other) noexcept : type_(other.type_), ipv4_address_(other.ipv4_address_), ipv6_address_(other.ipv6_address_) { } -#endif // defined(ASIO_HAS_MOVE) -address& address::operator=(const address& other) +address& address::operator=(const address& other) noexcept { type_ = other.type_; ipv4_address_ = other.ipv4_address_; @@ -74,17 +74,16 @@ address& address::operator=(const address& other) return *this; } -#if defined(ASIO_HAS_MOVE) -address& address::operator=(address&& other) +address& address::operator=(address&& other) noexcept { type_ = other.type_; ipv4_address_ = other.ipv4_address_; ipv6_address_ = other.ipv6_address_; return *this; } -#endif // defined(ASIO_HAS_MOVE) -address& address::operator=(const asio::ip::address_v4& ipv4_address) +address& address::operator=( + const asio::ip::address_v4& ipv4_address) noexcept { type_ = ipv4; ipv4_address_ = ipv4_address; @@ -92,7 +91,8 @@ address& address::operator=(const asio::ip::address_v4& ipv4_address) return *this; } -address& address::operator=(const asio::ip::address_v6& ipv6_address) +address& address::operator=( + const asio::ip::address_v6& ipv6_address) noexcept { type_ = ipv6; ipv4_address_ = asio::ip::address_v4(); @@ -108,7 +108,8 @@ address make_address(const char* str) return addr; } -address make_address(const char* str, asio::error_code& ec) +address make_address(const char* str, + asio::error_code& ec) noexcept { asio::ip::address_v6 ipv6_address = asio::ip::make_address_v6(str, ec); @@ -129,12 +130,12 @@ address make_address(const std::string& str) } address make_address(const std::string& str, - asio::error_code& ec) + asio::error_code& ec) noexcept { return make_address(str.c_str(), ec); } -#if defined(ASIO_HAS_STD_STRING_VIEW) +#if defined(ASIO_HAS_STRING_VIEW) address make_address(string_view str) { @@ -142,12 +143,12 @@ address make_address(string_view str) } address make_address(string_view str, - asio::error_code& ec) + asio::error_code& ec) noexcept { return make_address(static_cast<std::string>(str), ec); } -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) asio::ip::address_v4 address::to_v4() const { @@ -185,28 +186,28 @@ std::string address::to_string(asio::error_code& ec) const } #endif // !defined(ASIO_NO_DEPRECATED) -bool address::is_loopback() const +bool address::is_loopback() const noexcept { return (type_ == ipv4) ? ipv4_address_.is_loopback() : ipv6_address_.is_loopback(); } -bool address::is_unspecified() const +bool address::is_unspecified() const noexcept { return (type_ == ipv4) ? ipv4_address_.is_unspecified() : ipv6_address_.is_unspecified(); } -bool address::is_multicast() const +bool address::is_multicast() const noexcept { return (type_ == ipv4) ? ipv4_address_.is_multicast() : ipv6_address_.is_multicast(); } -bool operator==(const address& a1, const address& a2) +bool operator==(const address& a1, const address& a2) noexcept { if (a1.type_ != a2.type_) return false; @@ -215,7 +216,7 @@ bool operator==(const address& a1, const address& a2) return a1.ipv4_address_ == a2.ipv4_address_; } -bool operator<(const address& a1, const address& a2) +bool operator<(const address& a1, const address& a2) noexcept { if (a1.type_ < a2.type_) return true; diff --git a/3rdparty/asio/include/asio/ip/impl/address_v4.hpp b/3rdparty/asio/include/asio/ip/impl/address_v4.hpp index 1897fd2675f..5e29a249ba8 100644 --- a/3rdparty/asio/include/asio/ip/impl/address_v4.hpp +++ b/3rdparty/asio/include/asio/ip/impl/address_v4.hpp @@ -2,7 +2,7 @@ // ip/impl/address_v4.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/impl/address_v4.ipp b/3rdparty/asio/include/asio/ip/impl/address_v4.ipp index 09439eb16c2..d7803271ac9 100644 --- a/3rdparty/asio/include/asio/ip/impl/address_v4.ipp +++ b/3rdparty/asio/include/asio/ip/impl/address_v4.ipp @@ -2,7 +2,7 @@ // ip/impl/address_v4.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -57,19 +57,15 @@ address_v4::address_v4(address_v4::uint_type addr) static_cast<asio::detail::u_long_type>(addr)); } -address_v4::bytes_type address_v4::to_bytes() const +address_v4::bytes_type address_v4::to_bytes() const noexcept { using namespace std; // For memcpy. bytes_type bytes; -#if defined(ASIO_HAS_STD_ARRAY) memcpy(bytes.data(), &addr_.s_addr, 4); -#else // defined(ASIO_HAS_STD_ARRAY) - memcpy(bytes.elems, &addr_.s_addr, 4); -#endif // defined(ASIO_HAS_STD_ARRAY) return bytes; } -address_v4::uint_type address_v4::to_uint() const +address_v4::uint_type address_v4::to_uint() const noexcept { return asio::detail::socket_ops::network_to_host_long(addr_.s_addr); } @@ -108,12 +104,12 @@ std::string address_v4::to_string(asio::error_code& ec) const } #endif // !defined(ASIO_NO_DEPRECATED) -bool address_v4::is_loopback() const +bool address_v4::is_loopback() const noexcept { return (to_uint() & 0xFF000000) == 0x7F000000; } -bool address_v4::is_unspecified() const +bool address_v4::is_unspecified() const noexcept { return to_uint() == 0; } @@ -135,7 +131,7 @@ bool address_v4::is_class_c() const } #endif // !defined(ASIO_NO_DEPRECATED) -bool address_v4::is_multicast() const +bool address_v4::is_multicast() const noexcept { return (to_uint() & 0xF0000000) == 0xE0000000; } @@ -166,8 +162,8 @@ address_v4 make_address_v4(const char* str) return addr; } -address_v4 make_address_v4( - const char* str, asio::error_code& ec) +address_v4 make_address_v4(const char* str, + asio::error_code& ec) noexcept { address_v4::bytes_type bytes; if (asio::detail::socket_ops::inet_pton( @@ -181,13 +177,13 @@ address_v4 make_address_v4(const std::string& str) return make_address_v4(str.c_str()); } -address_v4 make_address_v4( - const std::string& str, asio::error_code& ec) +address_v4 make_address_v4(const std::string& str, + asio::error_code& ec) noexcept { return make_address_v4(str.c_str(), ec); } -#if defined(ASIO_HAS_STD_STRING_VIEW) +#if defined(ASIO_HAS_STRING_VIEW) address_v4 make_address_v4(string_view str) { @@ -195,12 +191,12 @@ address_v4 make_address_v4(string_view str) } address_v4 make_address_v4(string_view str, - asio::error_code& ec) + asio::error_code& ec) noexcept { return make_address_v4(static_cast<std::string>(str), ec); } -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) } // namespace ip } // namespace asio diff --git a/3rdparty/asio/include/asio/ip/impl/address_v6.hpp b/3rdparty/asio/include/asio/ip/impl/address_v6.hpp index 407d9c1802e..b4b53abe069 100644 --- a/3rdparty/asio/include/asio/ip/impl/address_v6.hpp +++ b/3rdparty/asio/include/asio/ip/impl/address_v6.hpp @@ -2,7 +2,7 @@ // ip/impl/address_v6.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/impl/address_v6.ipp b/3rdparty/asio/include/asio/ip/impl/address_v6.ipp index 79025aed7d4..8d5b7d1fd09 100644 --- a/3rdparty/asio/include/asio/ip/impl/address_v6.ipp +++ b/3rdparty/asio/include/asio/ip/impl/address_v6.ipp @@ -2,7 +2,7 @@ // ip/impl/address_v6.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -31,14 +31,14 @@ namespace asio { namespace ip { -address_v6::address_v6() +address_v6::address_v6() noexcept : addr_(), scope_id_(0) { } address_v6::address_v6(const address_v6::bytes_type& bytes, - unsigned long scope) + scope_id_type scope) : scope_id_(scope) { #if UCHAR_MAX > 0xFF @@ -56,45 +56,37 @@ address_v6::address_v6(const address_v6::bytes_type& bytes, memcpy(addr_.s6_addr, bytes.data(), 16); } -address_v6::address_v6(const address_v6& other) +address_v6::address_v6(const address_v6& other) noexcept : addr_(other.addr_), scope_id_(other.scope_id_) { } -#if defined(ASIO_HAS_MOVE) -address_v6::address_v6(address_v6&& other) +address_v6::address_v6(address_v6&& other) noexcept : addr_(other.addr_), scope_id_(other.scope_id_) { } -#endif // defined(ASIO_HAS_MOVE) -address_v6& address_v6::operator=(const address_v6& other) +address_v6& address_v6::operator=(const address_v6& other) noexcept { addr_ = other.addr_; scope_id_ = other.scope_id_; return *this; } -#if defined(ASIO_HAS_MOVE) -address_v6& address_v6::operator=(address_v6&& other) +address_v6& address_v6::operator=(address_v6&& other) noexcept { addr_ = other.addr_; scope_id_ = other.scope_id_; return *this; } -#endif // defined(ASIO_HAS_MOVE) -address_v6::bytes_type address_v6::to_bytes() const +address_v6::bytes_type address_v6::to_bytes() const noexcept { using namespace std; // For memcpy. bytes_type bytes; -#if defined(ASIO_HAS_STD_ARRAY) memcpy(bytes.data(), addr_.s6_addr, 16); -#else // defined(ASIO_HAS_STD_ARRAY) - memcpy(bytes.elems, addr_.s6_addr, 16); -#endif // defined(ASIO_HAS_STD_ARRAY) return bytes; } @@ -138,7 +130,7 @@ address_v4 address_v6::to_v4() const } #endif // !defined(ASIO_NO_DEPRECATED) -bool address_v6::is_loopback() const +bool address_v6::is_loopback() const noexcept { return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) @@ -150,7 +142,7 @@ bool address_v6::is_loopback() const && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); } -bool address_v6::is_unspecified() const +bool address_v6::is_unspecified() const noexcept { return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) @@ -162,17 +154,17 @@ bool address_v6::is_unspecified() const && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); } -bool address_v6::is_link_local() const +bool address_v6::is_link_local() const noexcept { return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0x80)); } -bool address_v6::is_site_local() const +bool address_v6::is_site_local() const noexcept { return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0xc0)); } -bool address_v6::is_v4_mapped() const +bool address_v6::is_v4_mapped() const noexcept { return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) @@ -198,37 +190,37 @@ bool address_v6::is_v4_compatible() const } #endif // !defined(ASIO_NO_DEPRECATED) -bool address_v6::is_multicast() const +bool address_v6::is_multicast() const noexcept { return (addr_.s6_addr[0] == 0xff); } -bool address_v6::is_multicast_global() const +bool address_v6::is_multicast_global() const noexcept { return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x0e)); } -bool address_v6::is_multicast_link_local() const +bool address_v6::is_multicast_link_local() const noexcept { return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x02)); } -bool address_v6::is_multicast_node_local() const +bool address_v6::is_multicast_node_local() const noexcept { return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x01)); } -bool address_v6::is_multicast_org_local() const +bool address_v6::is_multicast_org_local() const noexcept { return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x08)); } -bool address_v6::is_multicast_site_local() const +bool address_v6::is_multicast_site_local() const noexcept { return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x05)); } -bool operator==(const address_v6& a1, const address_v6& a2) +bool operator==(const address_v6& a1, const address_v6& a2) noexcept { using namespace std; // For memcmp. return memcmp(&a1.addr_, &a2.addr_, @@ -236,7 +228,7 @@ bool operator==(const address_v6& a1, const address_v6& a2) && a1.scope_id_ == a2.scope_id_; } -bool operator<(const address_v6& a1, const address_v6& a2) +bool operator<(const address_v6& a1, const address_v6& a2) noexcept { using namespace std; // For memcmp. int memcmp_result = memcmp(&a1.addr_, &a2.addr_, @@ -248,7 +240,7 @@ bool operator<(const address_v6& a1, const address_v6& a2) return a1.scope_id_ < a2.scope_id_; } -address_v6 address_v6::loopback() +address_v6 address_v6::loopback() noexcept { address_v6 tmp; tmp.addr_.s6_addr[15] = 1; @@ -281,8 +273,8 @@ address_v6 make_address_v6(const char* str) return addr; } -address_v6 make_address_v6( - const char* str, asio::error_code& ec) +address_v6 make_address_v6(const char* str, + asio::error_code& ec) noexcept { address_v6::bytes_type bytes; unsigned long scope_id = 0; @@ -297,13 +289,13 @@ address_v6 make_address_v6(const std::string& str) return make_address_v6(str.c_str()); } -address_v6 make_address_v6( - const std::string& str, asio::error_code& ec) +address_v6 make_address_v6(const std::string& str, + asio::error_code& ec) noexcept { return make_address_v6(str.c_str(), ec); } -#if defined(ASIO_HAS_STD_STRING_VIEW) +#if defined(ASIO_HAS_STRING_VIEW) address_v6 make_address_v6(string_view str) { @@ -311,12 +303,12 @@ address_v6 make_address_v6(string_view str) } address_v6 make_address_v6(string_view str, - asio::error_code& ec) + asio::error_code& ec) noexcept { return make_address_v6(static_cast<std::string>(str), ec); } -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) address_v4 make_address_v4( v4_mapped_t, const address_v6& v6_addr) diff --git a/3rdparty/asio/include/asio/ip/impl/basic_endpoint.hpp b/3rdparty/asio/include/asio/ip/impl/basic_endpoint.hpp index c1a29a8a4eb..2da96c16547 100644 --- a/3rdparty/asio/include/asio/ip/impl/basic_endpoint.hpp +++ b/3rdparty/asio/include/asio/ip/impl/basic_endpoint.hpp @@ -2,7 +2,7 @@ // ip/impl/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/impl/host_name.ipp b/3rdparty/asio/include/asio/ip/impl/host_name.ipp index a1f8a0d331f..eb27829fdab 100644 --- a/3rdparty/asio/include/asio/ip/impl/host_name.ipp +++ b/3rdparty/asio/include/asio/ip/impl/host_name.ipp @@ -2,7 +2,7 @@ // ip/impl/host_name.ipp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/impl/network_v4.hpp b/3rdparty/asio/include/asio/ip/impl/network_v4.hpp index 34c03fdd378..2199c7da8ca 100644 --- a/3rdparty/asio/include/asio/ip/impl/network_v4.hpp +++ b/3rdparty/asio/include/asio/ip/impl/network_v4.hpp @@ -2,7 +2,7 @@ // ip/impl/network_v4.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying diff --git a/3rdparty/asio/include/asio/ip/impl/network_v4.ipp b/3rdparty/asio/include/asio/ip/impl/network_v4.ipp index ec39aae1c04..e7e68ed443a 100644 --- a/3rdparty/asio/include/asio/ip/impl/network_v4.ipp +++ b/3rdparty/asio/include/asio/ip/impl/network_v4.ipp @@ -2,7 +2,7 @@ // ip/impl/network_v4.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -91,7 +91,7 @@ network_v4::network_v4(const address_v4& addr, const address_v4& mask) } } -address_v4 network_v4::netmask() const ASIO_NOEXCEPT +address_v4 network_v4::netmask() const noexcept { uint32_t nmbits = 0xffffffff; if (prefix_length_ == 0) @@ -101,7 +101,7 @@ address_v4 network_v4::netmask() const ASIO_NOEXCEPT return address_v4(nmbits); } -address_v4_range network_v4::hosts() const ASIO_NOEXCEPT +address_v4_range network_v4::hosts() const noexcept { return is_host() ? address_v4_range(address_, address_v4(address_.to_uint() + 1)) @@ -126,9 +126,12 @@ std::string network_v4::to_string() const std::string network_v4::to_string(asio::error_code& ec) const { + using namespace std; // For sprintf. ec = asio::error_code(); char prefix_len[16]; -#if defined(ASIO_HAS_SECURE_RTL) +#if defined(ASIO_HAS_SNPRINTF) + snprintf(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); +#elif defined(ASIO_HAS_SECURE_RTL) sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); #else // defined(ASIO_HAS_SECURE_RTL) sprintf(prefix_len, "/%u", prefix_length_); @@ -178,11 +181,21 @@ network_v4 make_network_v4(const std::string& str, return network_v4(); } - return network_v4(make_address_v4(str.substr(0, pos)), - std::atoi(str.substr(pos + 1).c_str())); + const address_v4 addr = make_address_v4(str.substr(0, pos), ec); + if (ec) + return network_v4(); + + const int prefix_len = std::atoi(str.substr(pos + 1).c_str()); + if (prefix_len < 0 || prefix_len > 32) + { + ec = asio::error::invalid_argument; + return network_v4(); + } + + return network_v4(addr, static_cast<unsigned short>(prefix_len)); } -#if defined(ASIO_HAS_STD_STRING_VIEW) +#if defined(ASIO_HAS_STRING_VIEW) network_v4 make_network_v4(string_view str) { @@ -195,7 +208,7 @@ network_v4 make_network_v4(string_view str, return make_network_v4(static_cast<std::string>(str), ec); } -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) } // namespace ip } // namespace asio diff --git a/3rdparty/asio/include/asio/ip/impl/network_v6.hpp b/3rdparty/asio/include/asio/ip/impl/network_v6.hpp index 03b9ed899eb..69c121813cb 100644 --- a/3rdparty/asio/include/asio/ip/impl/network_v6.hpp +++ b/3rdparty/asio/include/asio/ip/impl/network_v6.hpp @@ -2,7 +2,7 @@ // ip/impl/network_v6.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/impl/network_v6.ipp b/3rdparty/asio/include/asio/ip/impl/network_v6.ipp index c2418e3e955..d85cd647e06 100644 --- a/3rdparty/asio/include/asio/ip/impl/network_v6.ipp +++ b/3rdparty/asio/include/asio/ip/impl/network_v6.ipp @@ -2,7 +2,7 @@ // ip/impl/network_v6.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -42,7 +42,7 @@ network_v6::network_v6(const address_v6& addr, unsigned short prefix_len) } } -ASIO_DECL address_v6 network_v6::network() const ASIO_NOEXCEPT +ASIO_DECL address_v6 network_v6::network() const noexcept { address_v6::bytes_type bytes(address_.to_bytes()); for (std::size_t i = 0; i < 16; ++i) @@ -55,7 +55,7 @@ ASIO_DECL address_v6 network_v6::network() const ASIO_NOEXCEPT return address_v6(bytes, address_.scope_id()); } -address_v6_range network_v6::hosts() const ASIO_NOEXCEPT +address_v6_range network_v6::hosts() const noexcept { address_v6::bytes_type begin_bytes(address_.to_bytes()); address_v6::bytes_type end_bytes(address_.to_bytes()); @@ -95,9 +95,12 @@ std::string network_v6::to_string() const std::string network_v6::to_string(asio::error_code& ec) const { + using namespace std; // For sprintf. ec = asio::error_code(); char prefix_len[16]; -#if defined(ASIO_HAS_SECURE_RTL) +#if defined(ASIO_HAS_SNPRINTF) + snprintf(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); +#elif defined(ASIO_HAS_SECURE_RTL) sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); #else // defined(ASIO_HAS_SECURE_RTL) sprintf(prefix_len, "/%u", prefix_length_); @@ -147,11 +150,21 @@ network_v6 make_network_v6(const std::string& str, return network_v6(); } - return network_v6(make_address_v6(str.substr(0, pos)), - std::atoi(str.substr(pos + 1).c_str())); + const address_v6 addr = make_address_v6(str.substr(0, pos), ec); + if (ec) + return network_v6(); + + const int prefix_len = std::atoi(str.substr(pos + 1).c_str()); + if (prefix_len < 0 || prefix_len > 128) + { + ec = asio::error::invalid_argument; + return network_v6(); + } + + return network_v6(addr, static_cast<unsigned short>(prefix_len)); } -#if defined(ASIO_HAS_STD_STRING_VIEW) +#if defined(ASIO_HAS_STRING_VIEW) network_v6 make_network_v6(string_view str) { @@ -164,7 +177,7 @@ network_v6 make_network_v6(string_view str, return make_network_v6(static_cast<std::string>(str), ec); } -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) } // namespace ip } // namespace asio diff --git a/3rdparty/asio/include/asio/ip/multicast.hpp b/3rdparty/asio/include/asio/ip/multicast.hpp index 16fbf4cd7e8..363f5ed81d5 100644 --- a/3rdparty/asio/include/asio/ip/multicast.hpp +++ b/3rdparty/asio/include/asio/ip/multicast.hpp @@ -2,7 +2,7 @@ // ip/multicast.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -32,7 +32,7 @@ namespace multicast { * @par Examples * Setting the option to join a multicast group: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::address multicast_address = * asio::ip::address::from_string("225.0.0.1"); @@ -60,7 +60,7 @@ typedef asio::ip::detail::socket_option::multicast_request< * @par Examples * Setting the option to leave a multicast group: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::address multicast_address = * asio::ip::address::from_string("225.0.0.1"); @@ -88,7 +88,7 @@ typedef asio::ip::detail::socket_option::multicast_request< * @par Examples * Setting the option: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::address_v4 local_interface = * asio::ip::address_v4::from_string("1.2.3.4"); @@ -116,7 +116,7 @@ typedef asio::ip::detail::socket_option::network_interface< * @par Examples * Setting the option: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::multicast::hops option(4); * socket.set_option(option); @@ -125,7 +125,7 @@ typedef asio::ip::detail::socket_option::network_interface< * @par * Getting the current option value: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::multicast::hops option; * socket.get_option(option); @@ -153,7 +153,7 @@ typedef asio::ip::detail::socket_option::multicast_hops< * @par Examples * Setting the option: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::multicast::enable_loopback option(true); * socket.set_option(option); @@ -162,7 +162,7 @@ typedef asio::ip::detail::socket_option::multicast_hops< * @par * Getting the current option value: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::multicast::enable_loopback option; * socket.get_option(option); diff --git a/3rdparty/asio/include/asio/ip/network_v4.hpp b/3rdparty/asio/include/asio/ip/network_v4.hpp index 5980b8e510e..1c29ebec143 100644 --- a/3rdparty/asio/include/asio/ip/network_v4.hpp +++ b/3rdparty/asio/include/asio/ip/network_v4.hpp @@ -2,7 +2,7 @@ // ip/network_v4.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -40,7 +40,7 @@ class network_v4 { public: /// Default constructor. - network_v4() ASIO_NOEXCEPT + network_v4() noexcept : address_(), prefix_length_(0) { @@ -55,78 +55,74 @@ public: const address_v4& mask); /// Copy constructor. - network_v4(const network_v4& other) ASIO_NOEXCEPT + network_v4(const network_v4& other) noexcept : address_(other.address_), prefix_length_(other.prefix_length_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. - network_v4(network_v4&& other) ASIO_NOEXCEPT - : address_(ASIO_MOVE_CAST(address_v4)(other.address_)), + network_v4(network_v4&& other) noexcept + : address_(static_cast<address_v4&&>(other.address_)), prefix_length_(other.prefix_length_) { } -#endif // defined(ASIO_HAS_MOVE) /// Assign from another network. - network_v4& operator=(const network_v4& other) ASIO_NOEXCEPT + network_v4& operator=(const network_v4& other) noexcept { address_ = other.address_; prefix_length_ = other.prefix_length_; return *this; } -#if defined(ASIO_HAS_MOVE) /// Move-assign from another network. - network_v4& operator=(network_v4&& other) ASIO_NOEXCEPT + network_v4& operator=(network_v4&& other) noexcept { - address_ = ASIO_MOVE_CAST(address_v4)(other.address_); + address_ = static_cast<address_v4&&>(other.address_); prefix_length_ = other.prefix_length_; return *this; } -#endif // defined(ASIO_HAS_MOVE) /// Obtain the address object specified when the network object was created. - address_v4 address() const ASIO_NOEXCEPT + address_v4 address() const noexcept { return address_; } /// Obtain the prefix length that was specified when the network object was /// created. - unsigned short prefix_length() const ASIO_NOEXCEPT + unsigned short prefix_length() const noexcept { return prefix_length_; } /// Obtain the netmask that was specified when the network object was created. - ASIO_DECL address_v4 netmask() const ASIO_NOEXCEPT; + ASIO_DECL address_v4 netmask() const noexcept; /// Obtain an address object that represents the network address. - address_v4 network() const ASIO_NOEXCEPT + address_v4 network() const noexcept { return address_v4(address_.to_uint() & netmask().to_uint()); } /// Obtain an address object that represents the network's broadcast address. - address_v4 broadcast() const ASIO_NOEXCEPT + address_v4 broadcast() const noexcept { return address_v4(network().to_uint() | (netmask().to_uint() ^ 0xFFFFFFFF)); } /// Obtain an address range corresponding to the hosts in the network. - ASIO_DECL address_v4_range hosts() const ASIO_NOEXCEPT; + ASIO_DECL address_v4_range hosts() const noexcept; /// Obtain the true network address, omitting any host bits. - network_v4 canonical() const ASIO_NOEXCEPT + network_v4 canonical() const noexcept { - return network_v4(network(), netmask()); + return network_v4(network(), prefix_length()); } /// Test if network is a valid host address. - bool is_host() const ASIO_NOEXCEPT + bool is_host() const noexcept { return prefix_length_ == 32; } @@ -207,7 +203,7 @@ ASIO_DECL network_v4 make_network_v4(const std::string& str); ASIO_DECL network_v4 make_network_v4( const std::string& str, asio::error_code& ec); -#if defined(ASIO_HAS_STD_STRING_VIEW) \ +#if defined(ASIO_HAS_STRING_VIEW) \ || defined(GENERATING_DOCUMENTATION) /// Create an IPv4 network from a string containing IP address and prefix @@ -225,7 +221,7 @@ ASIO_DECL network_v4 make_network_v4(string_view str); ASIO_DECL network_v4 make_network_v4( string_view str, asio::error_code& ec); -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) // || defined(GENERATING_DOCUMENTATION) #if !defined(ASIO_NO_IOSTREAM) diff --git a/3rdparty/asio/include/asio/ip/network_v6.hpp b/3rdparty/asio/include/asio/ip/network_v6.hpp index 4e07dbbc71d..942ed9d2f29 100644 --- a/3rdparty/asio/include/asio/ip/network_v6.hpp +++ b/3rdparty/asio/include/asio/ip/network_v6.hpp @@ -2,7 +2,7 @@ // ip/network_v6.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -40,7 +40,7 @@ class network_v6 { public: /// Default constructor. - network_v6() ASIO_NOEXCEPT + network_v6() noexcept : address_(), prefix_length_(0) { @@ -51,66 +51,62 @@ public: unsigned short prefix_len); /// Copy constructor. - network_v6(const network_v6& other) ASIO_NOEXCEPT + network_v6(const network_v6& other) noexcept : address_(other.address_), prefix_length_(other.prefix_length_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. - network_v6(network_v6&& other) ASIO_NOEXCEPT - : address_(ASIO_MOVE_CAST(address_v6)(other.address_)), + network_v6(network_v6&& other) noexcept + : address_(static_cast<address_v6&&>(other.address_)), prefix_length_(other.prefix_length_) { } -#endif // defined(ASIO_HAS_MOVE) /// Assign from another network. - network_v6& operator=(const network_v6& other) ASIO_NOEXCEPT + network_v6& operator=(const network_v6& other) noexcept { address_ = other.address_; prefix_length_ = other.prefix_length_; return *this; } -#if defined(ASIO_HAS_MOVE) /// Move-assign from another network. - network_v6& operator=(network_v6&& other) ASIO_NOEXCEPT + network_v6& operator=(network_v6&& other) noexcept { - address_ = ASIO_MOVE_CAST(address_v6)(other.address_); + address_ = static_cast<address_v6&&>(other.address_); prefix_length_ = other.prefix_length_; return *this; } -#endif // defined(ASIO_HAS_MOVE) /// Obtain the address object specified when the network object was created. - address_v6 address() const ASIO_NOEXCEPT + address_v6 address() const noexcept { return address_; } /// Obtain the prefix length that was specified when the network object was /// created. - unsigned short prefix_length() const ASIO_NOEXCEPT + unsigned short prefix_length() const noexcept { return prefix_length_; } /// Obtain an address object that represents the network address. - ASIO_DECL address_v6 network() const ASIO_NOEXCEPT; + ASIO_DECL address_v6 network() const noexcept; /// Obtain an address range corresponding to the hosts in the network. - ASIO_DECL address_v6_range hosts() const ASIO_NOEXCEPT; + ASIO_DECL address_v6_range hosts() const noexcept; /// Obtain the true network address, omitting any host bits. - network_v6 canonical() const ASIO_NOEXCEPT + network_v6 canonical() const noexcept { return network_v6(network(), prefix_length()); } /// Test if network is a valid host address. - bool is_host() const ASIO_NOEXCEPT + bool is_host() const noexcept { return prefix_length_ == 128; } @@ -181,7 +177,7 @@ ASIO_DECL network_v6 make_network_v6(const std::string& str); ASIO_DECL network_v6 make_network_v6( const std::string& str, asio::error_code& ec); -#if defined(ASIO_HAS_STD_STRING_VIEW) \ +#if defined(ASIO_HAS_STRING_VIEW) \ || defined(GENERATING_DOCUMENTATION) /// Create an IPv6 network from a string containing IP address and prefix @@ -199,7 +195,7 @@ ASIO_DECL network_v6 make_network_v6(string_view str); ASIO_DECL network_v6 make_network_v6( string_view str, asio::error_code& ec); -#endif // defined(ASIO_HAS_STD_STRING_VIEW) +#endif // defined(ASIO_HAS_STRING_VIEW) // || defined(GENERATING_DOCUMENTATION) #if !defined(ASIO_NO_IOSTREAM) diff --git a/3rdparty/asio/include/asio/ip/resolver_base.hpp b/3rdparty/asio/include/asio/ip/resolver_base.hpp index a8a94d5a2cc..9fa01ca9107 100644 --- a/3rdparty/asio/include/asio/ip/resolver_base.hpp +++ b/3rdparty/asio/include/asio/ip/resolver_base.hpp @@ -2,7 +2,7 @@ // ip/resolver_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/resolver_query_base.hpp b/3rdparty/asio/include/asio/ip/resolver_query_base.hpp index 297c9c93f2c..892bc28e006 100644 --- a/3rdparty/asio/include/asio/ip/resolver_query_base.hpp +++ b/3rdparty/asio/include/asio/ip/resolver_query_base.hpp @@ -2,7 +2,7 @@ // ip/resolver_query_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ip/resolver_service.hpp b/3rdparty/asio/include/asio/ip/resolver_service.hpp deleted file mode 100644 index 18e2dc193dc..00000000000 --- a/3rdparty/asio/include/asio/ip/resolver_service.hpp +++ /dev/null @@ -1,200 +0,0 @@ -// -// ip/resolver_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_IP_RESOLVER_SERVICE_HPP -#define ASIO_IP_RESOLVER_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include "asio/async_result.hpp" -#include "asio/error_code.hpp" -#include "asio/io_context.hpp" -#include "asio/ip/basic_resolver_iterator.hpp" -#include "asio/ip/basic_resolver_query.hpp" -#include "asio/ip/basic_resolver_results.hpp" - -#if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/winrt_resolver_service.hpp" -#else -# include "asio/detail/resolver_service.hpp" -#endif - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace ip { - -/// Default service implementation for a resolver. -template <typename InternetProtocol> -class resolver_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base< - resolver_service<InternetProtocol> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The protocol type. - typedef InternetProtocol protocol_type; - - /// The endpoint type. - typedef typename InternetProtocol::endpoint endpoint_type; - - /// The query type. - typedef basic_resolver_query<InternetProtocol> query_type; - - /// The iterator type. - typedef basic_resolver_iterator<InternetProtocol> iterator_type; - - /// The results type. - typedef basic_resolver_results<InternetProtocol> results_type; - -private: - // The type of the platform-specific implementation. -#if defined(ASIO_WINDOWS_RUNTIME) - typedef asio::detail::winrt_resolver_service<InternetProtocol> - service_impl_type; -#else - typedef asio::detail::resolver_service<InternetProtocol> - service_impl_type; -#endif - -public: - /// The type of a resolver implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// Construct a new resolver service for the specified io_context. - explicit resolver_service(asio::io_context& io_context) - : asio::detail::service_base< - resolver_service<InternetProtocol> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new resolver implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new resolver implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another resolver implementation. - void move_assign(implementation_type& impl, - resolver_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a resolver implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Cancel pending asynchronous operations. - void cancel(implementation_type& impl) - { - service_impl_.cancel(impl); - } - - /// Resolve a query to a list of entries. - results_type resolve(implementation_type& impl, const query_type& query, - asio::error_code& ec) - { - return service_impl_.resolve(impl, query, ec); - } - - /// Asynchronously resolve a query to a list of entries. - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(implementation_type& impl, const query_type& query, - ASIO_MOVE_ARG(ResolveHandler) handler) - { - asio::async_completion<ResolveHandler, - void (asio::error_code, results_type)> init(handler); - - service_impl_.async_resolve(impl, query, init.completion_handler); - - return init.result.get(); - } - - /// Resolve an endpoint to a list of entries. - results_type resolve(implementation_type& impl, - const endpoint_type& endpoint, asio::error_code& ec) - { - return service_impl_.resolve(impl, endpoint, ec); - } - - /// Asynchronously resolve an endpoint to a list of entries. - template <typename ResolveHandler> - ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (asio::error_code, results_type)) - async_resolve(implementation_type& impl, const endpoint_type& endpoint, - ASIO_MOVE_ARG(ResolveHandler) handler) - { - asio::async_completion<ResolveHandler, - void (asio::error_code, results_type)> init(handler); - - service_impl_.async_resolve(impl, endpoint, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // Perform any fork-related housekeeping. - void notify_fork(asio::io_context::fork_event event) - { - service_impl_.notify_fork(event); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace ip -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_IP_RESOLVER_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/ip/tcp.hpp b/3rdparty/asio/include/asio/ip/tcp.hpp index 40e5470ad0f..b8319609ddb 100644 --- a/3rdparty/asio/include/asio/ip/tcp.hpp +++ b/3rdparty/asio/include/asio/ip/tcp.hpp @@ -2,7 +2,7 @@ // ip/tcp.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -49,31 +49,31 @@ public: typedef basic_endpoint<tcp> endpoint; /// Construct to represent the IPv4 TCP protocol. - static tcp v4() + static tcp v4() noexcept { return tcp(ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 TCP protocol. - static tcp v6() + static tcp v6() noexcept { return tcp(ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return ASIO_OS_DEF(SOCK_STREAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return ASIO_OS_DEF(IPPROTO_TCP); } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return family_; } @@ -99,7 +99,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::no_delay option(true); * socket.set_option(option); @@ -108,7 +108,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::no_delay option; * socket.get_option(option); @@ -139,7 +139,7 @@ public: private: // Construct with a specific family. - explicit tcp(int protocol_family) + explicit tcp(int protocol_family) noexcept : family_(protocol_family) { } diff --git a/3rdparty/asio/include/asio/ip/udp.hpp b/3rdparty/asio/include/asio/ip/udp.hpp index a011accaff2..50c667a5371 100644 --- a/3rdparty/asio/include/asio/ip/udp.hpp +++ b/3rdparty/asio/include/asio/ip/udp.hpp @@ -2,7 +2,7 @@ // ip/udp.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -46,31 +46,31 @@ public: typedef basic_endpoint<udp> endpoint; /// Construct to represent the IPv4 UDP protocol. - static udp v4() + static udp v4() noexcept { return udp(ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 UDP protocol. - static udp v6() + static udp v6() noexcept { return udp(ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return ASIO_OS_DEF(SOCK_DGRAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return ASIO_OS_DEF(IPPROTO_UDP); } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return family_; } @@ -95,7 +95,7 @@ public: private: // Construct with a specific family. - explicit udp(int protocol_family) + explicit udp(int protocol_family) noexcept : family_(protocol_family) { } diff --git a/3rdparty/asio/include/asio/ip/unicast.hpp b/3rdparty/asio/include/asio/ip/unicast.hpp index 8b768c2336f..4d68af877bc 100644 --- a/3rdparty/asio/include/asio/ip/unicast.hpp +++ b/3rdparty/asio/include/asio/ip/unicast.hpp @@ -2,7 +2,7 @@ // ip/unicast.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -32,7 +32,7 @@ namespace unicast { * @par Examples * Setting the option: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::unicast::hops option(4); * socket.set_option(option); @@ -41,7 +41,7 @@ namespace unicast { * @par * Getting the current option value: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::ip::unicast::hops option; * socket.get_option(option); diff --git a/3rdparty/asio/include/asio/ip/v6_only.hpp b/3rdparty/asio/include/asio/ip/v6_only.hpp index 9106b25b6cd..0fc61213bda 100644 --- a/3rdparty/asio/include/asio/ip/v6_only.hpp +++ b/3rdparty/asio/include/asio/ip/v6_only.hpp @@ -2,7 +2,7 @@ // ip/v6_only.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -26,12 +26,12 @@ namespace ip { /// Socket option for determining whether an IPv6 socket supports IPv6 /// communication only. /** - * Implements the IPPROTO_IPV6/IP_V6ONLY socket option. + * Implements the IPPROTO_IPV6/IPV6_V6ONLY socket option. * * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::v6_only option(true); * socket.set_option(option); @@ -40,7 +40,7 @@ namespace ip { * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::v6_only option; * socket.get_option(option); diff --git a/3rdparty/asio/include/asio/is_applicable_property.hpp b/3rdparty/asio/include/asio/is_applicable_property.hpp new file mode 100644 index 00000000000..20ca981ad02 --- /dev/null +++ b/3rdparty/asio/include/asio/is_applicable_property.hpp @@ -0,0 +1,61 @@ +// +// is_applicable_property.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IS_APPLICABLE_PROPERTY_HPP +#define ASIO_IS_APPLICABLE_PROPERTY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +namespace asio { +namespace detail { + +template <typename T, typename Property, typename = void> +struct is_applicable_property_trait : false_type +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +struct is_applicable_property_trait<T, Property, + void_t< + enable_if_t< + !!Property::template is_applicable_property_v<T> + > + >> : true_type +{ +}; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +} // namespace detail + +template <typename T, typename Property, typename = void> +struct is_applicable_property : + detail::is_applicable_property_trait<T, Property> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +constexpr const bool is_applicable_property_v + = is_applicable_property<T, Property>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +} // namespace asio + +#endif // ASIO_IS_APPLICABLE_PROPERTY_HPP diff --git a/3rdparty/asio/include/asio/is_contiguous_iterator.hpp b/3rdparty/asio/include/asio/is_contiguous_iterator.hpp new file mode 100644 index 00000000000..a120d4d3761 --- /dev/null +++ b/3rdparty/asio/include/asio/is_contiguous_iterator.hpp @@ -0,0 +1,45 @@ +// +// is_contiguous_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_IS_CONTIGUOUS_ITERATOR_HPP +#define ASIO_IS_CONTIGUOUS_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <iterator> +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// The is_contiguous_iterator class is a traits class that may be used to +/// determine whether a type is a contiguous iterator. +template <typename T> +struct is_contiguous_iterator : +#if defined(ASIO_HAS_STD_CONCEPTS) \ + || defined(GENERATING_DOCUMENTATION) + integral_constant<bool, std::contiguous_iterator<T>> +#else // defined(ASIO_HAS_STD_CONCEPTS) + // || defined(GENERATING_DOCUMENTATION) + is_pointer<T> +#endif // defined(ASIO_HAS_STD_CONCEPTS) + // || defined(GENERATING_DOCUMENTATION) +{ +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IS_CONTIGUOUS_ITERATOR_HPP diff --git a/3rdparty/asio/include/asio/is_executor.hpp b/3rdparty/asio/include/asio/is_executor.hpp index d5abf7b70c4..2c933a3949c 100644 --- a/3rdparty/asio/include/asio/is_executor.hpp +++ b/3rdparty/asio/include/asio/is_executor.hpp @@ -2,7 +2,7 @@ // is_executor.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/is_read_buffered.hpp b/3rdparty/asio/include/asio/is_read_buffered.hpp index 10483b17b79..768f70fb7e1 100644 --- a/3rdparty/asio/include/asio/is_read_buffered.hpp +++ b/3rdparty/asio/include/asio/is_read_buffered.hpp @@ -2,7 +2,7 @@ // is_read_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/is_write_buffered.hpp b/3rdparty/asio/include/asio/is_write_buffered.hpp index b0efbbb6841..1818fd4b2d5 100644 --- a/3rdparty/asio/include/asio/is_write_buffered.hpp +++ b/3rdparty/asio/include/asio/is_write_buffered.hpp @@ -2,7 +2,7 @@ // is_write_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/local/basic_endpoint.hpp b/3rdparty/asio/include/asio/local/basic_endpoint.hpp index ae30100728a..d363f352531 100644 --- a/3rdparty/asio/include/asio/local/basic_endpoint.hpp +++ b/3rdparty/asio/include/asio/local/basic_endpoint.hpp @@ -2,7 +2,7 @@ // local/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -60,7 +60,7 @@ public: #endif /// Default constructor. - basic_endpoint() + basic_endpoint() noexcept { } @@ -76,19 +76,25 @@ public: { } + #if defined(ASIO_HAS_STRING_VIEW) + /// Construct an endpoint using the specified path name. + basic_endpoint(string_view path_name) + : impl_(path_name) + { + } + #endif // defined(ASIO_HAS_STRING_VIEW) + /// Copy constructor. basic_endpoint(const basic_endpoint& other) : impl_(other.impl_) { } -#if defined(ASIO_HAS_MOVE) /// Move constructor. basic_endpoint(basic_endpoint&& other) : impl_(other.impl_) { } -#endif // defined(ASIO_HAS_MOVE) /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) @@ -97,14 +103,12 @@ public: return *this; } -#if defined(ASIO_HAS_MOVE) /// Move-assign from another endpoint. basic_endpoint& operator=(basic_endpoint&& other) { impl_ = other.impl_; return *this; } -#endif // defined(ASIO_HAS_MOVE) /// The protocol associated with the endpoint. protocol_type protocol() const diff --git a/3rdparty/asio/include/asio/local/connect_pair.hpp b/3rdparty/asio/include/asio/local/connect_pair.hpp index 3542d9b05ae..b8608e40de5 100644 --- a/3rdparty/asio/include/asio/local/connect_pair.hpp +++ b/3rdparty/asio/include/asio/local/connect_pair.hpp @@ -2,7 +2,7 @@ // local/connect_pair.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -32,33 +32,28 @@ namespace asio { namespace local { /// Create a pair of connected sockets. -template <typename Protocol ASIO_SVC_TPARAM ASIO_SVC_TPARAM1> -void connect_pair( - basic_socket<Protocol ASIO_SVC_TARG>& socket1, - basic_socket<Protocol ASIO_SVC_TARG1>& socket2); +template <typename Protocol, typename Executor1, typename Executor2> +void connect_pair(basic_socket<Protocol, Executor1>& socket1, + basic_socket<Protocol, Executor2>& socket2); /// Create a pair of connected sockets. -template <typename Protocol ASIO_SVC_TPARAM ASIO_SVC_TPARAM1> -ASIO_SYNC_OP_VOID connect_pair( - basic_socket<Protocol ASIO_SVC_TARG>& socket1, - basic_socket<Protocol ASIO_SVC_TARG1>& socket2, - asio::error_code& ec); - -template <typename Protocol ASIO_SVC_TPARAM ASIO_SVC_TPARAM1> -inline void connect_pair( - basic_socket<Protocol ASIO_SVC_TARG>& socket1, - basic_socket<Protocol ASIO_SVC_TARG1>& socket2) +template <typename Protocol, typename Executor1, typename Executor2> +ASIO_SYNC_OP_VOID connect_pair(basic_socket<Protocol, Executor1>& socket1, + basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec); + +template <typename Protocol, typename Executor1, typename Executor2> +inline void connect_pair(basic_socket<Protocol, Executor1>& socket1, + basic_socket<Protocol, Executor2>& socket2) { asio::error_code ec; connect_pair(socket1, socket2, ec); asio::detail::throw_error(ec, "connect_pair"); } -template <typename Protocol ASIO_SVC_TPARAM ASIO_SVC_TPARAM1> +template <typename Protocol, typename Executor1, typename Executor2> inline ASIO_SYNC_OP_VOID connect_pair( - basic_socket<Protocol ASIO_SVC_TARG>& socket1, - basic_socket<Protocol ASIO_SVC_TARG1>& socket2, - asio::error_code& ec) + basic_socket<Protocol, Executor1>& socket1, + basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec) { // Check that this function is only being used with a UNIX domain socket. asio::local::basic_endpoint<Protocol>* tmp diff --git a/3rdparty/asio/include/asio/local/datagram_protocol.hpp b/3rdparty/asio/include/asio/local/datagram_protocol.hpp index 17773d77aae..6bf18a46e49 100644 --- a/3rdparty/asio/include/asio/local/datagram_protocol.hpp +++ b/3rdparty/asio/include/asio/local/datagram_protocol.hpp @@ -2,7 +2,7 @@ // local/datagram_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -45,19 +45,19 @@ class datagram_protocol { public: /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return SOCK_DGRAM; } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return 0; } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return AF_UNIX; } diff --git a/3rdparty/asio/include/asio/local/detail/endpoint.hpp b/3rdparty/asio/include/asio/local/detail/endpoint.hpp index 6125e972571..5e94c3d0aeb 100644 --- a/3rdparty/asio/include/asio/local/detail/endpoint.hpp +++ b/3rdparty/asio/include/asio/local/detail/endpoint.hpp @@ -2,7 +2,7 @@ // local/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -23,6 +23,7 @@ #include <cstddef> #include <string> #include "asio/detail/socket_types.hpp" +#include "asio/detail/string_view.hpp" #include "asio/detail/push_options.hpp" @@ -43,6 +44,11 @@ public: // Construct an endpoint using the specified path name. ASIO_DECL endpoint(const std::string& path_name); + #if defined(ASIO_HAS_STRING_VIEW) + // Construct an endpoint using the specified path name. + ASIO_DECL endpoint(string_view path_name); + #endif // defined(ASIO_HAS_STRING_VIEW) + // Copy constructor. endpoint(const endpoint& other) : data_(other.data_), diff --git a/3rdparty/asio/include/asio/local/detail/impl/endpoint.ipp b/3rdparty/asio/include/asio/local/detail/impl/endpoint.ipp index adda630f81e..55b403e8ed6 100644 --- a/3rdparty/asio/include/asio/local/detail/impl/endpoint.ipp +++ b/3rdparty/asio/include/asio/local/detail/impl/endpoint.ipp @@ -2,7 +2,7 @@ // local/detail/impl/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -48,6 +48,13 @@ endpoint::endpoint(const std::string& path_name) init(path_name.data(), path_name.length()); } +#if defined(ASIO_HAS_STRING_VIEW) +endpoint::endpoint(string_view path_name) +{ + init(path_name.data(), path_name.length()); +} +#endif // defined(ASIO_HAS_STRING_VIEW) + void endpoint::resize(std::size_t new_size) { if (new_size > sizeof(asio::detail::sockaddr_un_type)) @@ -105,16 +112,12 @@ void endpoint::init(const char* path_name, std::size_t path_length) asio::detail::throw_error(ec); } - using namespace std; // For memcpy. - data_.local = asio::detail::sockaddr_un_type(); + using namespace std; // For memset and memcpy. + memset(&data_.local, 0, sizeof(asio::detail::sockaddr_un_type)); data_.local.sun_family = AF_UNIX; - memcpy(data_.local.sun_path, path_name, path_length); + if (path_length > 0) + memcpy(data_.local.sun_path, path_name, path_length); path_length_ = path_length; - - // NUL-terminate normal path names. Names that start with a NUL are in the - // UNIX domain protocol's "abstract namespace" and are not NUL-terminated. - if (path_length > 0 && data_.local.sun_path[0] == 0) - data_.local.sun_path[path_length] = 0; } } // namespace detail diff --git a/3rdparty/asio/include/asio/local/seq_packet_protocol.hpp b/3rdparty/asio/include/asio/local/seq_packet_protocol.hpp new file mode 100644 index 00000000000..c5a231fe859 --- /dev/null +++ b/3rdparty/asio/include/asio/local/seq_packet_protocol.hpp @@ -0,0 +1,84 @@ +// +// local/seq_packet_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_LOCAL_SEQ_PACKET_PROTOCOL_HPP +#define ASIO_LOCAL_SEQ_PACKET_PROTOCOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) + +#include "asio/basic_socket_acceptor.hpp" +#include "asio/basic_seq_packet_socket.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/local/basic_endpoint.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace local { + +/// Encapsulates the flags needed for seq_packet UNIX sockets. +/** + * The asio::local::seq_packet_protocol class contains flags necessary + * for sequenced packet UNIX domain sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol. + */ +class seq_packet_protocol +{ +public: + /// Obtain an identifier for the type of the protocol. + int type() const noexcept + { + return SOCK_SEQPACKET; + } + + /// Obtain an identifier for the protocol. + int protocol() const noexcept + { + return 0; + } + + /// Obtain an identifier for the protocol family. + int family() const noexcept + { + return AF_UNIX; + } + + /// The type of a UNIX domain endpoint. + typedef basic_endpoint<seq_packet_protocol> endpoint; + + /// The UNIX domain socket type. + typedef basic_seq_packet_socket<seq_packet_protocol> socket; + + /// The UNIX domain acceptor type. + typedef basic_socket_acceptor<seq_packet_protocol> acceptor; +}; + +} // namespace local +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_LOCAL_SOCKETS) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_LOCAL_SEQ_PACKET_PROTOCOL_HPP diff --git a/3rdparty/asio/include/asio/local/stream_protocol.hpp b/3rdparty/asio/include/asio/local/stream_protocol.hpp index e8094ccb9a1..4cbad450fc5 100644 --- a/3rdparty/asio/include/asio/local/stream_protocol.hpp +++ b/3rdparty/asio/include/asio/local/stream_protocol.hpp @@ -2,7 +2,7 @@ // local/stream_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -47,19 +47,19 @@ class stream_protocol { public: /// Obtain an identifier for the type of the protocol. - int type() const + int type() const noexcept { return SOCK_STREAM; } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const noexcept { return 0; } /// Obtain an identifier for the protocol family. - int family() const + int family() const noexcept { return AF_UNIX; } diff --git a/3rdparty/asio/include/asio/multiple_exceptions.hpp b/3rdparty/asio/include/asio/multiple_exceptions.hpp new file mode 100644 index 00000000000..2fd0455a91a --- /dev/null +++ b/3rdparty/asio/include/asio/multiple_exceptions.hpp @@ -0,0 +1,52 @@ +// +// multiple_exceptions.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_MULTIPLE_EXCEPTIONS_HPP +#define ASIO_MULTIPLE_EXCEPTIONS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <exception> +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Exception thrown when there are multiple pending exceptions to rethrow. +class multiple_exceptions + : public std::exception +{ +public: + /// Constructor. + ASIO_DECL multiple_exceptions( + std::exception_ptr first) noexcept; + + /// Obtain message associated with exception. + ASIO_DECL virtual const char* what() const + noexcept; + + /// Obtain a pointer to the first exception. + ASIO_DECL std::exception_ptr first_exception() const; + +private: + std::exception_ptr first_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/multiple_exceptions.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_MULTIPLE_EXCEPTIONS_HPP diff --git a/3rdparty/asio/include/asio/packaged_task.hpp b/3rdparty/asio/include/asio/packaged_task.hpp index af8d6896642..68e5b9b175a 100644 --- a/3rdparty/asio/include/asio/packaged_task.hpp +++ b/3rdparty/asio/include/asio/packaged_task.hpp @@ -2,7 +2,7 @@ // packaged_task.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,22 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/future.hpp" -#if defined(ASIO_HAS_STD_FUTURE) \ +#if defined(ASIO_HAS_STD_FUTURE_CLASS) \ || defined(GENERATING_DOCUMENTATION) -#include <future> #include "asio/async_result.hpp" #include "asio/detail/type_traits.hpp" -#include "asio/detail/variadic_templates.hpp" #include "asio/detail/push_options.hpp" namespace asio { -#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \ - || defined(GENERATING_DOCUMENTATION) - /// Partial specialisation of @c async_result for @c std::packaged_task. template <typename Result, typename... Args, typename Signature> class async_result<std::packaged_task<Result(Args...)>, Signature> @@ -60,67 +56,11 @@ private: return_type future_; }; -#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) - // || defined(GENERATING_DOCUMENTATION) - -template <typename Result, typename Signature> -struct async_result<std::packaged_task<Result()>, Signature> -{ - typedef std::packaged_task<Result()> completion_handler_type; - typedef std::future<Result> return_type; - - explicit async_result(completion_handler_type& h) - : future_(h.get_future()) - { - } - - return_type get() - { - return std::move(future_); - } - -private: - return_type future_; -}; - -#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ - template <typename Result, \ - ASIO_VARIADIC_TPARAMS(n), typename Signature> \ - class async_result< \ - std::packaged_task<Result(ASIO_VARIADIC_TARGS(n))>, Signature> \ - { \ - public: \ - typedef std::packaged_task< \ - Result(ASIO_VARIADIC_TARGS(n))> \ - completion_handler_type; \ - \ - typedef std::future<Result> return_type; \ - \ - explicit async_result(completion_handler_type& h) \ - : future_(h.get_future()) \ - { \ - } \ - \ - return_type get() \ - { \ - return std::move(future_); \ - } \ - \ - private: \ - return_type future_; \ - }; \ - /**/ - ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF) -#undef ASIO_PRIVATE_ASYNC_RESULT_DEF - -#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) - // || defined(GENERATING_DOCUMENTATION) - } // namespace asio #include "asio/detail/pop_options.hpp" -#endif // defined(ASIO_HAS_STD_FUTURE) +#endif // defined(ASIO_HAS_STD_FUTURE_CLASS) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_PACKAGED_TASK_HPP diff --git a/3rdparty/asio/include/asio/placeholders.hpp b/3rdparty/asio/include/asio/placeholders.hpp index 8e6e2e5c6c2..21da545fe9e 100644 --- a/3rdparty/asio/include/asio/placeholders.hpp +++ b/3rdparty/asio/include/asio/placeholders.hpp @@ -2,7 +2,7 @@ // placeholders.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,10 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_BOOST_BIND) -# include <boost/bind/arg.hpp> -#endif // defined(ASIO_HAS_BOOST_BIND) +#include "asio/detail/functional.hpp" #include "asio/detail/push_options.hpp" @@ -28,119 +25,46 @@ namespace placeholders { #if defined(GENERATING_DOCUMENTATION) -/// An argument placeholder, for use with boost::bind(), that corresponds to -/// the error argument of a handler for any of the asynchronous functions. +/// An argument placeholder, for use with std::bind() or boost::bind(), that +/// corresponds to the error argument of a handler for any of the asynchronous +/// functions. unspecified error; -/// An argument placeholder, for use with boost::bind(), that corresponds to -/// the bytes_transferred argument of a handler for asynchronous functions such -/// as asio::basic_stream_socket::async_write_some or +/// An argument placeholder, for use with std::bind() or boost::bind(), that +/// corresponds to the bytes_transferred argument of a handler for asynchronous +/// functions such as asio::basic_stream_socket::async_write_some or /// asio::async_write. unspecified bytes_transferred; -/// An argument placeholder, for use with boost::bind(), that corresponds to -/// the iterator argument of a handler for asynchronous functions such as -/// asio::async_connect. +/// An argument placeholder, for use with std::bind() or boost::bind(), that +/// corresponds to the iterator argument of a handler for asynchronous functions +/// such as asio::async_connect. unspecified iterator; -/// An argument placeholder, for use with boost::bind(), that corresponds to -/// the results argument of a handler for asynchronous functions such as -/// asio::basic_resolver::async_resolve. +/// An argument placeholder, for use with std::bind() or boost::bind(), that +/// corresponds to the results argument of a handler for asynchronous functions +/// such as asio::basic_resolver::async_resolve. unspecified results; -/// An argument placeholder, for use with boost::bind(), that corresponds to -/// the results argument of a handler for asynchronous functions such as -/// asio::async_connect. +/// An argument placeholder, for use with std::bind() or boost::bind(), that +/// corresponds to the results argument of a handler for asynchronous functions +/// such as asio::async_connect. unspecified endpoint; -/// An argument placeholder, for use with boost::bind(), that corresponds to -/// the signal_number argument of a handler for asynchronous functions such as -/// asio::signal_set::async_wait. +/// An argument placeholder, for use with std::bind() or boost::bind(), that +/// corresponds to the signal_number argument of a handler for asynchronous +/// functions such as asio::signal_set::async_wait. unspecified signal_number; -#elif defined(ASIO_HAS_BOOST_BIND) -# if defined(__BORLANDC__) || defined(__GNUC__) - -inline boost::arg<1> error() -{ - return boost::arg<1>(); -} - -inline boost::arg<2> bytes_transferred() -{ - return boost::arg<2>(); -} - -inline boost::arg<2> iterator() -{ - return boost::arg<2>(); -} - -inline boost::arg<2> results() -{ - return boost::arg<2>(); -} - -inline boost::arg<2> endpoint() -{ - return boost::arg<2>(); -} - -inline boost::arg<2> signal_number() -{ - return boost::arg<2>(); -} - -# else - -namespace detail -{ - template <int Number> - struct placeholder - { - static boost::arg<Number>& get() - { - static boost::arg<Number> result; - return result; - } - }; -} - -# if defined(ASIO_MSVC) && (ASIO_MSVC < 1400) - -static boost::arg<1>& error - = asio::placeholders::detail::placeholder<1>::get(); -static boost::arg<2>& bytes_transferred - = asio::placeholders::detail::placeholder<2>::get(); -static boost::arg<2>& iterator - = asio::placeholders::detail::placeholder<2>::get(); -static boost::arg<2>& results - = asio::placeholders::detail::placeholder<2>::get(); -static boost::arg<2>& endpoint - = asio::placeholders::detail::placeholder<2>::get(); -static boost::arg<2>& signal_number - = asio::placeholders::detail::placeholder<2>::get(); - -# else - -namespace -{ - boost::arg<1>& error - = asio::placeholders::detail::placeholder<1>::get(); - boost::arg<2>& bytes_transferred - = asio::placeholders::detail::placeholder<2>::get(); - boost::arg<2>& iterator - = asio::placeholders::detail::placeholder<2>::get(); - boost::arg<2>& results - = asio::placeholders::detail::placeholder<2>::get(); - boost::arg<2>& endpoint - = asio::placeholders::detail::placeholder<2>::get(); - boost::arg<2>& signal_number - = asio::placeholders::detail::placeholder<2>::get(); -} // namespace - -# endif -# endif +#else + +static constexpr auto& error = std::placeholders::_1; +static constexpr auto& bytes_transferred = std::placeholders::_2; +static constexpr auto& iterator = std::placeholders::_2; +static constexpr auto& results = std::placeholders::_2; +static constexpr auto& endpoint = std::placeholders::_2; +static constexpr auto& signal_number = std::placeholders::_2; + #endif } // namespace placeholders diff --git a/3rdparty/asio/include/asio/posix/basic_descriptor.hpp b/3rdparty/asio/include/asio/posix/basic_descriptor.hpp index 27db872c338..fa47d6a0949 100644 --- a/3rdparty/asio/include/asio/posix/basic_descriptor.hpp +++ b/3rdparty/asio/include/asio/posix/basic_descriptor.hpp @@ -2,7 +2,7 @@ // posix/basic_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,16 +17,26 @@ #include "asio/detail/config.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) - #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) -#include "asio/basic_io_object.hpp" +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" +#include "asio/execution_context.hpp" #include "asio/posix/descriptor_base.hpp" +#if defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_descriptor_service.hpp" +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/reactive_descriptor_service.hpp" +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + #include "asio/detail/push_options.hpp" namespace asio { @@ -41,37 +51,76 @@ namespace posix { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename DescriptorService> +template <typename Executor = any_io_executor> class basic_descriptor - : public basic_io_object<DescriptorService>, - public descriptor_base + : public descriptor_base { +private: + class initiate_async_wait; + public: - /// The native representation of a descriptor. - typedef typename DescriptorService::native_handle_type native_handle_type; + /// The type of the executor associated with the object. + typedef Executor executor_type; - /// A basic_descriptor is always the lowest layer. - typedef basic_descriptor<DescriptorService> lowest_layer_type; + /// Rebinds the descriptor type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The descriptor type when rebound to the specified executor. + typedef basic_descriptor<Executor1> other; + }; - /// Construct a basic_descriptor without opening it. + /// The native representation of a descriptor. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef detail::io_uring_descriptor_service::native_handle_type + native_handle_type; +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef detail::reactive_descriptor_service::native_handle_type + native_handle_type; +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + + /// A descriptor is always the lowest layer. + typedef basic_descriptor lowest_layer_type; + + /// Construct a descriptor without opening it. /** * This constructor creates a descriptor without opening it. * - * @param io_context The io_context object that the descriptor will use to + * @param ex The I/O executor that the descriptor will use, by default, to * dispatch handlers for any asynchronous operations performed on the * descriptor. */ - explicit basic_descriptor(asio::io_context& io_context) - : basic_io_object<DescriptorService>(io_context) + explicit basic_descriptor(const executor_type& ex) + : impl_(0, ex) { } - /// Construct a basic_descriptor on an existing native descriptor. + /// Construct a descriptor without opening it. + /** + * This constructor creates a descriptor without opening it. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + */ + template <typename ExecutionContext> + explicit basic_descriptor(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct a descriptor on an existing native descriptor. /** * This constructor creates a descriptor object to hold an existing native * descriptor. * - * @param io_context The io_context object that the descriptor will use to + * @param ex The I/O executor that the descriptor will use, by default, to * dispatch handlers for any asynchronous operations performed on the * descriptor. * @@ -79,18 +128,82 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_descriptor(asio::io_context& io_context, + basic_descriptor(const executor_type& ex, const native_handle_type& native_descriptor) - : basic_io_object<DescriptorService>(io_context) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_descriptor, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a descriptor on an existing native descriptor. + /** + * This constructor creates a descriptor object to hold an existing native + * descriptor. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + * + * @param native_descriptor A native descriptor. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_descriptor(ExecutionContext& context, + const native_handle_type& native_descriptor, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), native_descriptor, ec); asio::detail::throw_error(ec, "assign"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a basic_descriptor from another. + /// Move-construct a descriptor from another. + /** + * This constructor moves a descriptor from one object to another. + * + * @param other The other descriptor object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_descriptor(const executor_type&) + * constructor. + */ + basic_descriptor(basic_descriptor&& other) noexcept + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a descriptor from another. + /** + * This assignment operator moves a descriptor from one object to another. + * + * @param other The other descriptor object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_descriptor(const executor_type&) + * constructor. + */ + basic_descriptor& operator=(basic_descriptor&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All descriptors have access to each other's implementations. + template <typename Executor1> + friend class basic_descriptor; + + /// Move-construct a basic_descriptor from a descriptor of another executor + /// type. /** * This constructor moves a descriptor from one object to another. * @@ -98,15 +211,20 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_descriptor(io_context&) constructor. + * constructed using the @c basic_descriptor(const executor_type&) + * constructor. */ - basic_descriptor(basic_descriptor&& other) - : basic_io_object<DescriptorService>( - ASIO_MOVE_CAST(basic_descriptor)(other)) + template <typename Executor1> + basic_descriptor(basic_descriptor<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(std::move(other.impl_)) { } - /// Move-assign a basic_descriptor from another. + /// Move-assign a basic_descriptor from a descriptor of another executor type. /** * This assignment operator moves a descriptor from one object to another. * @@ -114,20 +232,30 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_descriptor(io_context&) constructor. + * constructed using the @c basic_descriptor(const executor_type&) + * constructor. */ - basic_descriptor& operator=(basic_descriptor&& other) + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_descriptor& + > operator=(basic_descriptor<Executor1> && other) { - basic_io_object<DescriptorService>::operator=( - ASIO_MOVE_CAST(basic_descriptor)(other)); + basic_descriptor tmp(std::move(other)); + impl_ = std::move(tmp.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of - * layers. Since a basic_descriptor cannot contain any further layers, it + * layers. Since a descriptor cannot contain any further layers, it * simply returns a reference to itself. * * @return A reference to the lowest layer in the stack of layers. Ownership @@ -141,7 +269,7 @@ public: /// Get a const reference to the lowest layer. /** * This function returns a const reference to the lowest layer in a stack of - * layers. Since a basic_descriptor cannot contain any further layers, it + * layers. Since a descriptor cannot contain any further layers, it * simply returns a reference to itself. * * @return A const reference to the lowest layer in the stack of layers. @@ -163,7 +291,7 @@ public: void assign(const native_handle_type& native_descriptor) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), native_descriptor, ec); asio::detail::throw_error(ec, "assign"); } @@ -179,15 +307,15 @@ public: ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor, asio::error_code& ec) { - this->get_service().assign( - this->get_implementation(), native_descriptor, ec); + impl_.get_service().assign( + impl_.get_implementation(), native_descriptor, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the descriptor is open. bool is_open() const { - return this->get_service().is_open(this->get_implementation()); + return impl_.get_service().is_open(impl_.get_implementation()); } /// Close the descriptor. @@ -202,7 +330,7 @@ public: void close() { asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "close"); } @@ -217,7 +345,7 @@ public: */ ASIO_SYNC_OP_VOID close(asio::error_code& ec) { - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -229,7 +357,7 @@ public: */ native_handle_type native_handle() { - return this->get_service().native_handle(this->get_implementation()); + return impl_.get_service().native_handle(impl_.get_implementation()); } /// Release ownership of the native descriptor implementation. @@ -244,7 +372,7 @@ public: */ native_handle_type release() { - return this->get_service().release(this->get_implementation()); + return impl_.get_service().release(impl_.get_implementation()); } /// Cancel all asynchronous operations associated with the descriptor. @@ -258,7 +386,7 @@ public: void cancel() { asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); } @@ -272,7 +400,7 @@ public: */ ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) { - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -291,7 +419,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::posix::stream_descriptor descriptor(io_context); + * asio::posix::stream_descriptor descriptor(my_context); * ... * asio::posix::stream_descriptor::bytes_readable command; * descriptor.io_control(command); @@ -302,7 +430,7 @@ public: void io_control(IoControlCommand& command) { asio::error_code ec; - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); asio::detail::throw_error(ec, "io_control"); } @@ -321,7 +449,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::posix::stream_descriptor descriptor(io_context); + * asio::posix::stream_descriptor descriptor(my_context); * ... * asio::posix::stream_descriptor::bytes_readable command; * asio::error_code ec; @@ -337,7 +465,7 @@ public: ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, asio::error_code& ec) { - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -354,7 +482,7 @@ public: */ bool non_blocking() const { - return this->get_service().non_blocking(this->get_implementation()); + return impl_.get_service().non_blocking(impl_.get_implementation()); } /// Sets the non-blocking mode of the descriptor. @@ -373,7 +501,7 @@ public: void non_blocking(bool mode) { asio::error_code ec; - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "non_blocking"); } @@ -393,7 +521,7 @@ public: ASIO_SYNC_OP_VOID non_blocking( bool mode, asio::error_code& ec) { - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -413,8 +541,8 @@ public: */ bool native_non_blocking() const { - return this->get_service().native_non_blocking( - this->get_implementation()); + return impl_.get_service().native_non_blocking( + impl_.get_implementation()); } /// Sets the non-blocking mode of the native descriptor implementation. @@ -435,8 +563,8 @@ public: void native_non_blocking(bool mode) { asio::error_code ec; - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "native_non_blocking"); } @@ -458,8 +586,8 @@ public: ASIO_SYNC_OP_VOID native_non_blocking( bool mode, asio::error_code& ec) { - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -474,7 +602,7 @@ public: * @par Example * Waiting for a descriptor to become readable. * @code - * asio::posix::stream_descriptor descriptor(io_context); + * asio::posix::stream_descriptor descriptor(my_context); * ... * descriptor.wait(asio::posix::stream_descriptor::wait_read); * @endcode @@ -482,7 +610,7 @@ public: void wait(wait_type w) { asio::error_code ec; - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); asio::detail::throw_error(ec, "wait"); } @@ -499,7 +627,7 @@ public: * @par Example * Waiting for a descriptor to become readable. * @code - * asio::posix::stream_descriptor descriptor(io_context); + * asio::posix::stream_descriptor descriptor(my_context); * ... * asio::error_code ec; * descriptor.wait(asio::posix::stream_descriptor::wait_read, ec); @@ -507,7 +635,7 @@ public: */ ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) { - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -515,20 +643,27 @@ public: /// write, or to have pending error conditions. /** * This function is used to perform an asynchronous wait for a descriptor to - * enter a ready to read, write or error condition state. + * enter a ready to read, write or error condition state. It is an initiating + * function for an @ref asynchronous_operation, and always returns + * immediately. * * @param w Specifies the desired descriptor state. * - * @param handler The handler to be called when the wait operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the wait completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode * * @par Example * @code @@ -542,31 +677,89 @@ public: * * ... * - * asio::posix::stream_descriptor descriptor(io_context); + * asio::posix::stream_descriptor descriptor(my_context); * ... * descriptor.async_wait( * asio::posix::stream_descriptor::wait_read, * wait_handler); * @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitToken = default_completion_token_t<executor_type>> + auto async_wait(wait_type w, + WaitToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WaitToken, void (asio::error_code)>( + declval<initiate_async_wait>(), token, w)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WaitHandler. - ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - - return this->get_service().async_wait(this->get_implementation(), - w, ASIO_MOVE_CAST(WaitHandler)(handler)); + return async_initiate<WaitToken, void (asio::error_code)>( + initiate_async_wait(this), token, w); } protected: /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the descriptor, cancelling any outstanding + * asynchronous wait operations associated with the descriptor as if by + * calling @c cancel. + */ ~basic_descriptor() { } + +#if defined(ASIO_HAS_IO_URING_AS_DEFAULT) + detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_; +#else // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_; +#endif // defined(ASIO_HAS_IO_URING_AS_DEFAULT) + +private: + // Disallow copying and assignment. + basic_descriptor(const basic_descriptor&) = delete; + basic_descriptor& operator=(const basic_descriptor&) = delete; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_descriptor* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue<WaitHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_descriptor* self_; + }; }; } // namespace posix @@ -577,6 +770,4 @@ protected: #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP diff --git a/3rdparty/asio/include/asio/posix/basic_stream_descriptor.hpp b/3rdparty/asio/include/asio/posix/basic_stream_descriptor.hpp index eb7bc8bb975..9868dee1259 100644 --- a/3rdparty/asio/include/asio/posix/basic_stream_descriptor.hpp +++ b/3rdparty/asio/include/asio/posix/basic_stream_descriptor.hpp @@ -2,7 +2,7 @@ // posix/basic_stream_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,19 +16,11 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) +#include "asio/posix/basic_descriptor.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) -#include <cstddef> -#include "asio/detail/handler_type_requirements.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/error.hpp" -#include "asio/posix/basic_descriptor.hpp" -#include "asio/posix/stream_descriptor_service.hpp" - #include "asio/detail/push_options.hpp" namespace asio { @@ -43,87 +35,193 @@ namespace posix { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * + * Synchronous @c read_some and @c write_some operations are thread safe with + * respect to each other, if the underlying operating system calls are also + * thread safe. This means that it is permitted to perform concurrent calls to + * these synchronous operations on a single descriptor object. Other synchronous + * operations, such as @c close, are not thread safe. + * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ -template <typename StreamDescriptorService = stream_descriptor_service> +template <typename Executor = any_io_executor> class basic_stream_descriptor - : public basic_descriptor<StreamDescriptorService> + : public basic_descriptor<Executor> { +private: + class initiate_async_write_some; + class initiate_async_read_some; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the descriptor type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The descriptor type when rebound to the specified executor. + typedef basic_stream_descriptor<Executor1> other; + }; + /// The native representation of a descriptor. - typedef typename StreamDescriptorService::native_handle_type + typedef typename basic_descriptor<Executor>::native_handle_type native_handle_type; - /// Construct a basic_stream_descriptor without opening it. + /// Construct a stream descriptor without opening it. /** * This constructor creates a stream descriptor without opening it. The * descriptor needs to be opened and then connected or accepted before data * can be sent or received on it. * - * @param io_context The io_context object that the stream descriptor will - * use to dispatch handlers for any asynchronous operations performed on the + * @param ex The I/O executor that the descriptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the * descriptor. */ - explicit basic_stream_descriptor(asio::io_context& io_context) - : basic_descriptor<StreamDescriptorService>(io_context) + explicit basic_stream_descriptor(const executor_type& ex) + : basic_descriptor<Executor>(ex) + { + } + + /// Construct a stream descriptor without opening it. + /** + * This constructor creates a stream descriptor without opening it. The + * descriptor needs to be opened and then connected or accepted before data + * can be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + */ + template <typename ExecutionContext> + explicit basic_stream_descriptor(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_descriptor<Executor>(context) { } - /// Construct a basic_stream_descriptor on an existing native descriptor. + /// Construct a stream descriptor on an existing native descriptor. /** * This constructor creates a stream descriptor object to hold an existing * native descriptor. * - * @param io_context The io_context object that the stream descriptor will - * use to dispatch handlers for any asynchronous operations performed on the + * @param ex The I/O executor that the descriptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the * descriptor. * * @param native_descriptor The new underlying descriptor implementation. * * @throws asio::system_error Thrown on failure. */ - basic_stream_descriptor(asio::io_context& io_context, + basic_stream_descriptor(const executor_type& ex, const native_handle_type& native_descriptor) - : basic_descriptor<StreamDescriptorService>(io_context, native_descriptor) + : basic_descriptor<Executor>(ex, native_descriptor) + { + } + + /// Construct a stream descriptor on an existing native descriptor. + /** + * This constructor creates a stream descriptor object to hold an existing + * native descriptor. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + * + * @param native_descriptor The new underlying descriptor implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_stream_descriptor(ExecutionContext& context, + const native_handle_type& native_descriptor, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_descriptor<Executor>(context, native_descriptor) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a basic_stream_descriptor from another. + /// Move-construct a stream descriptor from another. /** * This constructor moves a stream descriptor from one object to another. * - * @param other The other basic_stream_descriptor object from which the move + * @param other The other stream descriptor object from which the move * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_descriptor(io_context&) constructor. + * constructed using the @c basic_stream_descriptor(const executor_type&) + * constructor. */ - basic_stream_descriptor(basic_stream_descriptor&& other) - : basic_descriptor<StreamDescriptorService>( - ASIO_MOVE_CAST(basic_stream_descriptor)(other)) + basic_stream_descriptor(basic_stream_descriptor&& other) noexcept + : basic_descriptor<Executor>(std::move(other)) { } - /// Move-assign a basic_stream_descriptor from another. + /// Move-assign a stream descriptor from another. /** * This assignment operator moves a stream descriptor from one object to * another. * - * @param other The other basic_stream_descriptor object from which the move + * @param other The other stream descriptor object from which the move * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_descriptor(io_context&) constructor. + * constructed using the @c basic_stream_descriptor(const executor_type&) + * constructor. */ basic_stream_descriptor& operator=(basic_stream_descriptor&& other) { - basic_descriptor<StreamDescriptorService>::operator=( - ASIO_MOVE_CAST(basic_stream_descriptor)(other)); + basic_descriptor<Executor>::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_stream_descriptor from a descriptor of another + /// executor type. + /** + * This constructor moves a descriptor from one object to another. + * + * @param other The other basic_stream_descriptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_descriptor(const executor_type&) + * constructor. + */ + template <typename Executor1> + basic_stream_descriptor(basic_stream_descriptor<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_descriptor<Executor>(std::move(other)) + { + } + + /// Move-assign a basic_stream_descriptor from a descriptor of another + /// executor type. + /** + * This assignment operator moves a descriptor from one object to another. + * + * @param other The other basic_stream_descriptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_descriptor(const executor_type&) + * constructor. + */ + template <typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_stream_descriptor& + > operator=(basic_stream_descriptor<Executor1> && other) + { + basic_descriptor<Executor>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Write some data to the descriptor. /** @@ -156,8 +254,8 @@ public: std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().write_some( - this->get_implementation(), buffers, ec); + std::size_t s = this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); asio::detail::throw_error(ec, "write_some"); return s; } @@ -182,31 +280,37 @@ public: std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().write_some( - this->get_implementation(), buffers, ec); + return this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the stream - * descriptor. The function call always returns immediately. + * descriptor. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more data buffers to be written to the descriptor. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -220,19 +324,30 @@ public: * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some(this), token, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - return this->get_service().async_write_some(this->get_implementation(), - buffers, ASIO_MOVE_CAST(WriteHandler)(handler)); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some(this), token, buffers); } /// Read some data from the descriptor. @@ -267,8 +382,8 @@ public: std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().read_some( - this->get_implementation(), buffers, ec); + std::size_t s = this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); asio::detail::throw_error(ec, "read_some"); return s; } @@ -294,31 +409,37 @@ public: std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().read_some( - this->get_implementation(), buffers, ec); + return this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the stream - * descriptor. The function call always returns immediately. + * descriptor. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -333,20 +454,98 @@ public: * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some>(), token, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - return this->get_service().async_read_some(this->get_implementation(), - buffers, ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some(this), token, buffers); } + +private: + class initiate_async_write_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_stream_descriptor* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_descriptor* self_; + }; + + class initiate_async_read_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_stream_descriptor* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_descriptor* self_; + }; }; } // namespace posix @@ -357,6 +556,4 @@ public: #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP diff --git a/3rdparty/asio/include/asio/posix/descriptor.hpp b/3rdparty/asio/include/asio/posix/descriptor.hpp index 9ab46a5d956..57b5b2522fd 100644 --- a/3rdparty/asio/include/asio/posix/descriptor.hpp +++ b/3rdparty/asio/include/asio/posix/descriptor.hpp @@ -2,7 +2,7 @@ // posix/descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,628 +17,21 @@ #include "asio/detail/config.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) - #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) -#include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" -#include "asio/detail/handler_type_requirements.hpp" -#include "asio/detail/reactive_descriptor_service.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" -#include "asio/posix/descriptor_base.hpp" - -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#define ASIO_SVC_T asio::detail::reactive_descriptor_service - -#include "asio/detail/push_options.hpp" +#include "asio/posix/basic_descriptor.hpp" namespace asio { namespace posix { -/// Provides POSIX descriptor functionality. -/** - * The posix::descriptor class template provides the ability to wrap a - * POSIX descriptor. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - */ -class descriptor - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>, - public descriptor_base -{ -public: - /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; - - /// The native representation of a descriptor. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef ASIO_SVC_T::native_handle_type native_handle_type; -#endif - - /// A descriptor is always the lowest layer. - typedef descriptor lowest_layer_type; - - /// Construct a descriptor without opening it. - /** - * This constructor creates a descriptor without opening it. - * - * @param io_context The io_context object that the descriptor will use to - * dispatch handlers for any asynchronous operations performed on the - * descriptor. - */ - explicit descriptor(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) - { - } - - /// Construct a descriptor on an existing native descriptor. - /** - * This constructor creates a descriptor object to hold an existing native - * descriptor. - * - * @param io_context The io_context object that the descriptor will use to - * dispatch handlers for any asynchronous operations performed on the - * descriptor. - * - * @param native_descriptor A native descriptor. - * - * @throws asio::system_error Thrown on failure. - */ - descriptor(asio::io_context& io_context, - const native_handle_type& native_descriptor) - : basic_io_object<ASIO_SVC_T>(io_context) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), - native_descriptor, ec); - asio::detail::throw_error(ec, "assign"); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a descriptor from another. - /** - * This constructor moves a descriptor from one object to another. - * - * @param other The other descriptor object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c descriptor(io_context&) constructor. - */ - descriptor(descriptor&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) - { - } - - /// Move-assign a descriptor from another. - /** - * This assignment operator moves a descriptor from one object to another. - * - * @param other The other descriptor object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c descriptor(io_context&) constructor. - */ - descriptor& operator=(descriptor&& other) - { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - - /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT - { - return basic_io_object<ASIO_SVC_T>::get_executor(); - } - - /// Get a reference to the lowest layer. - /** - * This function returns a reference to the lowest layer in a stack of - * layers. Since a descriptor cannot contain any further layers, it - * simply returns a reference to itself. - * - * @return A reference to the lowest layer in the stack of layers. Ownership - * is not transferred to the caller. - */ - lowest_layer_type& lowest_layer() - { - return *this; - } - - /// Get a const reference to the lowest layer. - /** - * This function returns a const reference to the lowest layer in a stack of - * layers. Since a descriptor cannot contain any further layers, it - * simply returns a reference to itself. - * - * @return A const reference to the lowest layer in the stack of layers. - * Ownership is not transferred to the caller. - */ - const lowest_layer_type& lowest_layer() const - { - return *this; - } - - /// Assign an existing native descriptor to the descriptor. - /* - * This function opens the descriptor to hold an existing native descriptor. - * - * @param native_descriptor A native descriptor. - * - * @throws asio::system_error Thrown on failure. - */ - void assign(const native_handle_type& native_descriptor) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), - native_descriptor, ec); - asio::detail::throw_error(ec, "assign"); - } - - /// Assign an existing native descriptor to the descriptor. - /* - * This function opens the descriptor to hold an existing native descriptor. - * - * @param native_descriptor A native descriptor. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor, - asio::error_code& ec) - { - this->get_service().assign( - this->get_implementation(), native_descriptor, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the descriptor is open. - bool is_open() const - { - return this->get_service().is_open(this->get_implementation()); - } - - /// Close the descriptor. - /** - * This function is used to close the descriptor. Any asynchronous read or - * write operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. Note that, even if - * the function indicates an error, the underlying descriptor is closed. - */ - void close() - { - asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); - asio::detail::throw_error(ec, "close"); - } - - /// Close the descriptor. - /** - * This function is used to close the descriptor. Any asynchronous read or - * write operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. Note that, even if - * the function indicates an error, the underlying descriptor is closed. - */ - ASIO_SYNC_OP_VOID close(asio::error_code& ec) - { - this->get_service().close(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native descriptor representation. - /** - * This function may be used to obtain the underlying representation of the - * descriptor. This is intended to allow access to native descriptor - * functionality that is not otherwise provided. - */ - native_handle_type native_handle() - { - return this->get_service().native_handle(this->get_implementation()); - } - - /// Release ownership of the native descriptor implementation. - /** - * This function may be used to obtain the underlying representation of the - * descriptor. After calling this function, @c is_open() returns false. The - * caller is responsible for closing the descriptor. - * - * All outstanding asynchronous read or write operations will finish - * immediately, and the handlers for cancelled operations will be passed the - * asio::error::operation_aborted error. - */ - native_handle_type release() - { - return this->get_service().release(this->get_implementation()); - } - - /// Cancel all asynchronous operations associated with the descriptor. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void cancel() - { - asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); - asio::detail::throw_error(ec, "cancel"); - } - - /// Cancel all asynchronous operations associated with the descriptor. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) - { - this->get_service().cancel(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform an IO control command on the descriptor. - /** - * This function is used to execute an IO control command on the descriptor. - * - * @param command The IO control command to be performed on the descriptor. - * - * @throws asio::system_error Thrown on failure. - * - * @sa IoControlCommand @n - * asio::posix::descriptor_base::bytes_readable @n - * asio::posix::descriptor_base::non_blocking_io - * - * @par Example - * Getting the number of bytes ready to read: - * @code - * asio::posix::stream_descriptor descriptor(io_context); - * ... - * asio::posix::stream_descriptor::bytes_readable command; - * descriptor.io_control(command); - * std::size_t bytes_readable = command.get(); - * @endcode - */ - template <typename IoControlCommand> - void io_control(IoControlCommand& command) - { - asio::error_code ec; - this->get_service().io_control(this->get_implementation(), command, ec); - asio::detail::throw_error(ec, "io_control"); - } - - /// Perform an IO control command on the descriptor. - /** - * This function is used to execute an IO control command on the descriptor. - * - * @param command The IO control command to be performed on the descriptor. - * - * @param ec Set to indicate what error occurred, if any. - * - * @sa IoControlCommand @n - * asio::posix::descriptor_base::bytes_readable @n - * asio::posix::descriptor_base::non_blocking_io - * - * @par Example - * Getting the number of bytes ready to read: - * @code - * asio::posix::stream_descriptor descriptor(io_context); - * ... - * asio::posix::stream_descriptor::bytes_readable command; - * asio::error_code ec; - * descriptor.io_control(command, ec); - * if (ec) - * { - * // An error occurred. - * } - * std::size_t bytes_readable = command.get(); - * @endcode - */ - template <typename IoControlCommand> - ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, - asio::error_code& ec) - { - this->get_service().io_control(this->get_implementation(), command, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the descriptor. - /** - * @returns @c true if the descriptor's synchronous operations will fail with - * asio::error::would_block if they are unable to perform the requested - * operation immediately. If @c false, synchronous operations will block - * until complete. - * - * @note The non-blocking mode has no effect on the behaviour of asynchronous - * operations. Asynchronous operations will never fail with the error - * asio::error::would_block. - */ - bool non_blocking() const - { - return this->get_service().non_blocking(this->get_implementation()); - } - - /// Sets the non-blocking mode of the descriptor. - /** - * @param mode If @c true, the descriptor's synchronous operations will fail - * with asio::error::would_block if they are unable to perform the - * requested operation immediately. If @c false, synchronous operations will - * block until complete. - * - * @throws asio::system_error Thrown on failure. - * - * @note The non-blocking mode has no effect on the behaviour of asynchronous - * operations. Asynchronous operations will never fail with the error - * asio::error::would_block. - */ - void non_blocking(bool mode) - { - asio::error_code ec; - this->get_service().non_blocking(this->get_implementation(), mode, ec); - asio::detail::throw_error(ec, "non_blocking"); - } - - /// Sets the non-blocking mode of the descriptor. - /** - * @param mode If @c true, the descriptor's synchronous operations will fail - * with asio::error::would_block if they are unable to perform the - * requested operation immediately. If @c false, synchronous operations will - * block until complete. - * - * @param ec Set to indicate what error occurred, if any. - * - * @note The non-blocking mode has no effect on the behaviour of asynchronous - * operations. Asynchronous operations will never fail with the error - * asio::error::would_block. - */ - ASIO_SYNC_OP_VOID non_blocking( - bool mode, asio::error_code& ec) - { - this->get_service().non_blocking(this->get_implementation(), mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the native descriptor implementation. - /** - * This function is used to retrieve the non-blocking mode of the underlying - * native descriptor. This mode has no effect on the behaviour of the - * descriptor object's synchronous operations. - * - * @returns @c true if the underlying descriptor is in non-blocking mode and - * direct system calls may fail with asio::error::would_block (or the - * equivalent system error). - * - * @note The current non-blocking mode is cached by the descriptor object. - * Consequently, the return value may be incorrect if the non-blocking mode - * was set directly on the native descriptor. - */ - bool native_non_blocking() const - { - return this->get_service().native_non_blocking( - this->get_implementation()); - } - - /// Sets the non-blocking mode of the native descriptor implementation. - /** - * This function is used to modify the non-blocking mode of the underlying - * native descriptor. It has no effect on the behaviour of the descriptor - * object's synchronous operations. - * - * @param mode If @c true, the underlying descriptor is put into non-blocking - * mode and direct system calls may fail with asio::error::would_block - * (or the equivalent system error). - * - * @throws asio::system_error Thrown on failure. If the @c mode is - * @c false, but the current value of @c non_blocking() is @c true, this - * function fails with asio::error::invalid_argument, as the - * combination does not make sense. - */ - void native_non_blocking(bool mode) - { - asio::error_code ec; - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); - asio::detail::throw_error(ec, "native_non_blocking"); - } - - /// Sets the non-blocking mode of the native descriptor implementation. - /** - * This function is used to modify the non-blocking mode of the underlying - * native descriptor. It has no effect on the behaviour of the descriptor - * object's synchronous operations. - * - * @param mode If @c true, the underlying descriptor is put into non-blocking - * mode and direct system calls may fail with asio::error::would_block - * (or the equivalent system error). - * - * @param ec Set to indicate what error occurred, if any. If the @c mode is - * @c false, but the current value of @c non_blocking() is @c true, this - * function fails with asio::error::invalid_argument, as the - * combination does not make sense. - */ - ASIO_SYNC_OP_VOID native_non_blocking( - bool mode, asio::error_code& ec) - { - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Wait for the descriptor to become ready to read, ready to write, or to - /// have pending error conditions. - /** - * This function is used to perform a blocking wait for a descriptor to enter - * a ready to read, write or error condition state. - * - * @param w Specifies the desired descriptor state. - * - * @par Example - * Waiting for a descriptor to become readable. - * @code - * asio::posix::stream_descriptor descriptor(io_context); - * ... - * descriptor.wait(asio::posix::stream_descriptor::wait_read); - * @endcode - */ - void wait(wait_type w) - { - asio::error_code ec; - this->get_service().wait(this->get_implementation(), w, ec); - asio::detail::throw_error(ec, "wait"); - } - - /// Wait for the descriptor to become ready to read, ready to write, or to - /// have pending error conditions. - /** - * This function is used to perform a blocking wait for a descriptor to enter - * a ready to read, write or error condition state. - * - * @param w Specifies the desired descriptor state. - * - * @param ec Set to indicate what error occurred, if any. - * - * @par Example - * Waiting for a descriptor to become readable. - * @code - * asio::posix::stream_descriptor descriptor(io_context); - * ... - * asio::error_code ec; - * descriptor.wait(asio::posix::stream_descriptor::wait_read, ec); - * @endcode - */ - ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) - { - this->get_service().wait(this->get_implementation(), w, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Asynchronously wait for the descriptor to become ready to read, ready to - /// write, or to have pending error conditions. - /** - * This function is used to perform an asynchronous wait for a descriptor to - * enter a ready to read, write or error condition state. - * - * @param w Specifies the desired descriptor state. - * - * @param handler The handler to be called when the wait operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error // Result of operation - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @par Example - * @code - * void wait_handler(const asio::error_code& error) - * { - * if (!error) - * { - * // Wait succeeded. - * } - * } - * - * ... - * - * asio::posix::stream_descriptor descriptor(io_context); - * ... - * descriptor.async_wait( - * asio::posix::stream_descriptor::wait_read, - * wait_handler); - * @endcode - */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WaitHandler. - ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_wait( - this->get_implementation(), w, init.completion_handler); - - return init.result.get(); - } - -protected: - /// Protected destructor to prevent deletion through this type. - /** - * This function destroys the descriptor, cancelling any outstanding - * asynchronous wait operations associated with the descriptor as if by - * calling @c cancel. - */ - ~descriptor() - { - } -}; +/// Typedef for the typical usage of basic_descriptor. +typedef basic_descriptor<> descriptor; } // namespace posix } // namespace asio -#include "asio/detail/pop_options.hpp" - -#undef ASIO_SVC_T - #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) - // || defined(GENERATING_DOCUMENTATION) - -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) + // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_POSIX_DESCRIPTOR_HPP diff --git a/3rdparty/asio/include/asio/posix/descriptor_base.hpp b/3rdparty/asio/include/asio/posix/descriptor_base.hpp index b77d49d8227..7bc3bc1e8f6 100644 --- a/3rdparty/asio/include/asio/posix/descriptor_base.hpp +++ b/3rdparty/asio/include/asio/posix/descriptor_base.hpp @@ -2,7 +2,7 @@ // posix/descriptor_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -56,7 +56,7 @@ public: * * @par Example * @code - * asio::posix::stream_descriptor descriptor(io_context); + * asio::posix::stream_descriptor descriptor(my_context); * ... * asio::descriptor_base::bytes_readable command(true); * descriptor.io_control(command); diff --git a/3rdparty/asio/include/asio/posix/stream_descriptor.hpp b/3rdparty/asio/include/asio/posix/stream_descriptor.hpp index 29e157208c6..4855f10777e 100644 --- a/3rdparty/asio/include/asio/posix/stream_descriptor.hpp +++ b/3rdparty/asio/include/asio/posix/stream_descriptor.hpp @@ -2,7 +2,7 @@ // posix/stream_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,340 +16,17 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/posix/descriptor.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/posix/basic_stream_descriptor.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) +#include "asio/posix/basic_stream_descriptor.hpp" namespace asio { namespace posix { -#if defined(ASIO_ENABLE_OLD_SERVICES) -// Typedef for the typical usage of a stream-oriented descriptor. +/// Typedef for the typical usage of a stream-oriented descriptor. typedef basic_stream_descriptor<> stream_descriptor; -#else // defined(ASIO_ENABLE_OLD_SERVICES) -/// Provides stream-oriented descriptor functionality. -/** - * The posix::stream_descriptor class template provides asynchronous and - * blocking stream-oriented descriptor functionality. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - * - * @par Concepts: - * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. - */ -class stream_descriptor - : public descriptor -{ -public: - /// Construct a stream_descriptor without opening it. - /** - * This constructor creates a stream descriptor without opening it. The - * descriptor needs to be opened and then connected or accepted before data - * can be sent or received on it. - * - * @param io_context The io_context object that the stream descriptor will - * use to dispatch handlers for any asynchronous operations performed on the - * descriptor. - */ - explicit stream_descriptor(asio::io_context& io_context) - : descriptor(io_context) - { - } - - /// Construct a stream_descriptor on an existing native descriptor. - /** - * This constructor creates a stream descriptor object to hold an existing - * native descriptor. - * - * @param io_context The io_context object that the stream descriptor will - * use to dispatch handlers for any asynchronous operations performed on the - * descriptor. - * - * @param native_descriptor The new underlying descriptor implementation. - * - * @throws asio::system_error Thrown on failure. - */ - stream_descriptor(asio::io_context& io_context, - const native_handle_type& native_descriptor) - : descriptor(io_context, native_descriptor) - { - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a stream_descriptor from another. - /** - * This constructor moves a stream descriptor from one object to another. - * - * @param other The other stream_descriptor object from which the move - * will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c stream_descriptor(io_context&) constructor. - */ - stream_descriptor(stream_descriptor&& other) - : descriptor(std::move(other)) - { - } - - /// Move-assign a stream_descriptor from another. - /** - * This assignment operator moves a stream descriptor from one object to - * another. - * - * @param other The other stream_descriptor object from which the move - * will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c stream_descriptor(io_context&) constructor. - */ - stream_descriptor& operator=(stream_descriptor&& other) - { - descriptor::operator=(std::move(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Write some data to the descriptor. - /** - * This function is used to write data to the stream descriptor. The function - * call will block until one or more bytes of the data has been written - * successfully, or until an error occurs. - * - * @param buffers One or more data buffers to be written to the descriptor. - * - * @returns The number of bytes written. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that - * all data is written before the blocking operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * descriptor.write_some(asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().write_some( - this->get_implementation(), buffers, ec); - asio::detail::throw_error(ec, "write_some"); - return s; - } - - /// Write some data to the descriptor. - /** - * This function is used to write data to the stream descriptor. The function - * call will block until one or more bytes of the data has been written - * successfully, or until an error occurs. - * - * @param buffers One or more data buffers to be written to the descriptor. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes written. Returns 0 if an error occurred. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that - * all data is written before the blocking operation completes. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers, - asio::error_code& ec) - { - return this->get_service().write_some( - this->get_implementation(), buffers, ec); - } - - /// Start an asynchronous write. - /** - * This function is used to asynchronously write data to the stream - * descriptor. The function call always returns immediately. - * - * @param buffers One or more data buffers to be written to the descriptor. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The write operation may not transmit all of the data to the peer. - * Consider using the @ref async_write function if you need to ensure that all - * data is written before the asynchronous operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * descriptor.async_write_some(asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - asio::async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_write_some( - this->get_implementation(), buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the descriptor. - /** - * This function is used to read data from the stream descriptor. The function - * call will block until one or more bytes of data has been read successfully, - * or until an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @returns The number of bytes read. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * descriptor.read_some(asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().read_some( - this->get_implementation(), buffers, ec); - asio::detail::throw_error(ec, "read_some"); - return s; - } - - /// Read some data from the descriptor. - /** - * This function is used to read data from the stream descriptor. The function - * call will block until one or more bytes of data has been read successfully, - * or until an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes read. Returns 0 if an error occurred. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers, - asio::error_code& ec) - { - return this->get_service().read_some( - this->get_implementation(), buffers, ec); - } - - /// Start an asynchronous read. - /** - * This function is used to asynchronously read data from the stream - * descriptor. The function call always returns immediately. - * - * @param buffers One or more buffers into which the data will be read. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The read operation may not read all of the requested number of bytes. - * Consider using the @ref async_read function if you need to ensure that the - * requested amount of data is read before the asynchronous operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * descriptor.async_read_some(asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - asio::async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_read_some( - this->get_implementation(), buffers, init.completion_handler); - - return init.result.get(); - } -}; -#endif // defined(ASIO_ENABLE_OLD_SERVICES) } // namespace posix } // namespace asio diff --git a/3rdparty/asio/include/asio/posix/stream_descriptor_service.hpp b/3rdparty/asio/include/asio/posix/stream_descriptor_service.hpp deleted file mode 100644 index e7a1b32394c..00000000000 --- a/3rdparty/asio/include/asio/posix/stream_descriptor_service.hpp +++ /dev/null @@ -1,279 +0,0 @@ -// -// posix/stream_descriptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP -#define ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ - || defined(GENERATING_DOCUMENTATION) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" -#include "asio/detail/reactive_descriptor_service.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace posix { - -/// Default service implementation for a stream descriptor. -class stream_descriptor_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<stream_descriptor_service> -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - -private: - // The type of the platform-specific implementation. - typedef detail::reactive_descriptor_service service_impl_type; - -public: - /// The type of a stream descriptor implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef service_impl_type::implementation_type implementation_type; -#endif - - /// The native descriptor type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new stream descriptor service for the specified io_context. - explicit stream_descriptor_service(asio::io_context& io_context) - : asio::detail::service_base<stream_descriptor_service>(io_context), - service_impl_(io_context) - { - } - - /// Construct a new stream descriptor implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new stream descriptor implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another stream descriptor implementation. - void move_assign(implementation_type& impl, - stream_descriptor_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a stream descriptor implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Assign an existing native descriptor to a stream descriptor. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const native_handle_type& native_descriptor, - asio::error_code& ec) - { - service_impl_.assign(impl, native_descriptor, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the descriptor is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a stream descriptor implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native descriptor implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Release ownership of the native descriptor implementation. - native_handle_type release(implementation_type& impl) - { - return service_impl_.release(impl); - } - - /// Cancel all asynchronous operations associated with the descriptor. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform an IO control command on the descriptor. - template <typename IoControlCommand> - ASIO_SYNC_OP_VOID io_control(implementation_type& impl, - IoControlCommand& command, asio::error_code& ec) - { - service_impl_.io_control(impl, command, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the descriptor. - bool non_blocking(const implementation_type& impl) const - { - return service_impl_.non_blocking(impl); - } - - /// Sets the non-blocking mode of the descriptor. - ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the native descriptor implementation. - bool native_non_blocking(const implementation_type& impl) const - { - return service_impl_.native_non_blocking(impl); - } - - /// Sets the non-blocking mode of the native descriptor implementation. - ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.native_non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Wait for the descriptor to become ready to read, ready to write, or to - /// have pending error conditions. - ASIO_SYNC_OP_VOID wait(implementation_type& impl, - descriptor_base::wait_type w, asio::error_code& ec) - { - service_impl_.wait(impl, w, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Asynchronously wait for the descriptor to become ready to read, ready to - /// write, or to have pending error conditions. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, descriptor_base::wait_type w, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, w, init.completion_handler); - - return init.result.get(); - } - - /// Write the given data to the stream. - template <typename ConstBufferSequence> - std::size_t write_some(implementation_type& impl, - const ConstBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.write_some(impl, buffers, ec); - } - - /// Start an asynchronous write. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - asio::async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_write_some(impl, buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the stream. - template <typename MutableBufferSequence> - std::size_t read_some(implementation_type& impl, - const MutableBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.read_some(impl, buffers, ec); - } - - /// Start an asynchronous read. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - asio::async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_read_some(impl, buffers, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace posix -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) - // || defined(GENERATING_DOCUMENTATION) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/post.hpp b/3rdparty/asio/include/asio/post.hpp index 17625cb27f0..6b534dfae4a 100644 --- a/3rdparty/asio/include/asio/post.hpp +++ b/3rdparty/asio/include/asio/post.hpp @@ -2,7 +2,7 @@ // post.hpp // ~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,9 +17,13 @@ #include "asio/detail/config.hpp" #include "asio/async_result.hpp" +#include "asio/detail/initiate_post.hpp" #include "asio/detail/type_traits.hpp" #include "asio/execution_context.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" #include "asio/is_executor.hpp" +#include "asio/require.hpp" #include "asio/detail/push_options.hpp" @@ -31,27 +35,56 @@ namespace asio { * executor. The function object is queued for execution, and is never called * from the current thread prior to returning from <tt>post()</tt>. * - * This function has the following effects: + * The use of @c post(), rather than @ref defer(), indicates the caller's + * preference that the function object be eagerly queued for execution. * - * @li Constructs a function object handler of type @c Handler, initialized - * with <tt>handler(forward<CompletionToken>(token))</tt>. + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode * - * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, - * initializing the object as <tt>result(handler)</tt>. + * @returns This function returns <tt>async_initiate<NullaryToken, + * void()>(Init{}, token)</tt>, where @c Init is a function object type defined + * as: * - * @li Obtains the handler's associated executor object @c ex by performing - * <tt>get_associated_executor(handler)</tt>. + * @code class Init + * { + * public: + * template <typename CompletionHandler> + * void operator()(CompletionHandler&& completion_handler) const; + * }; @endcode * - * @li Obtains the handler's associated allocator object @c alloc by performing - * <tt>get_associated_allocator(handler)</tt>. + * The function call operator of @c Init: * - * @li Performs <tt>ex.post(std::move(handler), alloc)</tt>. + * @li Obtains the handler's associated executor object @c ex of type @c Ex by + * performing @code auto ex = get_associated_executor(handler); @endcode * - * @li Returns <tt>result.get()</tt>. + * @li Obtains the handler's associated allocator object @c alloc by performing + * @code auto alloc = get_associated_allocator(handler); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs + * @code prefer( + * require(ex, execution::blocking.never), + * execution::relationship.fork, + * execution::allocator(alloc) + * ).execute(std::forward<CompletionHandler>(completion_handler)); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs + * @code ex.post( + * std::forward<CompletionHandler>(completion_handler), + * alloc); @endcode + * + * @par Completion Signature + * @code void() @endcode */ -template <typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - ASIO_MOVE_ARG(CompletionToken) token); +template <ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken> +inline auto post(NullaryToken&& token) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_post>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_post(), token); +} /// Submits a completion token or function object for execution. /** @@ -59,49 +92,122 @@ ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( * The function object is queued for execution, and is never called from the * current thread prior to returning from <tt>post()</tt>. * - * This function has the following effects: + * The use of @c post(), rather than @ref defer(), indicates the caller's + * preference that the function object be eagerly queued for execution. * - * @li Constructs a function object handler of type @c Handler, initialized - * with <tt>handler(forward<CompletionToken>(token))</tt>. + * @param ex The target executor. * - * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, - * initializing the object as <tt>result(handler)</tt>. + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode * - * @li Obtains the handler's associated executor object @c ex1 by performing - * <tt>get_associated_executor(handler)</tt>. + * @returns This function returns <tt>async_initiate<NullaryToken, + * void()>(Init{ex}, token)</tt>, where @c Init is a function object type + * defined as: * - * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. + * @code class Init + * { + * public: + * using executor_type = Executor; + * explicit Init(const Executor& ex) : ex_(ex) {} + * executor_type get_executor() const noexcept { return ex_; } + * template <typename CompletionHandler> + * void operator()(CompletionHandler&& completion_handler) const; + * private: + * Executor ex_; // exposition only + * }; @endcode * - * @li Obtains the handler's associated allocator object @c alloc by performing - * <tt>get_associated_allocator(handler)</tt>. + * The function call operator of @c Init: * - * @li Constructs a function object @c f with a function call operator that - * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by - * <tt>w.reset()</tt>. + * @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by + * performing @code auto ex1 = get_associated_executor(handler, ex); @endcode * - * @li Performs <tt>Executor(ex).post(std::move(f), alloc)</tt>. - * - * @li Returns <tt>result.get()</tt>. + * @li Obtains the handler's associated allocator object @c alloc by performing + * @code auto alloc = get_associated_allocator(handler); @endcode + * + * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a + * function object @c f with a member @c executor_ that is initialised with + * <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c + * handler_ that is a decay-copy of @c completion_handler, and a function call + * operator that performs: + * @code auto a = get_associated_allocator(handler_); + * prefer(executor_, execution::allocator(a)).execute(std::move(handler_)); + * @endcode + * + * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a + * function object @c f with a member @c work_ that is initialised with + * <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of + * @c completion_handler, and a function call operator that performs: + * @code auto a = get_associated_allocator(handler_); + * work_.get_executor().dispatch(std::move(handler_), a); + * work_.reset(); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs + * @code prefer( + * require(ex, execution::blocking.never), + * execution::relationship.fork, + * execution::allocator(alloc) + * ).execute(std::move(f)); @endcode + * + * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs + * @code ex.post(std::move(f), alloc); @endcode + * + * @par Completion Signature + * @code void() @endcode */ -template <typename Executor, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_executor<Executor>::value>::type* = 0); +template <typename Executor, + ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken + = default_completion_token_t<Executor>> +inline auto post(const Executor& ex, + NullaryToken&& token = default_completion_token_t<Executor>(), + constraint_t< + (execution::is_executor<Executor>::value + && can_require<Executor, execution::blocking_t::never_t>::value) + || is_executor<Executor>::value + > = 0) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_post_with_executor<Executor>>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_post_with_executor<Executor>(ex), token); +} /// Submits a completion token or function object for execution. /** - * @returns <tt>post(ctx.get_executor(), forward<CompletionToken>(token))</tt>. + * @param ctx An execution context, from which the target executor is obtained. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler. The function signature of the completion handler must be: + * @code void handler(); @endcode + * + * @returns <tt>post(ctx.get_executor(), forward<NullaryToken>(token))</tt>. + * + * @par Completion Signature + * @code void() @endcode */ -template <typename ExecutionContext, typename CompletionToken> -ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type* = 0); +template <typename ExecutionContext, + ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken + = default_completion_token_t<typename ExecutionContext::executor_type>> +inline auto post(ExecutionContext& ctx, + NullaryToken&& token = default_completion_token_t< + typename ExecutionContext::executor_type>(), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + -> decltype( + async_initiate<NullaryToken, void()>( + declval<detail::initiate_post_with_executor< + typename ExecutionContext::executor_type>>(), token)) +{ + return async_initiate<NullaryToken, void()>( + detail::initiate_post_with_executor< + typename ExecutionContext::executor_type>( + ctx.get_executor()), token); +} } // namespace asio #include "asio/detail/pop_options.hpp" -#include "asio/impl/post.hpp" - #endif // ASIO_POST_HPP diff --git a/3rdparty/asio/include/asio/prefer.hpp b/3rdparty/asio/include/asio/prefer.hpp new file mode 100644 index 00000000000..3b13d4123bf --- /dev/null +++ b/3rdparty/asio/include/asio/prefer.hpp @@ -0,0 +1,577 @@ +// +// prefer.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_PREFER_HPP +#define ASIO_PREFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/prefer_free.hpp" +#include "asio/traits/prefer_member.hpp" +#include "asio/traits/require_free.hpp" +#include "asio/traits/require_member.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { + +/// A customisation point that attempts to apply a property to an object. +/** + * The name <tt>prefer</tt> denotes a customisation point object. The + * expression <tt>asio::prefer(E, P0, Pn...)</tt> for some subexpressions + * <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> represents <tt>N</tt> + * subexpressions (where <tt>N</tt> is 0 or more, and with types <tt>T = + * decay_t<decltype(E)></tt> and <tt>Prop0 = decay_t<decltype(P0)></tt>) is + * expression-equivalent to: + * + * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_preferable</tt> is + * not a well-formed constant expression with value <tt>true</tt>, + * <tt>asio::prefer(E, P0, Pn...)</tt> is ill-formed. + * + * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression + * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a + * well-formed constant expression with value <tt>true</tt>. + * + * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression + * <tt>(E).require(P0)</tt> is a valid expression. + * + * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression + * <tt>require(E, P0)</tt> is a valid expression with overload resolution + * performed in a context that does not include the declaration of the + * <tt>require</tt> customization point object. + * + * @li Otherwise, <tt>(E).prefer(P0)</tt> if <tt>N == 0</tt> and the expression + * <tt>(E).prefer(P0)</tt> is a valid expression. + * + * @li Otherwise, <tt>prefer(E, P0)</tt> if <tt>N == 0</tt> and the expression + * <tt>prefer(E, P0)</tt> is a valid expression with overload resolution + * performed in a context that does not include the declaration of the + * <tt>prefer</tt> customization point object. + * + * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt>. + * + * @li Otherwise, + * <tt>asio::prefer(asio::prefer(E, P0), Pn...)</tt> + * if <tt>N > 0</tt> and the expression + * <tt>asio::prefer(asio::prefer(E, P0), Pn...)</tt> + * is a valid expression. + * + * @li Otherwise, <tt>asio::prefer(E, P0, Pn...)</tt> is ill-formed. + */ +inline constexpr unspecified prefer = unspecified; + +/// A type trait that determines whether a @c prefer expression is well-formed. +/** + * Class template @c can_prefer is a trait that is derived from + * @c true_type if the expression <tt>asio::prefer(std::declval<T>(), + * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type. + */ +template <typename T, typename... Properties> +struct can_prefer : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines whether a @c prefer expression will not throw. +/** + * Class template @c is_nothrow_prefer is a trait that is derived from + * @c true_type if the expression <tt>asio::prefer(std::declval<T>(), + * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type. + */ +template <typename T, typename... Properties> +struct is_nothrow_prefer : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines the result type of a @c prefer expression. +/** + * Class template @c prefer_result is a trait that determines the result + * type of the expression <tt>asio::prefer(std::declval<T>(), + * std::declval<Properties>()...)</tt>. + */ +template <typename T, typename... Properties> +struct prefer_result +{ + /// The result of the @c prefer expression. + typedef automatically_determined type; +}; + +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_prefer_fn { + +using asio::conditional_t; +using asio::decay_t; +using asio::declval; +using asio::enable_if_t; +using asio::is_applicable_property; +using asio::traits::prefer_free; +using asio::traits::prefer_member; +using asio::traits::require_free; +using asio::traits::require_member; +using asio::traits::static_require; + +void prefer(); +void require(); + +enum overload_type +{ + identity, + call_require_member, + call_require_free, + call_prefer_member, + call_prefer_free, + two_props, + n_props, + ill_formed +}; + +template <typename Impl, typename T, typename Properties, + typename = void, typename = void, typename = void, typename = void, + typename = void, typename = void, typename = void> +struct call_traits +{ + static constexpr overload_type overload = ill_formed; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_preferable + >, + enable_if_t< + static_require<T, Property>::is_valid + >> +{ + static constexpr overload_type overload = identity; + static constexpr bool is_noexcept = true; + + typedef T&& result_type; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_preferable + >, + enable_if_t< + !static_require<T, Property>::is_valid + >, + enable_if_t< + require_member<typename Impl::template proxy<T>::type, Property>::is_valid + >> : + require_member<typename Impl::template proxy<T>::type, Property> +{ + static constexpr overload_type overload = call_require_member; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_preferable + >, + enable_if_t< + !static_require<T, Property>::is_valid + >, + enable_if_t< + !require_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + require_free<T, Property>::is_valid + >> : + require_free<T, Property> +{ + static constexpr overload_type overload = call_require_free; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_preferable + >, + enable_if_t< + !static_require<T, Property>::is_valid + >, + enable_if_t< + !require_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + !require_free<T, Property>::is_valid + >, + enable_if_t< + prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid + >> : + prefer_member<typename Impl::template proxy<T>::type, Property> +{ + static constexpr overload_type overload = call_prefer_member; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_preferable + >, + enable_if_t< + !static_require<T, Property>::is_valid + >, + enable_if_t< + !require_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + !require_free<T, Property>::is_valid + >, + enable_if_t< + !prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + prefer_free<T, Property>::is_valid + >> : + prefer_free<T, Property> +{ + static constexpr overload_type overload = call_prefer_free; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_preferable + >, + enable_if_t< + !static_require<T, Property>::is_valid + >, + enable_if_t< + !require_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + !require_free<T, Property>::is_valid + >, + enable_if_t< + !prefer_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + !prefer_free<T, Property>::is_valid + >> +{ + static constexpr overload_type overload = identity; + static constexpr bool is_noexcept = true; + + typedef T&& result_type; +}; + +template <typename Impl, typename T, typename P0, typename P1> +struct call_traits<Impl, T, void(P0, P1), + enable_if_t< + call_traits<Impl, T, void(P0)>::overload != ill_formed + >, + enable_if_t< + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1) + >::overload != ill_formed + >> +{ + static constexpr overload_type overload = two_props; + + static constexpr bool is_noexcept = + ( + call_traits<Impl, T, void(P0)>::is_noexcept + && + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1) + >::is_noexcept + ); + + typedef decay_t< + typename call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1) + >::result_type + > result_type; +}; + +template <typename Impl, typename T, typename P0, + typename P1, typename... PN> +struct call_traits<Impl, T, void(P0, P1, PN...), + enable_if_t< + call_traits<Impl, T, void(P0)>::overload != ill_formed + >, + enable_if_t< + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1, PN...) + >::overload != ill_formed + >> +{ + static constexpr overload_type overload = n_props; + + static constexpr bool is_noexcept = + ( + call_traits<Impl, T, void(P0)>::is_noexcept + && + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1, PN...) + >::is_noexcept + ); + + typedef decay_t< + typename call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1, PN...) + >::result_type + > result_type; +}; + +struct impl +{ + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) \ + && defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + struct type + { + template <typename P> + auto require(P&& p) + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p)) + ); + + template <typename P> + auto prefer(P&& p) + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().prefer(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().prefer(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + // && defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + // && defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + }; + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == identity, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&&) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_require_member, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t).require(static_cast<Property&&>(p)); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_require_free, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return require(static_cast<T&&>(t), static_cast<Property&&>(p)); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_prefer_member, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t).prefer(static_cast<Property&&>(p)); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_prefer_free, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return prefer(static_cast<T&&>(t), static_cast<Property&&>(p)); + } + + template <typename T, typename P0, typename P1> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(P0, P1)>::overload == two_props, + typename call_traits<impl, T, void(P0, P1)>::result_type + > + operator()(T&& t, P0&& p0, P1&& p1) const + noexcept(call_traits<impl, T, void(P0, P1)>::is_noexcept) + { + return (*this)( + (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)), + static_cast<P1&&>(p1)); + } + + template <typename T, typename P0, typename P1, + typename... PN> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(P0, P1, PN...)>::overload == n_props, + typename call_traits<impl, T, void(P0, P1, PN...)>::result_type + > + operator()(T&& t, P0&& p0, P1&& p1, PN&&... pn) const + noexcept(call_traits<impl, T, void(P0, P1, PN...)>::is_noexcept) + { + return (*this)( + (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)), + static_cast<P1&&>(p1), static_cast<PN&&>(pn)...); + } +}; + +template <typename T = impl> +struct static_instance +{ + static const T instance; +}; + +template <typename T> +const T static_instance<T>::instance = {}; + +} // namespace asio_prefer_fn +namespace asio { +namespace { + +static constexpr const asio_prefer_fn::impl& + prefer = asio_prefer_fn::static_instance<>::instance; + +} // namespace + +typedef asio_prefer_fn::impl prefer_t; + +template <typename T, typename... Properties> +struct can_prefer : + integral_constant<bool, + asio_prefer_fn::call_traits< + prefer_t, T, void(Properties...)>::overload + != asio_prefer_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +constexpr bool can_prefer_v + = can_prefer<T, Properties...>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +struct is_nothrow_prefer : + integral_constant<bool, + asio_prefer_fn::call_traits< + prefer_t, T, void(Properties...)>::is_noexcept> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +constexpr bool is_nothrow_prefer_v = is_nothrow_prefer<T, Properties...>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +struct prefer_result +{ + typedef typename asio_prefer_fn::call_traits< + prefer_t, T, void(Properties...)>::result_type type; +}; + +template <typename T, typename... Properties> +using prefer_result_t = typename prefer_result<T, Properties...>::type; + +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_PREFER_HPP diff --git a/3rdparty/asio/include/asio/prepend.hpp b/3rdparty/asio/include/asio/prepend.hpp new file mode 100644 index 00000000000..972b47fd300 --- /dev/null +++ b/3rdparty/asio/include/asio/prepend.hpp @@ -0,0 +1,66 @@ +// +// prepend.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_PREPEND_HPP +#define ASIO_PREPEND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <tuple> +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Completion token type used to specify that the completion handler +/// arguments should be passed additional values before the results of the +/// operation. +template <typename CompletionToken, typename... Values> +class prepend_t +{ +public: + /// Constructor. + template <typename T, typename... V> + constexpr explicit prepend_t(T&& completion_token, V&&... values) + : token_(static_cast<T&&>(completion_token)), + values_(static_cast<V&&>(values)...) + { + } + +//private: + CompletionToken token_; + std::tuple<Values...> values_; +}; + +/// Completion token type used to specify that the completion handler +/// arguments should be passed additional values before the results of the +/// operation. +template <typename CompletionToken, typename... Values> +ASIO_NODISCARD inline constexpr +prepend_t<decay_t<CompletionToken>, decay_t<Values>...> +prepend(CompletionToken&& completion_token, + Values&&... values) +{ + return prepend_t<decay_t<CompletionToken>, decay_t<Values>...>( + static_cast<CompletionToken&&>(completion_token), + static_cast<Values&&>(values)...); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/prepend.hpp" + +#endif // ASIO_PREPEND_HPP diff --git a/3rdparty/asio/include/asio/query.hpp b/3rdparty/asio/include/asio/query.hpp new file mode 100644 index 00000000000..c27d26a4030 --- /dev/null +++ b/3rdparty/asio/include/asio/query.hpp @@ -0,0 +1,311 @@ +// +// query.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_QUERY_HPP +#define ASIO_QUERY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/query_member.hpp" +#include "asio/traits/query_free.hpp" +#include "asio/traits/static_query.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { + +/// A customisation point that queries the value of a property. +/** + * The name <tt>query</tt> denotes a customization point object. The + * expression <tt>asio::query(E, P)</tt> for some + * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T = + * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is + * expression-equivalent to: + * + * @li If <tt>is_applicable_property_v<T, Prop></tt> is not a well-formed + * constant expression with value <tt>true</tt>, <tt>asio::query(E, + * P)</tt> is ill-formed. + * + * @li Otherwise, <tt>Prop::template static_query_v<T></tt> if the expression + * <tt>Prop::template static_query_v<T></tt> is a well-formed constant + * expression. + * + * @li Otherwise, <tt>(E).query(P)</tt> if the expression + * <tt>(E).query(P)</tt> is well-formed. + * + * @li Otherwise, <tt>query(E, P)</tt> if the expression + * <tt>query(E, P)</tt> is a valid expression with overload + * resolution performed in a context that does not include the declaration + * of the <tt>query</tt> customization point object. + * + * @li Otherwise, <tt>asio::query(E, P)</tt> is ill-formed. + */ +inline constexpr unspecified query = unspecified; + +/// A type trait that determines whether a @c query expression is well-formed. +/** + * Class template @c can_query is a trait that is derived from + * @c true_type if the expression <tt>asio::query(std::declval<T>(), + * std::declval<Property>())</tt> is well formed; otherwise @c false_type. + */ +template <typename T, typename Property> +struct can_query : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines whether a @c query expression will +/// not throw. +/** + * Class template @c is_nothrow_query is a trait that is derived from + * @c true_type if the expression <tt>asio::query(std::declval<T>(), + * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type. + */ +template <typename T, typename Property> +struct is_nothrow_query : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines the result type of a @c query expression. +/** + * Class template @c query_result is a trait that determines the result + * type of the expression <tt>asio::query(std::declval<T>(), + * std::declval<Property>())</tt>. + */ +template <typename T, typename Property> +struct query_result +{ + /// The result of the @c query expression. + typedef automatically_determined type; +}; + +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_query_fn { + +using asio::conditional_t; +using asio::decay_t; +using asio::declval; +using asio::enable_if_t; +using asio::is_applicable_property; +using asio::traits::query_free; +using asio::traits::query_member; +using asio::traits::static_query; + +void query(); + +enum overload_type +{ + static_value, + call_member, + call_free, + ill_formed +}; + +template <typename Impl, typename T, typename Properties, + typename = void, typename = void, typename = void, typename = void> +struct call_traits +{ + static constexpr overload_type overload = ill_formed; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + static_query<T, Property>::is_valid + >> : + static_query<T, Property> +{ + static constexpr overload_type overload = static_value; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + !static_query<T, Property>::is_valid + >, + enable_if_t< + query_member<typename Impl::template proxy<T>::type, Property>::is_valid + >> : + query_member<typename Impl::template proxy<T>::type, Property> +{ + static constexpr overload_type overload = call_member; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + !static_query<T, Property>::is_valid + >, + enable_if_t< + !query_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + query_free<T, Property>::is_valid + >> : + query_free<T, Property> +{ + static constexpr overload_type overload = call_free; +}; + +struct impl +{ + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + struct type + { + template <typename P> + auto query(P&& p) + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().query(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + }; + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == static_value, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&&, Property&&) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_query<decay_t<T>, decay_t<Property>>::value(); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_member, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t).query(static_cast<Property&&>(p)); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_free, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return query(static_cast<T&&>(t), static_cast<Property&&>(p)); + } +}; + +template <typename T = impl> +struct static_instance +{ + static const T instance; +}; + +template <typename T> +const T static_instance<T>::instance = {}; + +} // namespace asio_query_fn +namespace asio { +namespace { + +static constexpr const asio_query_fn::impl& + query = asio_query_fn::static_instance<>::instance; + +} // namespace + +typedef asio_query_fn::impl query_t; + +template <typename T, typename Property> +struct can_query : + integral_constant<bool, + asio_query_fn::call_traits<query_t, T, void(Property)>::overload != + asio_query_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +constexpr bool can_query_v = can_query<T, Property>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +struct is_nothrow_query : + integral_constant<bool, + asio_query_fn::call_traits<query_t, T, void(Property)>::is_noexcept> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +constexpr bool is_nothrow_query_v = is_nothrow_query<T, Property>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +struct query_result +{ + typedef typename asio_query_fn::call_traits< + query_t, T, void(Property)>::result_type type; +}; + +template <typename T, typename Property> +using query_result_t = typename query_result<T, Property>::type; + +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_QUERY_HPP diff --git a/3rdparty/asio/include/asio/random_access_file.hpp b/3rdparty/asio/include/asio/random_access_file.hpp new file mode 100644 index 00000000000..c638e336394 --- /dev/null +++ b/3rdparty/asio/include/asio/random_access_file.hpp @@ -0,0 +1,35 @@ +// +// random_access_file.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_RANDOM_ACCESS_FILE_HPP +#define ASIO_RANDOM_ACCESS_FILE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + || defined(GENERATING_DOCUMENTATION) + +#include "asio/basic_random_access_file.hpp" + +namespace asio { + +/// Typedef for the typical usage of a random-access file. +typedef basic_random_access_file<> random_access_file; + +} // namespace asio + +#endif // defined(ASIO_HAS_FILE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_RANDOM_ACCESS_FILE_HPP diff --git a/3rdparty/asio/include/asio/raw_socket_service.hpp b/3rdparty/asio/include/asio/raw_socket_service.hpp deleted file mode 100644 index f8b183d57c7..00000000000 --- a/3rdparty/asio/include/asio/raw_socket_service.hpp +++ /dev/null @@ -1,455 +0,0 @@ -// -// raw_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_RAW_SOCKET_SERVICE_HPP -#define ASIO_RAW_SOCKET_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/type_traits.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/null_socket_service.hpp" -#elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -#else -# include "asio/detail/reactive_socket_service.hpp" -#endif - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a raw socket. -template <typename Protocol> -class raw_socket_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<raw_socket_service<Protocol> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The protocol type. - typedef Protocol protocol_type; - - /// The endpoint type. - typedef typename Protocol::endpoint endpoint_type; - -private: - // The type of the platform-specific implementation. -#if defined(ASIO_WINDOWS_RUNTIME) - typedef detail::null_socket_service<Protocol> service_impl_type; -#elif defined(ASIO_HAS_IOCP) - typedef detail::win_iocp_socket_service<Protocol> service_impl_type; -#else - typedef detail::reactive_socket_service<Protocol> service_impl_type; -#endif - -public: - /// The type of a raw socket. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef typename service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new raw socket service for the specified io_context. - explicit raw_socket_service(asio::io_context& io_context) - : asio::detail::service_base< - raw_socket_service<Protocol> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new raw socket implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new raw socket implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another raw socket implementation. - void move_assign(implementation_type& impl, - raw_socket_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } - - /// Move-construct a new raw socket implementation from another protocol - /// type. - template <typename Protocol1> - void converting_move_construct(implementation_type& impl, - typename raw_socket_service< - Protocol1>::implementation_type& other_impl, - typename enable_if<is_convertible< - Protocol1, Protocol>::value>::type* = 0) - { - service_impl_.template converting_move_construct<Protocol1>( - impl, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a raw socket implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - // Open a new raw socket implementation. - ASIO_SYNC_OP_VOID open(implementation_type& impl, - const protocol_type& protocol, asio::error_code& ec) - { - if (protocol.type() == ASIO_OS_DEF(SOCK_RAW)) - service_impl_.open(impl, protocol, ec); - else - ec = asio::error::invalid_argument; - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Assign an existing native socket to a raw socket. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const protocol_type& protocol, const native_handle_type& native_socket, - asio::error_code& ec) - { - service_impl_.assign(impl, protocol, native_socket, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a raw socket implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native socket implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the socket. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.at_mark(impl, ec); - } - - /// Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.available(impl, ec); - } - - // Bind the raw socket to the specified local endpoint. - ASIO_SYNC_OP_VOID bind(implementation_type& impl, - const endpoint_type& endpoint, asio::error_code& ec) - { - service_impl_.bind(impl, endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Connect the raw socket to the specified endpoint. - ASIO_SYNC_OP_VOID connect(implementation_type& impl, - const endpoint_type& peer_endpoint, asio::error_code& ec) - { - service_impl_.connect(impl, peer_endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Start an asynchronous connect. - template <typename ConnectHandler> - ASIO_INITFN_RESULT_TYPE(ConnectHandler, - void (asio::error_code)) - async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(ConnectHandler) handler) - { - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); - - return init.result.get(); - } - - /// Set a socket option. - template <typename SettableSocketOption> - ASIO_SYNC_OP_VOID set_option(implementation_type& impl, - const SettableSocketOption& option, asio::error_code& ec) - { - service_impl_.set_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get a socket option. - template <typename GettableSocketOption> - ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, - GettableSocketOption& option, asio::error_code& ec) const - { - service_impl_.get_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform an IO control command on the socket. - template <typename IoControlCommand> - ASIO_SYNC_OP_VOID io_control(implementation_type& impl, - IoControlCommand& command, asio::error_code& ec) - { - service_impl_.io_control(impl, command, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the socket. - bool non_blocking(const implementation_type& impl) const - { - return service_impl_.non_blocking(impl); - } - - /// Sets the non-blocking mode of the socket. - ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the native socket implementation. - bool native_non_blocking(const implementation_type& impl) const - { - return service_impl_.native_non_blocking(impl); - } - - /// Sets the non-blocking mode of the native socket implementation. - ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.native_non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the local endpoint. - endpoint_type local_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.local_endpoint(impl, ec); - } - - /// Get the remote endpoint. - endpoint_type remote_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.remote_endpoint(impl, ec); - } - - /// Disable sends or receives on the socket. - ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, - socket_base::shutdown_type what, asio::error_code& ec) - { - service_impl_.shutdown(impl, what, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Wait for the socket to become ready to read, ready to write, or to have - /// pending error conditions. - ASIO_SYNC_OP_VOID wait(implementation_type& impl, - socket_base::wait_type w, asio::error_code& ec) - { - service_impl_.wait(impl, w, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Asynchronously wait for the socket to become ready to read, ready to - /// write, or to have pending error conditions. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, socket_base::wait_type w, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, w, init.completion_handler); - - return init.result.get(); - } - - /// Send the given data to the peer. - template <typename ConstBufferSequence> - std::size_t send(implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.send(impl, buffers, flags, ec); - } - - /// Start an asynchronous send. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) - { - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_send(impl, buffers, flags, init.completion_handler); - - return init.result.get(); - } - - /// Send raw data to the specified endpoint. - template <typename ConstBufferSequence> - std::size_t send_to(implementation_type& impl, - const ConstBufferSequence& buffers, const endpoint_type& destination, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.send_to(impl, buffers, destination, flags, ec); - } - - /// Start an asynchronous send. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send_to(implementation_type& impl, - const ConstBufferSequence& buffers, const endpoint_type& destination, - socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) - { - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_send_to(impl, buffers, - destination, flags, init.completion_handler); - - return init.result.get(); - } - - /// Receive some data from the peer. - template <typename MutableBufferSequence> - std::size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.receive(impl, buffers, flags, ec); - } - - /// Start an asynchronous receive. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) - { - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_receive(impl, buffers, flags, init.completion_handler); - - return init.result.get(); - } - - /// Receive raw data with the endpoint of the sender. - template <typename MutableBufferSequence> - std::size_t receive_from(implementation_type& impl, - const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.receive_from(impl, buffers, sender_endpoint, flags, - ec); - } - - /// Start an asynchronous receive that will get the endpoint of the sender. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive_from(implementation_type& impl, - const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) - { - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_receive_from(impl, buffers, - sender_endpoint, flags, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_RAW_SOCKET_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/read.hpp b/3rdparty/asio/include/asio/read.hpp index 4839934dbab..0eb966af36f 100644 --- a/3rdparty/asio/include/asio/read.hpp +++ b/3rdparty/asio/include/asio/read.hpp @@ -2,7 +2,7 @@ // read.hpp // ~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,7 @@ #include <cstddef> #include "asio/async_result.hpp" #include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" #include "asio/error.hpp" #if !defined(ASIO_NO_EXTENSIONS) @@ -28,12 +29,21 @@ #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + +template <typename> class initiate_async_read; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +template <typename> class initiate_async_read_dynbuf_v1; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +template <typename> class initiate_async_read_dynbuf_v2; + +} // namespace detail /** * @defgroup read asio::read * - * @brief Attempt to read a certain amount of data from a stream before - * returning. + * @brief The @c read function is a composed operation that reads a certain + * amount of data from a stream before returning. */ /*@{*/ @@ -75,9 +85,9 @@ namespace asio { */ template <typename SyncReadStream, typename MutableBufferSequence> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type* = 0); + > = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -118,9 +128,9 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, template <typename SyncReadStream, typename MutableBufferSequence> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, asio::error_code& ec, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type* = 0); + > = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -172,9 +182,9 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type* = 0); + > = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -219,9 +229,11 @@ template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type* = 0); + > = 0); + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) /// Attempt to read a certain amount of data from a stream before returning. /** @@ -250,12 +262,15 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, * s, buffers, * asio::transfer_all()); @endcode */ -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + DynamicBuffer_v1&& buffers, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -283,13 +298,16 @@ std::size_t read(SyncReadStream& s, * s, buffers, * asio::transfer_all(), ec); @endcode */ -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -327,14 +345,17 @@ std::size_t read(SyncReadStream& s, * * @throws asio::system_error Thrown on failure. */ -template <typename SyncReadStream, typename DynamicBuffer, +template <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -373,14 +394,17 @@ std::size_t read(SyncReadStream& s, * @returns The number of bytes read. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ -template <typename SyncReadStream, typename DynamicBuffer, +template <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t read(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) @@ -527,13 +551,169 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b, #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code asio::read( + * s, buffers, + * asio::transfer_all()); @endcode + */ +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code asio::read( + * s, buffers, + * asio::transfer_all(), ec); @endcode + */ +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); /*@}*/ /** * @defgroup async_read asio::async_read * - * @brief Start an asynchronous operation to read a certain amount of data from - * a stream. + * @brief The @c async_read function is a composed asynchronous operation that + * reads a certain amount of data from a stream before completion. */ /*@{*/ @@ -541,9 +721,9 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b, /// stream. /** * This function is used to asynchronously read a certain number of bytes of - * data from a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions is - * true: + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. @@ -563,24 +743,29 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b, * of the buffer sizes indicates the maximum number of bytes to read from the * stream. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes copied into the - * // buffers. If an error occurred, - * // this will be the number of - * // bytes successfully transferred - * // prior to the error. + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -596,24 +781,41 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b, * s, buffers, * asio::transfer_all(), * handler); @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ template <typename AsyncReadStream, typename MutableBufferSequence, - typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type* = 0); + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read<AsyncReadStream>>(), + token, buffers, transfer_all())); /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of - * data from a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions is - * true: + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. @@ -627,7 +829,7 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * of the buffer sizes indicates the maximum number of bytes to read from the * stream. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object @@ -643,22 +845,27 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * return value indicates the maximum number of bytes to be read on the next * call to the stream's async_read_some function. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes copied into the - * // buffers. If an error occurred, - * // this will be the number of - * // bytes successfully transferred - * // prior to the error. + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -669,25 +876,46 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, +template <typename AsyncReadStream, + typename MutableBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< is_mutable_buffer_sequence<MutableBufferSequence>::value - >::type* = 0); + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read<AsyncReadStream>>(), + token, buffers, + static_cast<CompletionCondition&&>(completion_condition))); + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of - * data from a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions is - * true: + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The specified dynamic buffer sequence is full (that is, it has reached * maximum size). @@ -706,49 +934,73 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * @param buffers The dynamic buffer sequence into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes copied into the - * // buffers. If an error occurred, - * // this will be the number of - * // bytes successfully transferred - * // prior to the error. + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note This overload is equivalent to calling: * @code asio::async_read( * s, buffers, * asio::transfer_all(), * handler); @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); +template <typename AsyncReadStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, DynamicBuffer_v1&& buffers, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), transfer_all())); /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of - * data from a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions is - * true: + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The specified dynamic buffer sequence is full (that is, it has reached * maximum size). @@ -767,7 +1019,7 @@ async_read(AsyncReadStream& s, * @param buffers The dynamic buffer sequence into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object @@ -783,34 +1035,60 @@ async_read(AsyncReadStream& s, * return value indicates the maximum number of bytes to be read on the next * call to the stream's async_read_some function. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes copied into the - * // buffers. If an error occurred, - * // this will be the number of - * // bytes successfully transferred - * // prior to the error. + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename DynamicBuffer, - typename CompletionCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, +template <typename AsyncReadStream, + typename DynamicBuffer_v1, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))); #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) @@ -819,9 +1097,9 @@ async_read(AsyncReadStream& s, /// stream. /** * This function is used to asynchronously read a certain number of bytes of - * data from a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions is - * true: + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The supplied buffer is full (that is, it has reached maximum size). * @@ -838,44 +1116,67 @@ async_read(AsyncReadStream& s, * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes copied into the - * // buffers. If an error occurred, - * // this will be the number of - * // bytes successfully transferred - * // prior to the error. + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note This overload is equivalent to calling: * @code asio::async_read( * s, b, * asio::transfer_all(), * handler); @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, - ASIO_MOVE_ARG(ReadHandler) handler); +template <typename AsyncReadStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), transfer_all())); /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of - * data from a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions is - * true: + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The supplied buffer is full (that is, it has reached maximum size). * @@ -892,7 +1193,7 @@ async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object @@ -908,33 +1209,233 @@ async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, * return value indicates the maximum number of bytes to be read on the next * call to the stream's async_read_some function. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes copied into the - * // buffers. If an error occurred, - * // this will be the number of - * // bytes successfully transferred - * // prior to the error. + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename Allocator, - typename CompletionCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, +template <typename AsyncReadStream, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler); + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition))); #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note This overload is equivalent to calling: + * @code asio::async_read( + * s, buffers, + * asio::transfer_all(), + * handler); @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. + */ +template <typename AsyncReadStream, typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), transfer_all())); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. + */ +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_dynbuf_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))); /*@}*/ diff --git a/3rdparty/asio/include/asio/read_at.hpp b/3rdparty/asio/include/asio/read_at.hpp index 16e6af1568c..09a0b22e12e 100644 --- a/3rdparty/asio/include/asio/read_at.hpp +++ b/3rdparty/asio/include/asio/read_at.hpp @@ -2,7 +2,7 @@ // read_at.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,6 +18,7 @@ #include "asio/detail/config.hpp" #include <cstddef> #include "asio/async_result.hpp" +#include "asio/completion_condition.hpp" #include "asio/detail/cstdint.hpp" #include "asio/error.hpp" @@ -28,12 +29,20 @@ #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + +template <typename> class initiate_async_read_at; +#if !defined(ASIO_NO_IOSTREAM) +template <typename> class initiate_async_read_at_streambuf; +#endif // !defined(ASIO_NO_IOSTREAM) + +} // namespace detail /** * @defgroup read_at asio::read_at * - * @brief Attempt to read a certain amount of data at the specified offset - * before returning. + * @brief The @c read_at function is a composed operation that reads a certain + * amount of data at the specified offset before returning. */ /*@{*/ @@ -394,8 +403,8 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, /** * @defgroup async_read_at asio::async_read_at * - * @brief Start an asynchronous operation to read a certain amount of data at - * the specified offset. + * @brief The @c async_read_at function is a composed asynchronous operation + * that reads a certain amount of data at the specified offset. */ /*@{*/ @@ -403,9 +412,10 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of - * data from a random access device at the specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data from a random access device at the specified offset. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. @@ -424,11 +434,13 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * of the buffer sizes indicates the maximum number of bytes to read from the * device. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -439,9 +451,12 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -457,22 +472,40 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * d, 42, buffers, * asio::transfer_all(), * handler); @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessReadDevice type's + * async_read_some_at operation. */ template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, - typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, - const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler); + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>> +auto async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at<AsyncRandomAccessReadDevice>>(), + token, offset, buffers, transfer_all())); /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of - * data from a random access device at the specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data from a random access device at the specified offset. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. @@ -488,7 +521,7 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * of the buffer sizes indicates the maximum number of bytes to read from the * device. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object @@ -504,9 +537,11 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * return value indicates the maximum number of bytes to be read on the next * call to the device's async_read_some_at function. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -517,9 +552,12 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -530,15 +568,34 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessReadDevice type's + * async_read_some_at operation. */ -template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, +template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>> +auto async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler); + ReadToken&& token = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at<AsyncRandomAccessReadDevice>>(), + token, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition))); #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) @@ -547,9 +604,10 @@ async_read_at(AsyncRandomAccessReadDevice& d, /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of - * data from a random access device at the specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data from a random access device at the specified offset. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: * * @li An error occurred. * @@ -563,11 +621,13 @@ async_read_at(AsyncRandomAccessReadDevice& d, * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -578,30 +638,53 @@ async_read_at(AsyncRandomAccessReadDevice& d, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note This overload is equivalent to calling: * @code asio::async_read_at( * d, 42, b, * asio::transfer_all(), * handler); @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessReadDevice type's + * async_read_some_at operation. */ template <typename AsyncRandomAccessReadDevice, typename Allocator, - typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, - basic_streambuf<Allocator>& b, ASIO_MOVE_ARG(ReadHandler) handler); + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>> +auto async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, basic_streambuf<Allocator>& b, + ReadToken&& token = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at_streambuf< + AsyncRandomAccessReadDevice>>(), + token, offset, &b, transfer_all())); /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of - * data from a random access device at the specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data from a random access device at the specified offset. It is an + * initiating function for an @ref asynchronous_operation, and always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: * * @li The completion_condition function object returns 0. * @@ -615,7 +698,7 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object @@ -631,9 +714,11 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * return value indicates the maximum number of bytes to be read on the next * call to the device's async_read_some_at function. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -644,18 +729,40 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessReadDevice type's + * async_read_some_at operation. */ -template <typename AsyncRandomAccessReadDevice, typename Allocator, - typename CompletionCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, - uint64_t offset, basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(ReadHandler) handler); +template <typename AsyncRandomAccessReadDevice, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>> +auto async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, + basic_streambuf<Allocator>& b, CompletionCondition completion_condition, + ReadToken&& token = default_completion_token_t< + typename AsyncRandomAccessReadDevice::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_at_streambuf< + AsyncRandomAccessReadDevice>>(), + token, offset, &b, + static_cast<CompletionCondition&&>(completion_condition))); #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) diff --git a/3rdparty/asio/include/asio/read_until.hpp b/3rdparty/asio/include/asio/read_until.hpp index 93bf96b38c7..97abbdbf0ea 100644 --- a/3rdparty/asio/include/asio/read_until.hpp +++ b/3rdparty/asio/include/asio/read_until.hpp @@ -2,7 +2,7 @@ // read_until.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,7 @@ #include <cstddef> #include <string> #include "asio/async_result.hpp" +#include "asio/buffer.hpp" #include "asio/detail/regex_fwd.hpp" #include "asio/detail/string_view.hpp" #include "asio/detail/type_traits.hpp" @@ -31,19 +32,34 @@ #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { -namespace detail +char (&has_result_type_helper(...))[2]; + +template <typename T> +char has_result_type_helper(T*, typename T::result_type* = 0); + +template <typename T> +struct has_result_type { - char (&has_result_type_helper(...))[2]; + enum { value = (sizeof((has_result_type_helper)((T*)(0))) == 1) }; +}; - template <typename T> - char has_result_type_helper(T*, typename T::result_type* = 0); +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +template <typename> class initiate_async_read_until_delim_v1; +template <typename> class initiate_async_read_until_delim_string_v1; +#if defined(ASIO_HAS_BOOST_REGEX) +template <typename> class initiate_async_read_until_expr_v1; +#endif // defined(ASIO_HAS_BOOST_REGEX) +template <typename> class initiate_async_read_until_match_v1; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +template <typename> class initiate_async_read_until_delim_v2; +template <typename> class initiate_async_read_until_delim_string_v2; +#if defined(ASIO_HAS_BOOST_REGEX) +template <typename> class initiate_async_read_until_expr_v2; +#endif // defined(ASIO_HAS_BOOST_REGEX) +template <typename> class initiate_async_read_until_match_v2; - template <typename T> - struct has_result_type - { - enum { value = (sizeof((has_result_type_helper)((T*)(0))) == 1) }; - }; } // namespace detail /// Type trait used to determine whether a type can be used as a match condition @@ -57,8 +73,7 @@ struct is_match_condition #else enum { - value = asio::is_function< - typename asio::remove_pointer<T>::type>::value + value = asio::is_function<remove_pointer_t<T>>::value || detail::has_result_type<T>::value }; #endif @@ -67,12 +82,15 @@ struct is_match_condition /** * @defgroup read_until asio::read_until * - * @brief Read data into a dynamic buffer sequence, or into a streambuf, until - * it contains a delimiter, matches a regular expression, or a function object - * indicates a match. + * @brief The @c read_until function is a composed operation that reads data + * into a dynamic buffer sequence, or into a streambuf, until it contains a + * delimiter, matches a regular expression, or a function object indicates a + * match. */ /*@{*/ +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// Read data into a dynamic buffer sequence until it contains a specified /// delimiter. /** @@ -110,7 +128,7 @@ struct is_match_condition * @par Example * To read data into a @c std::string until a newline is encountered: * @code std::string data; - * std::string n = asio::read_until(s, + * std::size_t n = asio::read_until(s, * asio::dynamic_buffer(data), '\n'); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -126,9 +144,15 @@ struct is_match_condition * This data may be the start of a new line, to be extracted by a subsequent * @c read_until operation. */ -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim); + DynamicBuffer_v1&& buffers, char delim, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Read data into a dynamic buffer sequence until it contains a specified /// delimiter. @@ -164,10 +188,16 @@ std::size_t read_until(SyncReadStream& s, * typically leave that data in the dynamic buffer sequence for a subsequent * read_until operation to examine. */ -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - char delim, asio::error_code& ec); + DynamicBuffer_v1&& buffers, + char delim, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Read data into a dynamic buffer sequence until it contains a specified /// delimiter. @@ -204,7 +234,7 @@ std::size_t read_until(SyncReadStream& s, * @par Example * To read data into a @c std::string until a CR-LF sequence is encountered: * @code std::string data; - * std::string n = asio::read_until(s, + * std::size_t n = asio::read_until(s, * asio::dynamic_buffer(data), "\r\n"); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -220,10 +250,16 @@ std::size_t read_until(SyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c read_until operation. */ -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_STRING_VIEW_PARAM delim); + DynamicBuffer_v1&& buffers, + ASIO_STRING_VIEW_PARAM delim, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Read data into a dynamic buffer sequence until it contains a specified /// delimiter. @@ -259,11 +295,17 @@ std::size_t read_until(SyncReadStream& s, * typically leave that data in the dynamic buffer sequence for a subsequent * read_until operation to examine. */ -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, ASIO_STRING_VIEW_PARAM delim, - asio::error_code& ec); + asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); #if !defined(ASIO_NO_EXTENSIONS) #if defined(ASIO_HAS_BOOST_REGEX) \ @@ -307,7 +349,7 @@ std::size_t read_until(SyncReadStream& s, * @par Example * To read data into a @c std::string until a CR-LF sequence is encountered: * @code std::string data; - * std::string n = asio::read_until(s, + * std::size_t n = asio::read_until(s, * asio::dynamic_buffer(data), boost::regex("\r\n")); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -323,10 +365,15 @@ std::size_t read_until(SyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c read_until operation. */ -template <typename SyncReadStream, typename DynamicBuffer> -std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr); +template <typename SyncReadStream, typename DynamicBuffer_v1, typename Traits> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v1&& buffers, + const boost::basic_regex<char, Traits>& expr, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Read data into a dynamic buffer sequence until some part of the data it /// contains matches a regular expression. @@ -364,10 +411,15 @@ std::size_t read_until(SyncReadStream& s, * expression. An application will typically leave that data in the dynamic * buffer sequence for a subsequent read_until operation to examine. */ -template <typename SyncReadStream, typename DynamicBuffer> -std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr, asio::error_code& ec); +template <typename SyncReadStream, typename DynamicBuffer_v1, typename Traits> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v1&& buffers, + const boost::basic_regex<char, Traits>& expr, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); #endif // defined(ASIO_HAS_BOOST_REGEX) // || defined(GENERATING_DOCUMENTATION) @@ -400,7 +452,7 @@ std::size_t read_until(SyncReadStream& s, * @code pair<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: - * @code buffers_iterator<typename DynamicBuffer::const_buffers_type> + * @code buffers_iterator<typename DynamicBuffer_v1::const_buffers_type> * @endcode * The iterator parameters @c begin and @c end define the range of bytes to be * scanned to determine whether there is a match. The @c first member of the @@ -475,11 +527,19 @@ std::size_t read_until(SyncReadStream& s, * @endcode */ template <typename SyncReadStream, - typename DynamicBuffer, typename MatchCondition> + typename DynamicBuffer_v1, typename MatchCondition> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, MatchCondition match_condition, - typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + constraint_t< + is_match_condition<MatchCondition>::value + > = 0, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Read data into a dynamic buffer sequence until a function object indicates a /// match. @@ -508,7 +568,7 @@ std::size_t read_until(SyncReadStream& s, * @code pair<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: - * @code buffers_iterator<DynamicBuffer::const_buffers_type> + * @code buffers_iterator<DynamicBuffer_v1::const_buffers_type> * @endcode * The iterator parameters @c begin and @c end define the range of bytes to be * scanned to determine whether there is a match. The @c first member of the @@ -535,11 +595,19 @@ std::size_t read_until(SyncReadStream& s, * function objects. */ template <typename SyncReadStream, - typename DynamicBuffer, typename MatchCondition> + typename DynamicBuffer_v1, typename MatchCondition> std::size_t read_until(SyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, MatchCondition match_condition, asio::error_code& ec, - typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + constraint_t< + is_match_condition<MatchCondition>::value + > = 0, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); #if !defined(ASIO_NO_IOSTREAM) @@ -584,8 +652,8 @@ std::size_t read_until(SyncReadStream& s, * contains the delimiter: * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -671,8 +739,8 @@ std::size_t read_until(SyncReadStream& s, * contains the delimiter: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -764,16 +832,17 @@ std::size_t read_until(SyncReadStream& s, * contains the data which matched the regular expression: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * match, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c read_until operation. */ -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename Allocator, typename Traits> std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr); + asio::basic_streambuf<Allocator>& b, + const boost::basic_regex<char, Traits>& expr); /// Read data into a streambuf until some part of the data it contains matches /// a regular expression. @@ -808,9 +877,10 @@ std::size_t read_until(SyncReadStream& s, * application will typically leave that data in the streambuf for a subsequent * read_until operation to examine. */ -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename Allocator, typename Traits> std::size_t read_until(SyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + asio::basic_streambuf<Allocator>& b, + const boost::basic_regex<char, Traits>& expr, asio::error_code& ec); #endif // defined(ASIO_HAS_BOOST_REGEX) @@ -919,7 +989,7 @@ std::size_t read_until(SyncReadStream& s, template <typename SyncReadStream, typename Allocator, typename MatchCondition> std::size_t read_until(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, - typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + constraint_t<is_match_condition<MatchCondition>::value> = 0); /// Read data into a streambuf until a function object indicates a match. /** @@ -976,29 +1046,522 @@ template <typename SyncReadStream, typename Allocator, typename MatchCondition> std::size_t read_until(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, asio::error_code& ec, - typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + constraint_t<is_match_condition<MatchCondition>::value> = 0); #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @throws asio::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a newline is encountered: + * @code std::string data; + * std::size_t n = asio::read_until(s, + * asio::dynamic_buffer(data), '\n'); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::size_t n = asio::read_until(s, + * asio::dynamic_buffer(data), "\r\n"); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + ASIO_STRING_VIEW_PARAM delim, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +#if !defined(ASIO_NO_EXTENSIONS) +#if defined(ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. + * + * @throws asio::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::size_t n = asio::read_until(s, + * asio::dynamic_buffer(data), boost::regex("\r\n")); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2, typename Traits> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::basic_regex<char, Traits>& expr, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. Returns 0 + * if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBuffer_v2, typename Traits> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::basic_regex<char, Traits>& expr, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +#endif // defined(ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. + +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<typename DynamicBuffer_v2::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @returns The number of bytes in the dynamic_buffer's get area that + * have been fully consumed by the match function. + * + * @throws asio::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To read data into a dynamic buffer sequence until whitespace is encountered: + * @code typedef asio::buffers_iterator< + * asio::const_buffers_1> iterator; + * + * std::pair<iterator, bool> + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * std::string data; + * asio::read_until(s, data, match_whitespace); + * @endcode + * + * To read data into a @c std::string until a matching character is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template <typename Iterator> + * std::pair<Iterator, bool> operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition<match_char> + * : public boost::true_type {}; + * } // namespace asio + * ... + * std::string data; + * asio::read_until(s, data, match_char('a')); + * @endcode + */ +template <typename SyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, + constraint_t< + is_match_condition<MatchCondition>::value + > = 0, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<DynamicBuffer_v2::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area that + * have been fully consumed by the match function. Returns 0 if an error + * occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + */ +template <typename SyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, asio::error_code& ec, + constraint_t< + is_match_condition<MatchCondition>::value + > = 0, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +#endif // !defined(ASIO_NO_EXTENSIONS) /*@}*/ /** * @defgroup async_read_until asio::async_read_until * - * @brief Start an asynchronous operation to read data into a dynamic buffer - * sequence, or into a streambuf, until it contains a delimiter, matches a - * regular expression, or a function object indicates a match. + * @brief The @c async_read_until function is a composed asynchronous operation + * that reads data into a dynamic buffer sequence, or into a streambuf, until + * it contains a delimiter, matches a regular expression, or a function object + * indicates a match. */ /*@{*/ +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + /// Start an asynchronous operation to read data into a dynamic buffer sequence /// until it contains a specified delimiter. /** * This function is used to asynchronously read data into the specified dynamic * buffer sequence until the dynamic buffer sequence's get area contains the - * specified delimiter. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * specified delimiter. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The get area of the dynamic buffer sequence contains the specified * delimiter. @@ -1019,26 +1582,30 @@ std::size_t read_until(SyncReadStream& s, * @param buffers The dynamic buffer sequence into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param delim The delimiter character. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // The number of bytes in the dynamic buffer sequence's * // get area up to and including the delimiter. - * // 0 if an error occurred. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note After a successful async_read_until operation, the dynamic buffer * sequence may contain additional data beyond the delimiter. An application @@ -1072,23 +1639,46 @@ std::size_t read_until(SyncReadStream& s, * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - char delim, ASIO_MOVE_ARG(ReadHandler) handler); +template <typename AsyncReadStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, + DynamicBuffer_v1&& buffers, char delim, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), delim)); /// Start an asynchronous operation to read data into a dynamic buffer sequence /// until it contains a specified delimiter. /** * This function is used to asynchronously read data into the specified dynamic * buffer sequence until the dynamic buffer sequence's get area contains the - * specified delimiter. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * specified delimiter. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The get area of the dynamic buffer sequence contains the specified * delimiter. @@ -1109,26 +1699,30 @@ async_read_until(AsyncReadStream& s, * @param buffers The dynamic buffer sequence into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param delim The delimiter string. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // The number of bytes in the dynamic buffer sequence's * // get area up to and including the delimiter. - * // 0 if an error occurred. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note After a successful async_read_until operation, the dynamic buffer * sequence may contain additional data beyond the delimiter. An application @@ -1162,15 +1756,40 @@ async_read_until(AsyncReadStream& s, * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, +template <typename AsyncReadStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, + DynamicBuffer_v1&& buffers, ASIO_STRING_VIEW_PARAM delim, - ASIO_MOVE_ARG(ReadHandler) handler); + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_string_v1< + AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<std::string>(delim))); #if !defined(ASIO_NO_EXTENSIONS) #if defined(ASIO_HAS_BOOST_REGEX) \ @@ -1181,9 +1800,10 @@ async_read_until(AsyncReadStream& s, /** * This function is used to asynchronously read data into the specified dynamic * buffer sequence until the dynamic buffer sequence's get area contains some - * data that matches a regular expression. The function call always returns - * immediately. The asynchronous operation will continue until one of the - * following conditions is true: + * data that matches a regular expression. It is an initiating function for an + * @ref asynchronous_operation, and always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: * * @li A substring of the dynamic buffer sequence's get area matches the regular * expression. @@ -1205,13 +1825,15 @@ async_read_until(AsyncReadStream& s, * @param buffers The dynamic buffer sequence into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param expr The regular expression. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -1223,9 +1845,12 @@ async_read_until(AsyncReadStream& s, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note After a successful async_read_until operation, the dynamic buffer * sequence may contain additional data beyond that which matched the regular @@ -1260,15 +1885,37 @@ async_read_until(AsyncReadStream& s, * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr, - ASIO_MOVE_ARG(ReadHandler) handler); +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename Traits, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, DynamicBuffer_v1&& buffers, + const boost::basic_regex<char, Traits>& expr, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_expr_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), expr)); #endif // defined(ASIO_HAS_BOOST_REGEX) // || defined(GENERATING_DOCUMENTATION) @@ -1279,9 +1926,9 @@ async_read_until(AsyncReadStream& s, * This function is used to asynchronously read data into the specified dynamic * buffer sequence until a user-defined match condition function object, when * applied to the data contained in the dynamic buffer sequence, indicates a - * successful match. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * successful match. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li The match condition function object returns a std::pair where the second * element evaluates to true. @@ -1302,14 +1949,14 @@ async_read_until(AsyncReadStream& s, * @param buffers The dynamic buffer sequence into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param match_condition The function object to be called to determine whether * a match exists. The signature of the function object must be: * @code pair<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: - * @code buffers_iterator<typename DynamicBuffer::const_buffers_type> + * @code buffers_iterator<typename DynamicBuffer_v1::const_buffers_type> * @endcode * The iterator parameters @c begin and @c end define the range of bytes to be * scanned to determine whether there is a match. The @c first member of the @@ -1319,9 +1966,11 @@ async_read_until(AsyncReadStream& s, * @c second member of the return value is true if a match has been found, false * otherwise. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -1332,15 +1981,18 @@ async_read_until(AsyncReadStream& s, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * @note After a successful async_read_until operation, the dynamic buffer * sequence may contain additional data beyond that which matched the function * object. An application will typically leave that data in the dynamic buffer * sequence for a subsequent async_read_until operation to examine. * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a * @c result_type typedef. It must be specialised for other user-defined @@ -1400,15 +2052,42 @@ async_read_until(AsyncReadStream& s, * std::string data; * asio::async_read_until(s, data, match_char('a'), handler); * @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename DynamicBuffer, - typename MatchCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); +template <typename AsyncReadStream, + typename DynamicBuffer_v1, typename MatchCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, + DynamicBuffer_v1&& buffers, MatchCondition match_condition, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_match_condition<MatchCondition>::value + > = 0, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_match_v1<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + match_condition)); #if !defined(ASIO_NO_IOSTREAM) @@ -1417,8 +2096,9 @@ async_read_until(AsyncReadStream& s, /** * This function is used to asynchronously read data into the specified * streambuf until the streambuf's get area contains the specified delimiter. - * The function call always returns immediately. The asynchronous operation - * will continue until one of the following conditions is true: + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. The asynchronous operation will continue until one of + * the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * @@ -1437,13 +2117,15 @@ async_read_until(AsyncReadStream& s, * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains - * valid until the handler is called. + * valid until the completion handler is called. * * @param delim The delimiter character. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -1454,9 +2136,12 @@ async_read_until(AsyncReadStream& s, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond the delimiter. An application will typically @@ -1483,27 +2168,46 @@ async_read_until(AsyncReadStream& s, * @c b contains the delimiter: * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, - char delim, ASIO_MOVE_ARG(ReadHandler) handler); +template <typename AsyncReadStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), delim)); /// Start an asynchronous operation to read data into a streambuf until it /// contains a specified delimiter. /** * This function is used to asynchronously read data into the specified * streambuf until the streambuf's get area contains the specified delimiter. - * The function call always returns immediately. The asynchronous operation - * will continue until one of the following conditions is true: + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. The asynchronous operation will continue until one of + * the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * @@ -1522,13 +2226,15 @@ async_read_until(AsyncReadStream& s, * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains - * valid until the handler is called. + * valid until the completion handler is called. * * @param delim The delimiter string. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -1539,9 +2245,12 @@ async_read_until(AsyncReadStream& s, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond the delimiter. An application will typically @@ -1568,20 +2277,40 @@ async_read_until(AsyncReadStream& s, * @c b contains the delimiter: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, +template <typename AsyncReadStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, asio::basic_streambuf<Allocator>& b, ASIO_STRING_VIEW_PARAM delim, - ASIO_MOVE_ARG(ReadHandler) handler); + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_string_v1< + AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), + static_cast<std::string>(delim))); #if defined(ASIO_HAS_BOOST_REGEX) \ || defined(GENERATING_DOCUMENTATION) @@ -1591,9 +2320,9 @@ async_read_until(AsyncReadStream& s, /** * This function is used to asynchronously read data into the specified * streambuf until the streambuf's get area contains some data that matches a - * regular expression. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * regular expression. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li A substring of the streambuf's get area matches the regular expression. * @@ -1613,13 +2342,15 @@ async_read_until(AsyncReadStream& s, * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains - * valid until the handler is called. + * valid until the completion handler is called. * * @param expr The regular expression. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -1631,9 +2362,12 @@ async_read_until(AsyncReadStream& s, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond that which matched the regular expression. An @@ -1661,19 +2395,38 @@ async_read_until(AsyncReadStream& s, * @c b contains the data which matched the regular expression: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * match, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, const boost::regex& expr, - ASIO_MOVE_ARG(ReadHandler) handler); +template <typename AsyncReadStream, typename Allocator, typename Traits, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + const boost::basic_regex<char, Traits>& expr, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_expr_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), expr)); #endif // defined(ASIO_HAS_BOOST_REGEX) // || defined(GENERATING_DOCUMENTATION) @@ -1683,9 +2436,10 @@ async_read_until(AsyncReadStream& s, /** * This function is used to asynchronously read data into the specified * streambuf until a user-defined match condition function object, when applied - * to the data contained in the streambuf, indicates a successful match. The - * function call always returns immediately. The asynchronous operation will - * continue until one of the following conditions is true: + * to the data contained in the streambuf, indicates a successful match. It is + * an initiating function for an @ref asynchronous_operation, and always + * returns immediately. The asynchronous operation will continue until one of + * the following conditions is true: * * @li The match condition function object returns a std::pair where the second * element evaluates to true. @@ -1720,9 +2474,11 @@ async_read_until(AsyncReadStream& s, * @c second member of the return value is true if a match has been found, false * otherwise. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -1733,15 +2489,18 @@ async_read_until(AsyncReadStream& s, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond that which matched the function object. An * application will typically leave that data in the streambuf for a subsequent * async_read_until operation to examine. * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a * @c result_type typedef. It must be specialised for other user-defined @@ -1800,18 +2559,559 @@ async_read_until(AsyncReadStream& s, * asio::streambuf b; * asio::async_read_until(s, b, match_char('a'), handler); * @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. */ -template <typename AsyncReadStream, typename Allocator, - typename MatchCondition, typename ReadHandler> -ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, - asio::basic_streambuf<Allocator>& b, - MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); +template <typename AsyncReadStream, typename Allocator, typename MatchCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t<is_match_condition<MatchCondition>::value> = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_match_v1<AsyncReadStream>>(), + token, basic_streambuf_ref<Allocator>(b), match_condition)); #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param delim The delimiter character. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a newline is + * encountered: + * @code std::string data; + * ... + * void handler(const asio::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * asio::async_read_until(s, data, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. + */ +template <typename AsyncReadStream, typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, char delim, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), delim)); + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param delim The delimiter string. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const asio::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * asio::async_read_until(s, data, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. + */ +template <typename AsyncReadStream, typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + ASIO_STRING_VIEW_PARAM delim, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_delim_string_v2< + AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<std::string>(delim))); + +#if !defined(ASIO_NO_EXTENSIONS) +#if defined(ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until some part of its data matches a regular expression. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains some + * data that matches a regular expression. It is an initiating function for an + * @ref asynchronous_operation, and always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the regular + * expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains data that matches + * the regular expression, this asynchronous operation completes immediately. + * The program must ensure that the stream performs no other read operations + * (such as async_read, async_read_until, the stream's async_read_some + * function, or any other composed operations that perform reads) until this + * operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param expr The regular expression. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer + * // sequence's get area up to and including the + * // substring that matches the regular expression. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const asio::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * asio::async_read_until(s, data, + * boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the match, + * so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. + */ +template <typename AsyncReadStream, typename DynamicBuffer_v2, typename Traits, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::basic_regex<char, Traits>& expr, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_expr_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), expr)); + +#endif // defined(ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until a function object indicates a match. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until a user-defined match condition function object, when + * applied to the data contained in the dynamic buffer sequence, indicates a + * successful match. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the match condition function object already indicates a match, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<typename DynamicBuffer_v2::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area that have been fully consumed by the match + * // function. O if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the function + * object. An application will typically leave that data in the dynamic buffer + * sequence for a subsequent async_read_until operation to examine. + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To asynchronously read data into a @c std::string until whitespace is + * encountered: + * @code typedef asio::buffers_iterator< + * asio::const_buffers_1> iterator; + * + * std::pair<iterator, bool> + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * void handler(const asio::error_code& e, std::size_t size); + * ... + * std::string data; + * asio::async_read_until(s, data, match_whitespace, handler); + * @endcode + * + * To asynchronously read data into a @c std::string until a matching character + * is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template <typename Iterator> + * std::pair<Iterator, bool> operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition<match_char> + * : public boost::true_type {}; + * } // namespace asio + * ... + * void handler(const asio::error_code& e, std::size_t size); + * ... + * std::string data; + * asio::async_read_until(s, data, match_char('a'), handler); + * @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncReadStream type's + * @c async_read_some operation. + */ +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t< + typename AsyncReadStream::executor_type>> +auto async_read_until(AsyncReadStream& s, + DynamicBuffer_v2 buffers, MatchCondition match_condition, + ReadToken&& token = default_completion_token_t< + typename AsyncReadStream::executor_type>(), + constraint_t< + is_match_condition<MatchCondition>::value + > = 0, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_read_until_match_v2<AsyncReadStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), match_condition)); + +#endif // !defined(ASIO_NO_EXTENSIONS) /*@}*/ diff --git a/3rdparty/asio/include/asio/readable_pipe.hpp b/3rdparty/asio/include/asio/readable_pipe.hpp new file mode 100644 index 00000000000..19101c28702 --- /dev/null +++ b/3rdparty/asio/include/asio/readable_pipe.hpp @@ -0,0 +1,35 @@ +// +// readable_pipe.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_READABLE_PIPE_HPP +#define ASIO_READABLE_PIPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PIPE) \ + || defined(GENERATING_DOCUMENTATION) + +#include "asio/basic_readable_pipe.hpp" + +namespace asio { + +/// Typedef for the typical usage of a readable pipe. +typedef basic_readable_pipe<> readable_pipe; + +} // namespace asio + +#endif // defined(ASIO_HAS_PIPE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_READABLE_PIPE_HPP diff --git a/3rdparty/asio/include/asio/recycling_allocator.hpp b/3rdparty/asio/include/asio/recycling_allocator.hpp new file mode 100644 index 00000000000..b3986c0242e --- /dev/null +++ b/3rdparty/asio/include/asio/recycling_allocator.hpp @@ -0,0 +1,138 @@ +// +// recycling_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_RECYCLING_ALLOCATOR_HPP +#define ASIO_RECYCLING_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/recycling_allocator.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// An allocator that caches memory blocks in thread-local storage for reuse. +/** + * The @recycling_allocator uses a simple strategy where a limited number of + * small memory blocks are cached in thread-local storage, if the current + * thread is running an @c io_context or is part of a @c thread_pool. + */ +template <typename T> +class recycling_allocator +{ +public: + /// The type of object allocated by the recycling allocator. + typedef T value_type; + + /// Rebind the allocator to another value_type. + template <typename U> + struct rebind + { + /// The rebound @c allocator type. + typedef recycling_allocator<U> other; + }; + + /// Default constructor. + constexpr recycling_allocator() noexcept + { + } + + /// Converting constructor. + template <typename U> + constexpr recycling_allocator( + const recycling_allocator<U>&) noexcept + { + } + + /// Equality operator. Always returns true. + constexpr bool operator==( + const recycling_allocator&) const noexcept + { + return true; + } + + /// Inequality operator. Always returns false. + constexpr bool operator!=( + const recycling_allocator&) const noexcept + { + return false; + } + + /// Allocate memory for the specified number of values. + T* allocate(std::size_t n) + { + return detail::recycling_allocator<T>().allocate(n); + } + + /// Deallocate memory for the specified number of values. + void deallocate(T* p, std::size_t n) + { + detail::recycling_allocator<T>().deallocate(p, n); + } +}; + +/// A proto-allocator that caches memory blocks in thread-local storage for +/// reuse. +/** + * The @recycling_allocator uses a simple strategy where a limited number of + * small memory blocks are cached in thread-local storage, if the current + * thread is running an @c io_context or is part of a @c thread_pool. + */ +template <> +class recycling_allocator<void> +{ +public: + /// No values are allocated by a proto-allocator. + typedef void value_type; + + /// Rebind the allocator to another value_type. + template <typename U> + struct rebind + { + /// The rebound @c allocator type. + typedef recycling_allocator<U> other; + }; + + /// Default constructor. + constexpr recycling_allocator() noexcept + { + } + + /// Converting constructor. + template <typename U> + constexpr recycling_allocator( + const recycling_allocator<U>&) noexcept + { + } + + /// Equality operator. Always returns true. + constexpr bool operator==( + const recycling_allocator&) const noexcept + { + return true; + } + + /// Inequality operator. Always returns false. + constexpr bool operator!=( + const recycling_allocator&) const noexcept + { + return false; + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_RECYCLING_ALLOCATOR_HPP diff --git a/3rdparty/asio/include/asio/redirect_error.hpp b/3rdparty/asio/include/asio/redirect_error.hpp new file mode 100644 index 00000000000..524bd0b99a1 --- /dev/null +++ b/3rdparty/asio/include/asio/redirect_error.hpp @@ -0,0 +1,64 @@ +// +// redirect_error.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_REDIRECT_ERROR_HPP +#define ASIO_REDIRECT_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// A @ref completion_token adapter used to specify that an error produced by an +/// asynchronous operation is captured to an error_code variable. +/** + * The redirect_error_t class is used to indicate that any error_code produced + * by an asynchronous operation is captured to a specified variable. + */ +template <typename CompletionToken> +class redirect_error_t +{ +public: + /// Constructor. + template <typename T> + redirect_error_t(T&& completion_token, asio::error_code& ec) + : token_(static_cast<T&&>(completion_token)), + ec_(ec) + { + } + +//private: + CompletionToken token_; + asio::error_code& ec_; +}; + +/// Adapt a @ref completion_token to capture error_code values to a variable. +template <typename CompletionToken> +inline redirect_error_t<decay_t<CompletionToken>> redirect_error( + CompletionToken&& completion_token, asio::error_code& ec) +{ + return redirect_error_t<decay_t<CompletionToken>>( + static_cast<CompletionToken&&>(completion_token), ec); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/redirect_error.hpp" + +#endif // ASIO_REDIRECT_ERROR_HPP diff --git a/3rdparty/asio/include/asio/registered_buffer.hpp b/3rdparty/asio/include/asio/registered_buffer.hpp new file mode 100644 index 00000000000..f563277b30a --- /dev/null +++ b/3rdparty/asio/include/asio/registered_buffer.hpp @@ -0,0 +1,344 @@ +// +// registered_buffer.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_REGISTERED_BUFFER_HPP +#define ASIO_REGISTERED_BUFFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/buffer.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class buffer_registration_base; + +} // namespace detail + +class const_registered_buffer; + +/// Type used to identify a registered buffer. +class registered_buffer_id +{ +public: + /// The native buffer identifier type. + typedef int native_handle_type; + + /// Default constructor creates an invalid registered buffer identifier. + registered_buffer_id() noexcept + : scope_(0), + index_(-1) + { + } + + /// Get the native buffer identifier type. + native_handle_type native_handle() const noexcept + { + return index_; + } + + /// Compare two IDs for equality. + friend bool operator==(const registered_buffer_id& lhs, + const registered_buffer_id& rhs) noexcept + { + return lhs.scope_ == rhs.scope_ && lhs.index_ == rhs.index_; + } + + /// Compare two IDs for equality. + friend bool operator!=(const registered_buffer_id& lhs, + const registered_buffer_id& rhs) noexcept + { + return lhs.scope_ != rhs.scope_ || lhs.index_ != rhs.index_; + } + +private: + friend class detail::buffer_registration_base; + + // Hidden constructor used by buffer registration. + registered_buffer_id(const void* scope, int index) noexcept + : scope_(scope), + index_(index) + { + } + + const void* scope_; + int index_; +}; + +/// Holds a registered buffer over modifiable data. +/** + * Satisfies the @c MutableBufferSequence type requirements. + */ +class mutable_registered_buffer +{ +public: + /// Default constructor creates an invalid registered buffer. + mutable_registered_buffer() noexcept + : buffer_(), + id_() + { + } + + /// Get the underlying mutable buffer. + const mutable_buffer& buffer() const noexcept + { + return buffer_; + } + + /// Get a pointer to the beginning of the memory range. + /** + * @returns <tt>buffer().data()</tt>. + */ + void* data() const noexcept + { + return buffer_.data(); + } + + /// Get the size of the memory range. + /** + * @returns <tt>buffer().size()</tt>. + */ + std::size_t size() const noexcept + { + return buffer_.size(); + } + + /// Get the registered buffer identifier. + const registered_buffer_id& id() const noexcept + { + return id_; + } + + /// Move the start of the buffer by the specified number of bytes. + mutable_registered_buffer& operator+=(std::size_t n) noexcept + { + buffer_ += n; + return *this; + } + +private: + friend class detail::buffer_registration_base; + + // Hidden constructor used by buffer registration and operators. + mutable_registered_buffer(const mutable_buffer& b, + const registered_buffer_id& i) noexcept + : buffer_(b), + id_(i) + { + } + +#if !defined(GENERATING_DOCUMENTATION) + friend mutable_registered_buffer buffer( + const mutable_registered_buffer& b, std::size_t n) noexcept; +#endif // !defined(GENERATING_DOCUMENTATION) + + mutable_buffer buffer_; + registered_buffer_id id_; +}; + +/// Holds a registered buffer over non-modifiable data. +/** + * Satisfies the @c ConstBufferSequence type requirements. + */ +class const_registered_buffer +{ +public: + /// Default constructor creates an invalid registered buffer. + const_registered_buffer() noexcept + : buffer_(), + id_() + { + } + + /// Construct a non-modifiable buffer from a modifiable one. + const_registered_buffer( + const mutable_registered_buffer& b) noexcept + : buffer_(b.buffer()), + id_(b.id()) + { + } + + /// Get the underlying constant buffer. + const const_buffer& buffer() const noexcept + { + return buffer_; + } + + /// Get a pointer to the beginning of the memory range. + /** + * @returns <tt>buffer().data()</tt>. + */ + const void* data() const noexcept + { + return buffer_.data(); + } + + /// Get the size of the memory range. + /** + * @returns <tt>buffer().size()</tt>. + */ + std::size_t size() const noexcept + { + return buffer_.size(); + } + + /// Get the registered buffer identifier. + const registered_buffer_id& id() const noexcept + { + return id_; + } + + /// Move the start of the buffer by the specified number of bytes. + const_registered_buffer& operator+=(std::size_t n) noexcept + { + buffer_ += n; + return *this; + } + +private: + // Hidden constructor used by operators. + const_registered_buffer(const const_buffer& b, + const registered_buffer_id& i) noexcept + : buffer_(b), + id_(i) + { + } + +#if !defined(GENERATING_DOCUMENTATION) + friend const_registered_buffer buffer( + const const_registered_buffer& b, std::size_t n) noexcept; +#endif // !defined(GENERATING_DOCUMENTATION) + + const_buffer buffer_; + registered_buffer_id id_; +}; + +/** @addtogroup buffer_sequence_begin */ + +/// Get an iterator to the first element in a buffer sequence. +inline const mutable_buffer* buffer_sequence_begin( + const mutable_registered_buffer& b) noexcept +{ + return &b.buffer(); +} + +/// Get an iterator to the first element in a buffer sequence. +inline const const_buffer* buffer_sequence_begin( + const const_registered_buffer& b) noexcept +{ + return &b.buffer(); +} + +/** @} */ +/** @addtogroup buffer_sequence_end */ + +/// Get an iterator to one past the end element in a buffer sequence. +inline const mutable_buffer* buffer_sequence_end( + const mutable_registered_buffer& b) noexcept +{ + return &b.buffer() + 1; +} + +/// Get an iterator to one past the end element in a buffer sequence. +inline const const_buffer* buffer_sequence_end( + const const_registered_buffer& b) noexcept +{ + return &b.buffer() + 1; +} + +/** @} */ +/** @addtogroup buffer */ + +/// Obtain a buffer representing the entire registered buffer. +inline mutable_registered_buffer buffer( + const mutable_registered_buffer& b) noexcept +{ + return b; +} + +/// Obtain a buffer representing the entire registered buffer. +inline const_registered_buffer buffer( + const const_registered_buffer& b) noexcept +{ + return b; +} + +/// Obtain a buffer representing part of a registered buffer. +inline mutable_registered_buffer buffer( + const mutable_registered_buffer& b, std::size_t n) noexcept +{ + return mutable_registered_buffer(buffer(b.buffer_, n), b.id_); +} + +/// Obtain a buffer representing part of a registered buffer. +inline const_registered_buffer buffer( + const const_registered_buffer& b, std::size_t n) noexcept +{ + return const_registered_buffer(buffer(b.buffer_, n), b.id_); +} + +/** @} */ + +/// Create a new modifiable registered buffer that is offset from the start of +/// another. +/** + * @relates mutable_registered_buffer + */ +inline mutable_registered_buffer operator+( + const mutable_registered_buffer& b, std::size_t n) noexcept +{ + mutable_registered_buffer tmp(b); + tmp += n; + return tmp; +} + +/// Create a new modifiable buffer that is offset from the start of another. +/** + * @relates mutable_registered_buffer + */ +inline mutable_registered_buffer operator+(std::size_t n, + const mutable_registered_buffer& b) noexcept +{ + return b + n; +} + +/// Create a new non-modifiable registered buffer that is offset from the start +/// of another. +/** + * @relates const_registered_buffer + */ +inline const_registered_buffer operator+(const const_registered_buffer& b, + std::size_t n) noexcept +{ + const_registered_buffer tmp(b); + tmp += n; + return tmp; +} + +/// Create a new non-modifiable buffer that is offset from the start of another. +/** + * @relates const_registered_buffer + */ +inline const_registered_buffer operator+(std::size_t n, + const const_registered_buffer& b) noexcept +{ + return b + n; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_REGISTERED_BUFFER_HPP diff --git a/3rdparty/asio/include/asio/require.hpp b/3rdparty/asio/include/asio/require.hpp new file mode 100644 index 00000000000..609e54fcaa3 --- /dev/null +++ b/3rdparty/asio/include/asio/require.hpp @@ -0,0 +1,433 @@ +// +// require.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_REQUIRE_HPP +#define ASIO_REQUIRE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/require_member.hpp" +#include "asio/traits/require_free.hpp" +#include "asio/traits/static_require.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { + +/// A customisation point that applies a concept-preserving property to an +/// object. +/** + * The name <tt>require</tt> denotes a customisation point object. The + * expression <tt>asio::require(E, P0, Pn...)</tt> for some + * subexpressions <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> + * represents <tt>N</tt> subexpressions (where <tt>N</tt> is 0 or more, and with + * types <tt>T = decay_t<decltype(E)></tt> and <tt>Prop0 = + * decay_t<decltype(P0)></tt>) is expression-equivalent to: + * + * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_requirable</tt> is + * not a well-formed constant expression with value <tt>true</tt>, + * <tt>asio::require(E, P0, Pn...)</tt> is ill-formed. + * + * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression + * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a + * well-formed constant expression with value <tt>true</tt>. + * + * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression + * <tt>(E).require(P0)</tt> is a valid expression. + * + * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression + * <tt>require(E, P0)</tt> is a valid expression with overload resolution + * performed in a context that does not include the declaration of the + * <tt>require</tt> customization point object. + * + * @li Otherwise, + * <tt>asio::require(asio::require(E, P0), Pn...)</tt> + * if <tt>N > 0</tt> and the expression + * <tt>asio::require(asio::require(E, P0), Pn...)</tt> + * is a valid expression. + * + * @li Otherwise, <tt>asio::require(E, P0, Pn...)</tt> is ill-formed. + */ +inline constexpr unspecified require = unspecified; + +/// A type trait that determines whether a @c require expression is well-formed. +/** + * Class template @c can_require is a trait that is derived from + * @c true_type if the expression <tt>asio::require(std::declval<T>(), + * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type. + */ +template <typename T, typename... Properties> +struct can_require : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines whether a @c require expression will not throw. +/** + * Class template @c is_nothrow_require is a trait that is derived from + * @c true_type if the expression <tt>asio::require(std::declval<T>(), + * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type. + */ +template <typename T, typename... Properties> +struct is_nothrow_require : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines the result type of a @c require expression. +/** + * Class template @c require_result is a trait that determines the result + * type of the expression <tt>asio::require(std::declval<T>(), + * std::declval<Properties>()...)</tt>. + */ +template <typename T, typename... Properties> +struct require_result +{ + /// The result of the @c require expression. + typedef automatically_determined type; +}; + +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_require_fn { + +using asio::conditional_t; +using asio::decay_t; +using asio::declval; +using asio::enable_if_t; +using asio::is_applicable_property; +using asio::traits::require_free; +using asio::traits::require_member; +using asio::traits::static_require; + +void require(); + +enum overload_type +{ + identity, + call_member, + call_free, + two_props, + n_props, + ill_formed +}; + +template <typename Impl, typename T, typename Properties, typename = void, + typename = void, typename = void, typename = void, typename = void> +struct call_traits +{ + static constexpr overload_type overload = ill_formed; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_requirable + >, + enable_if_t< + static_require<T, Property>::is_valid + >> +{ + static constexpr overload_type overload = identity; + static constexpr bool is_noexcept = true; + + typedef T&& result_type; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_requirable + >, + enable_if_t< + !static_require<T, Property>::is_valid + >, + enable_if_t< + require_member<typename Impl::template proxy<T>::type, Property>::is_valid + >> : + require_member<typename Impl::template proxy<T>::type, Property> +{ + static constexpr overload_type overload = call_member; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_requirable + >, + enable_if_t< + !static_require<T, Property>::is_valid + >, + enable_if_t< + !require_member<typename Impl::template proxy<T>::type, Property>::is_valid + >, + enable_if_t< + require_free<T, Property>::is_valid + >> : + require_free<T, Property> +{ + static constexpr overload_type overload = call_free; +}; + +template <typename Impl, typename T, typename P0, typename P1> +struct call_traits<Impl, T, void(P0, P1), + enable_if_t< + call_traits<Impl, T, void(P0)>::overload != ill_formed + >, + enable_if_t< + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1) + >::overload != ill_formed + >> +{ + static constexpr overload_type overload = two_props; + + static constexpr bool is_noexcept = + ( + call_traits<Impl, T, void(P0)>::is_noexcept + && + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1) + >::is_noexcept + ); + + typedef decay_t< + typename call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1) + >::result_type + > result_type; +}; + +template <typename Impl, typename T, typename P0, + typename P1, typename... PN> +struct call_traits<Impl, T, void(P0, P1, PN...), + enable_if_t< + call_traits<Impl, T, void(P0)>::overload != ill_formed + >, + enable_if_t< + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1, PN...) + >::overload != ill_formed + >> +{ + static constexpr overload_type overload = n_props; + + static constexpr bool is_noexcept = + ( + call_traits<Impl, T, void(P0)>::is_noexcept + && + call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1, PN...) + >::is_noexcept + ); + + typedef decay_t< + typename call_traits< + Impl, + typename call_traits<Impl, T, void(P0)>::result_type, + void(P1, PN...) + >::result_type + > result_type; +}; + +struct impl +{ + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + struct type + { + template <typename P> + auto require(P&& p) + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().require(static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + }; + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == identity, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&&) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_member, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t).require(static_cast<Property&&>(p)); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_free, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return require(static_cast<T&&>(t), static_cast<Property&&>(p)); + } + + template <typename T, typename P0, typename P1> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(P0, P1)>::overload == two_props, + typename call_traits<impl, T, void(P0, P1)>::result_type + > + operator()(T&& t, P0&& p0, P1&& p1) const + noexcept(call_traits<impl, T, void(P0, P1)>::is_noexcept) + { + return (*this)( + (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)), + static_cast<P1&&>(p1)); + } + + template <typename T, typename P0, typename P1, + typename... PN> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(P0, P1, PN...)>::overload == n_props, + typename call_traits<impl, T, void(P0, P1, PN...)>::result_type + > + operator()(T&& t, P0&& p0, P1&& p1, PN&&... pn) const + noexcept(call_traits<impl, T, void(P0, P1, PN...)>::is_noexcept) + { + return (*this)( + (*this)(static_cast<T&&>(t), static_cast<P0&&>(p0)), + static_cast<P1&&>(p1), static_cast<PN&&>(pn)...); + } +}; + +template <typename T = impl> +struct static_instance +{ + static const T instance; +}; + +template <typename T> +const T static_instance<T>::instance = {}; + +} // namespace asio_require_fn +namespace asio { +namespace { + +static constexpr const asio_require_fn::impl& + require = asio_require_fn::static_instance<>::instance; + +} // namespace + +typedef asio_require_fn::impl require_t; + +template <typename T, typename... Properties> +struct can_require : + integral_constant<bool, + asio_require_fn::call_traits< + require_t, T, void(Properties...)>::overload + != asio_require_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +constexpr bool can_require_v + = can_require<T, Properties...>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +struct is_nothrow_require : + integral_constant<bool, + asio_require_fn::call_traits< + require_t, T, void(Properties...)>::is_noexcept> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +constexpr bool is_nothrow_require_v + = is_nothrow_require<T, Properties...>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename... Properties> +struct require_result +{ + typedef typename asio_require_fn::call_traits< + require_t, T, void(Properties...)>::result_type type; +}; + +template <typename T, typename... Properties> +using require_result_t = typename require_result<T, Properties...>::type; + +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_REQUIRE_HPP diff --git a/3rdparty/asio/include/asio/require_concept.hpp b/3rdparty/asio/include/asio/require_concept.hpp new file mode 100644 index 00000000000..b735b669952 --- /dev/null +++ b/3rdparty/asio/include/asio/require_concept.hpp @@ -0,0 +1,343 @@ +// +// require_concept.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_REQUIRE_CONCEPT_HPP +#define ASIO_REQUIRE_CONCEPT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/is_applicable_property.hpp" +#include "asio/traits/require_concept_member.hpp" +#include "asio/traits/require_concept_free.hpp" +#include "asio/traits/static_require_concept.hpp" + +#include "asio/detail/push_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) + +namespace asio { + +/// A customisation point that applies a concept-enforcing property to an +/// object. +/** + * The name <tt>require_concept</tt> denotes a customization point object. The + * expression <tt>asio::require_concept(E, P)</tt> for some + * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T = + * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is + * expression-equivalent to: + * + * @li If <tt>is_applicable_property_v<T, Prop> && + * Prop::is_requirable_concept</tt> is not a well-formed constant expression + * with value <tt>true</tt>, <tt>asio::require_concept(E, P)</tt> is + * ill-formed. + * + * @li Otherwise, <tt>E</tt> if the expression <tt>Prop::template + * static_query_v<T> == Prop::value()</tt> is a well-formed constant + * expression with value <tt>true</tt>. + * + * @li Otherwise, <tt>(E).require_concept(P)</tt> if the expression + * <tt>(E).require_concept(P)</tt> is well-formed. + * + * @li Otherwise, <tt>require_concept(E, P)</tt> if the expression + * <tt>require_concept(E, P)</tt> is a valid expression with overload + * resolution performed in a context that does not include the declaration + * of the <tt>require_concept</tt> customization point object. + * + * @li Otherwise, <tt>asio::require_concept(E, P)</tt> is ill-formed. + */ +inline constexpr unspecified require_concept = unspecified; + +/// A type trait that determines whether a @c require_concept expression is +/// well-formed. +/** + * Class template @c can_require_concept is a trait that is derived from + * @c true_type if the expression + * <tt>asio::require_concept(std::declval<T>(), + * std::declval<Property>())</tt> is well formed; otherwise @c false_type. + */ +template <typename T, typename Property> +struct can_require_concept : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines whether a @c require_concept expression will +/// not throw. +/** + * Class template @c is_nothrow_require_concept is a trait that is derived from + * @c true_type if the expression + * <tt>asio::require_concept(std::declval<T>(), + * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type. + */ +template <typename T, typename Property> +struct is_nothrow_require_concept : + integral_constant<bool, automatically_determined> +{ +}; + +/// A type trait that determines the result type of a @c require_concept +/// expression. +/** + * Class template @c require_concept_result is a trait that determines the + * result type of the expression + * <tt>asio::require_concept(std::declval<T>(), + * std::declval<Property>())</tt>. + */ +template <typename T, typename Property> +struct require_concept_result +{ + /// The result of the @c require_concept expression. + typedef automatically_determined type; +}; + +} // namespace asio + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_require_concept_fn { + +using asio::conditional_t; +using asio::decay_t; +using asio::declval; +using asio::enable_if_t; +using asio::is_applicable_property; +using asio::traits::require_concept_free; +using asio::traits::require_concept_member; +using asio::traits::static_require_concept; + +void require_concept(); + +enum overload_type +{ + identity, + call_member, + call_free, + ill_formed +}; + +template <typename Impl, typename T, typename Properties, typename = void, + typename = void, typename = void, typename = void, typename = void> +struct call_traits +{ + static constexpr overload_type overload = ill_formed; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_requirable_concept + >, + enable_if_t< + static_require_concept<T, Property>::is_valid + >> +{ + static constexpr overload_type overload = identity; + static constexpr bool is_noexcept = true; + typedef T&& result_type; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_requirable_concept + >, + enable_if_t< + !static_require_concept<T, Property>::is_valid + >, + enable_if_t< + require_concept_member< + typename Impl::template proxy<T>::type, + Property + >::is_valid + >> : + require_concept_member< + typename Impl::template proxy<T>::type, + Property + > +{ + static constexpr overload_type overload = call_member; +}; + +template <typename Impl, typename T, typename Property> +struct call_traits<Impl, T, void(Property), + enable_if_t< + is_applicable_property< + decay_t<T>, + decay_t<Property> + >::value + >, + enable_if_t< + decay_t<Property>::is_requirable_concept + >, + enable_if_t< + !static_require_concept<T, Property>::is_valid + >, + enable_if_t< + !require_concept_member< + typename Impl::template proxy<T>::type, + Property + >::is_valid + >, + enable_if_t< + require_concept_free<T, Property>::is_valid + >> : + require_concept_free<T, Property> +{ + static constexpr overload_type overload = call_free; +}; + +struct impl +{ + template <typename T> + struct proxy + { +#if defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + struct type + { + template <typename P> + auto require_concept(P&& p) + noexcept( + noexcept( + declval<conditional_t<true, T, P>>().require_concept( + static_cast<P&&>(p)) + ) + ) + -> decltype( + declval<conditional_t<true, T, P>>().require_concept( + static_cast<P&&>(p)) + ); + }; +#else // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + typedef T type; +#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + }; + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == identity, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&&) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_member, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return static_cast<T&&>(t).require_concept(static_cast<Property&&>(p)); + } + + template <typename T, typename Property> + ASIO_NODISCARD constexpr enable_if_t< + call_traits<impl, T, void(Property)>::overload == call_free, + typename call_traits<impl, T, void(Property)>::result_type + > + operator()(T&& t, Property&& p) const + noexcept(call_traits<impl, T, void(Property)>::is_noexcept) + { + return require_concept(static_cast<T&&>(t), static_cast<Property&&>(p)); + } +}; + +template <typename T = impl> +struct static_instance +{ + static const T instance; +}; + +template <typename T> +const T static_instance<T>::instance = {}; + +} // namespace asio_require_concept_fn +namespace asio { +namespace { + +static constexpr const asio_require_concept_fn::impl& + require_concept = asio_require_concept_fn::static_instance<>::instance; + +} // namespace + +typedef asio_require_concept_fn::impl require_concept_t; + +template <typename T, typename Property> +struct can_require_concept : + integral_constant<bool, + asio_require_concept_fn::call_traits< + require_concept_t, T, void(Property)>::overload != + asio_require_concept_fn::ill_formed> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +constexpr bool can_require_concept_v = can_require_concept<T, Property>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +struct is_nothrow_require_concept : + integral_constant<bool, + asio_require_concept_fn::call_traits< + require_concept_t, T, void(Property)>::is_noexcept> +{ +}; + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +constexpr bool is_nothrow_require_concept_v + = is_nothrow_require_concept<T, Property>::value; + +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + +template <typename T, typename Property> +struct require_concept_result +{ + typedef typename asio_require_concept_fn::call_traits< + require_concept_t, T, void(Property)>::result_type type; +}; + +template <typename T, typename Property> +using require_concept_result_t = + typename require_concept_result<T, Property>::type; + +} // namespace asio + +#endif // defined(GENERATING_DOCUMENTATION) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_REQUIRE_CONCEPT_HPP diff --git a/3rdparty/asio/include/asio/seq_packet_socket_service.hpp b/3rdparty/asio/include/asio/seq_packet_socket_service.hpp deleted file mode 100644 index d517eeb6a0c..00000000000 --- a/3rdparty/asio/include/asio/seq_packet_socket_service.hpp +++ /dev/null @@ -1,405 +0,0 @@ -// -// seq_packet_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_SEQ_PACKET_SOCKET_SERVICE_HPP -#define ASIO_SEQ_PACKET_SOCKET_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/type_traits.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/null_socket_service.hpp" -#elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -#else -# include "asio/detail/reactive_socket_service.hpp" -#endif - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a sequenced packet socket. -template <typename Protocol> -class seq_packet_socket_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base< - seq_packet_socket_service<Protocol> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The protocol type. - typedef Protocol protocol_type; - - /// The endpoint type. - typedef typename Protocol::endpoint endpoint_type; - -private: - // The type of the platform-specific implementation. -#if defined(ASIO_WINDOWS_RUNTIME) - typedef detail::null_socket_service<Protocol> service_impl_type; -#elif defined(ASIO_HAS_IOCP) - typedef detail::win_iocp_socket_service<Protocol> service_impl_type; -#else - typedef detail::reactive_socket_service<Protocol> service_impl_type; -#endif - -public: - /// The type of a sequenced packet socket implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef typename service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new sequenced packet socket service for the specified - /// io_context. - explicit seq_packet_socket_service(asio::io_context& io_context) - : asio::detail::service_base< - seq_packet_socket_service<Protocol> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new sequenced packet socket implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new sequenced packet socket implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another sequenced packet socket implementation. - void move_assign(implementation_type& impl, - seq_packet_socket_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } - - /// Move-construct a new sequenced packet socket implementation from another - /// protocol type. - template <typename Protocol1> - void converting_move_construct(implementation_type& impl, - typename seq_packet_socket_service< - Protocol1>::implementation_type& other_impl, - typename enable_if<is_convertible< - Protocol1, Protocol>::value>::type* = 0) - { - service_impl_.template converting_move_construct<Protocol1>( - impl, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a sequenced packet socket implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Open a sequenced packet socket. - ASIO_SYNC_OP_VOID open(implementation_type& impl, - const protocol_type& protocol, asio::error_code& ec) - { - if (protocol.type() == ASIO_OS_DEF(SOCK_SEQPACKET)) - service_impl_.open(impl, protocol, ec); - else - ec = asio::error::invalid_argument; - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Assign an existing native socket to a sequenced packet socket. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const protocol_type& protocol, const native_handle_type& native_socket, - asio::error_code& ec) - { - service_impl_.assign(impl, protocol, native_socket, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a sequenced packet socket implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native socket implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the socket. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.at_mark(impl, ec); - } - - /// Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.available(impl, ec); - } - - /// Bind the sequenced packet socket to the specified local endpoint. - ASIO_SYNC_OP_VOID bind(implementation_type& impl, - const endpoint_type& endpoint, asio::error_code& ec) - { - service_impl_.bind(impl, endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Connect the sequenced packet socket to the specified endpoint. - ASIO_SYNC_OP_VOID connect(implementation_type& impl, - const endpoint_type& peer_endpoint, asio::error_code& ec) - { - service_impl_.connect(impl, peer_endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Start an asynchronous connect. - template <typename ConnectHandler> - ASIO_INITFN_RESULT_TYPE(ConnectHandler, - void (asio::error_code)) - async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(ConnectHandler) handler) - { - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); - - return init.result.get(); - } - - /// Set a socket option. - template <typename SettableSocketOption> - ASIO_SYNC_OP_VOID set_option(implementation_type& impl, - const SettableSocketOption& option, asio::error_code& ec) - { - service_impl_.set_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get a socket option. - template <typename GettableSocketOption> - ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, - GettableSocketOption& option, asio::error_code& ec) const - { - service_impl_.get_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform an IO control command on the socket. - template <typename IoControlCommand> - ASIO_SYNC_OP_VOID io_control(implementation_type& impl, - IoControlCommand& command, asio::error_code& ec) - { - service_impl_.io_control(impl, command, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the socket. - bool non_blocking(const implementation_type& impl) const - { - return service_impl_.non_blocking(impl); - } - - /// Sets the non-blocking mode of the socket. - ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the native socket implementation. - bool native_non_blocking(const implementation_type& impl) const - { - return service_impl_.native_non_blocking(impl); - } - - /// Sets the non-blocking mode of the native socket implementation. - ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.native_non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the local endpoint. - endpoint_type local_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.local_endpoint(impl, ec); - } - - /// Get the remote endpoint. - endpoint_type remote_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.remote_endpoint(impl, ec); - } - - /// Disable sends or receives on the socket. - ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, - socket_base::shutdown_type what, asio::error_code& ec) - { - service_impl_.shutdown(impl, what, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Wait for the socket to become ready to read, ready to write, or to have - /// pending error conditions. - ASIO_SYNC_OP_VOID wait(implementation_type& impl, - socket_base::wait_type w, asio::error_code& ec) - { - service_impl_.wait(impl, w, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Asynchronously wait for the socket to become ready to read, ready to - /// write, or to have pending error conditions. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, socket_base::wait_type w, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, w, init.completion_handler); - - return init.result.get(); - } - - /// Send the given data to the peer. - template <typename ConstBufferSequence> - std::size_t send(implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.send(impl, buffers, flags, ec); - } - - /// Start an asynchronous send. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) - { - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_send(impl, buffers, flags, init.completion_handler); - - return init.result.get(); - } - - /// Receive some data from the peer. - template <typename MutableBufferSequence> - std::size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, socket_base::message_flags in_flags, - socket_base::message_flags& out_flags, asio::error_code& ec) - { - return service_impl_.receive_with_flags(impl, - buffers, in_flags, out_flags, ec); - } - - /// Start an asynchronous receive. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, socket_base::message_flags in_flags, - socket_base::message_flags& out_flags, - ASIO_MOVE_ARG(ReadHandler) handler) - { - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_receive_with_flags(impl, - buffers, in_flags, out_flags, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_SEQ_PACKET_SOCKET_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/serial_port.hpp b/3rdparty/asio/include/asio/serial_port.hpp index 4455a0aa3b6..61e893769bf 100644 --- a/3rdparty/asio/include/asio/serial_port.hpp +++ b/3rdparty/asio/include/asio/serial_port.hpp @@ -2,7 +2,7 @@ // serial_port.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -21,748 +21,15 @@ #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) -#include <string> -#include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" -#include "asio/detail/handler_type_requirements.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" -#include "asio/serial_port_base.hpp" - -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/basic_serial_port.hpp" -#else // defined(ASIO_ENABLE_OLD_SERVICES) -# if defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_serial_port_service.hpp" -# define ASIO_SVC_T detail::win_iocp_serial_port_service -# else -# include "asio/detail/reactive_serial_port_service.hpp" -# define ASIO_SVC_T detail::reactive_serial_port_service -# endif -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#include "asio/detail/push_options.hpp" +#include "asio/basic_serial_port.hpp" namespace asio { -#if defined(ASIO_ENABLE_OLD_SERVICES) -// Typedef for the typical usage of a serial port. +/// Typedef for the typical usage of a serial port. typedef basic_serial_port<> serial_port; -#else // defined(ASIO_ENABLE_OLD_SERVICES) -/// Provides serial port functionality. -/** - * The serial_port class provides a wrapper over serial port functionality. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - */ -class serial_port - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>, - public serial_port_base -{ -public: - /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; - - /// The native representation of a serial port. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef ASIO_SVC_T::native_handle_type native_handle_type; -#endif - - /// A basic_serial_port is always the lowest layer. - typedef serial_port lowest_layer_type; - - /// Construct a serial_port without opening it. - /** - * This constructor creates a serial port without opening it. - * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. - */ - explicit serial_port(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) - { - } - - /// Construct and open a serial_port. - /** - * This constructor creates and opens a serial port for the specified device - * name. - * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. - * - * @param device The platform-specific device name for this serial - * port. - */ - explicit serial_port(asio::io_context& io_context, - const char* device) - : basic_io_object<ASIO_SVC_T>(io_context) - { - asio::error_code ec; - this->get_service().open(this->get_implementation(), device, ec); - asio::detail::throw_error(ec, "open"); - } - - /// Construct and open a serial_port. - /** - * This constructor creates and opens a serial port for the specified device - * name. - * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. - * - * @param device The platform-specific device name for this serial - * port. - */ - explicit serial_port(asio::io_context& io_context, - const std::string& device) - : basic_io_object<ASIO_SVC_T>(io_context) - { - asio::error_code ec; - this->get_service().open(this->get_implementation(), device, ec); - asio::detail::throw_error(ec, "open"); - } - - /// Construct a serial_port on an existing native serial port. - /** - * This constructor creates a serial port object to hold an existing native - * serial port. - * - * @param io_context The io_context object that the serial port will use to - * dispatch handlers for any asynchronous operations performed on the port. - * - * @param native_serial_port A native serial port. - * - * @throws asio::system_error Thrown on failure. - */ - serial_port(asio::io_context& io_context, - const native_handle_type& native_serial_port) - : basic_io_object<ASIO_SVC_T>(io_context) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), - native_serial_port, ec); - asio::detail::throw_error(ec, "assign"); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a serial_port from another. - /** - * This constructor moves a serial port from one object to another. - * - * @param other The other serial_port object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c serial_port(io_context&) constructor. - */ - serial_port(serial_port&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) - { - } - - /// Move-assign a serial_port from another. - /** - * This assignment operator moves a serial port from one object to another. - * - * @param other The other serial_port object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c serial_port(io_context&) constructor. - */ - serial_port& operator=(serial_port&& other) - { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroys the serial port. - /** - * This function destroys the serial port, cancelling any outstanding - * asynchronous wait operations associated with the serial port as if by - * calling @c cancel. - */ - ~serial_port() - { - } - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - - /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT - { - return basic_io_object<ASIO_SVC_T>::get_executor(); - } - - /// Get a reference to the lowest layer. - /** - * This function returns a reference to the lowest layer in a stack of - * layers. Since a serial_port cannot contain any further layers, it simply - * returns a reference to itself. - * - * @return A reference to the lowest layer in the stack of layers. Ownership - * is not transferred to the caller. - */ - lowest_layer_type& lowest_layer() - { - return *this; - } - - /// Get a const reference to the lowest layer. - /** - * This function returns a const reference to the lowest layer in a stack of - * layers. Since a serial_port cannot contain any further layers, it simply - * returns a reference to itself. - * - * @return A const reference to the lowest layer in the stack of layers. - * Ownership is not transferred to the caller. - */ - const lowest_layer_type& lowest_layer() const - { - return *this; - } - - /// Open the serial port using the specified device name. - /** - * This function opens the serial port for the specified device name. - * - * @param device The platform-specific device name. - * - * @throws asio::system_error Thrown on failure. - */ - void open(const std::string& device) - { - asio::error_code ec; - this->get_service().open(this->get_implementation(), device, ec); - asio::detail::throw_error(ec, "open"); - } - - /// Open the serial port using the specified device name. - /** - * This function opens the serial port using the given platform-specific - * device name. - * - * @param device The platform-specific device name. - * - * @param ec Set the indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID open(const std::string& device, - asio::error_code& ec) - { - this->get_service().open(this->get_implementation(), device, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Assign an existing native serial port to the serial port. - /* - * This function opens the serial port to hold an existing native serial port. - * - * @param native_serial_port A native serial port. - * - * @throws asio::system_error Thrown on failure. - */ - void assign(const native_handle_type& native_serial_port) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), - native_serial_port, ec); - asio::detail::throw_error(ec, "assign"); - } - - /// Assign an existing native serial port to the serial port. - /* - * This function opens the serial port to hold an existing native serial port. - * - * @param native_serial_port A native serial port. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, - asio::error_code& ec) - { - this->get_service().assign(this->get_implementation(), - native_serial_port, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the serial port is open. - bool is_open() const - { - return this->get_service().is_open(this->get_implementation()); - } - - /// Close the serial port. - /** - * This function is used to close the serial port. Any asynchronous read or - * write operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void close() - { - asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); - asio::detail::throw_error(ec, "close"); - } - - /// Close the serial port. - /** - * This function is used to close the serial port. Any asynchronous read or - * write operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID close(asio::error_code& ec) - { - this->get_service().close(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native serial port representation. - /** - * This function may be used to obtain the underlying representation of the - * serial port. This is intended to allow access to native serial port - * functionality that is not otherwise provided. - */ - native_handle_type native_handle() - { - return this->get_service().native_handle(this->get_implementation()); - } - - /// Cancel all asynchronous operations associated with the serial port. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void cancel() - { - asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); - asio::detail::throw_error(ec, "cancel"); - } - - /// Cancel all asynchronous operations associated with the serial port. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) - { - this->get_service().cancel(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Send a break sequence to the serial port. - /** - * This function causes a break sequence of platform-specific duration to be - * sent out the serial port. - * - * @throws asio::system_error Thrown on failure. - */ - void send_break() - { - asio::error_code ec; - this->get_service().send_break(this->get_implementation(), ec); - asio::detail::throw_error(ec, "send_break"); - } - - /// Send a break sequence to the serial port. - /** - * This function causes a break sequence of platform-specific duration to be - * sent out the serial port. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID send_break(asio::error_code& ec) - { - this->get_service().send_break(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Set an option on the serial port. - /** - * This function is used to set an option on the serial port. - * - * @param option The option value to be set on the serial port. - * - * @throws asio::system_error Thrown on failure. - * - * @sa SettableSerialPortOption @n - * asio::serial_port_base::baud_rate @n - * asio::serial_port_base::flow_control @n - * asio::serial_port_base::parity @n - * asio::serial_port_base::stop_bits @n - * asio::serial_port_base::character_size - */ - template <typename SettableSerialPortOption> - void set_option(const SettableSerialPortOption& option) - { - asio::error_code ec; - this->get_service().set_option(this->get_implementation(), option, ec); - asio::detail::throw_error(ec, "set_option"); - } - - /// Set an option on the serial port. - /** - * This function is used to set an option on the serial port. - * - * @param option The option value to be set on the serial port. - * - * @param ec Set to indicate what error occurred, if any. - * - * @sa SettableSerialPortOption @n - * asio::serial_port_base::baud_rate @n - * asio::serial_port_base::flow_control @n - * asio::serial_port_base::parity @n - * asio::serial_port_base::stop_bits @n - * asio::serial_port_base::character_size - */ - template <typename SettableSerialPortOption> - ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, - asio::error_code& ec) - { - this->get_service().set_option(this->get_implementation(), option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get an option from the serial port. - /** - * This function is used to get the current value of an option on the serial - * port. - * - * @param option The option value to be obtained from the serial port. - * - * @throws asio::system_error Thrown on failure. - * - * @sa GettableSerialPortOption @n - * asio::serial_port_base::baud_rate @n - * asio::serial_port_base::flow_control @n - * asio::serial_port_base::parity @n - * asio::serial_port_base::stop_bits @n - * asio::serial_port_base::character_size - */ - template <typename GettableSerialPortOption> - void get_option(GettableSerialPortOption& option) - { - asio::error_code ec; - this->get_service().get_option(this->get_implementation(), option, ec); - asio::detail::throw_error(ec, "get_option"); - } - - /// Get an option from the serial port. - /** - * This function is used to get the current value of an option on the serial - * port. - * - * @param option The option value to be obtained from the serial port. - * - * @param ec Set to indicate what error occurred, if any. - * - * @sa GettableSerialPortOption @n - * asio::serial_port_base::baud_rate @n - * asio::serial_port_base::flow_control @n - * asio::serial_port_base::parity @n - * asio::serial_port_base::stop_bits @n - * asio::serial_port_base::character_size - */ - template <typename GettableSerialPortOption> - ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, - asio::error_code& ec) - { - this->get_service().get_option(this->get_implementation(), option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Write some data to the serial port. - /** - * This function is used to write data to the serial port. The function call - * will block until one or more bytes of the data has been written - * successfully, or until an error occurs. - * - * @param buffers One or more data buffers to be written to the serial port. - * - * @returns The number of bytes written. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that - * all data is written before the blocking operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * serial_port.write_some(asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().write_some( - this->get_implementation(), buffers, ec); - asio::detail::throw_error(ec, "write_some"); - return s; - } - - /// Write some data to the serial port. - /** - * This function is used to write data to the serial port. The function call - * will block until one or more bytes of the data has been written - * successfully, or until an error occurs. - * - * @param buffers One or more data buffers to be written to the serial port. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes written. Returns 0 if an error occurred. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that - * all data is written before the blocking operation completes. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers, - asio::error_code& ec) - { - return this->get_service().write_some( - this->get_implementation(), buffers, ec); - } - - /// Start an asynchronous write. - /** - * This function is used to asynchronously write data to the serial port. - * The function call always returns immediately. - * - * @param buffers One or more data buffers to be written to the serial port. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The write operation may not transmit all of the data to the peer. - * Consider using the @ref async_write function if you need to ensure that all - * data is written before the asynchronous operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * serial_port.async_write_some(asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_write_some( - this->get_implementation(), buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the serial port. - /** - * This function is used to read data from the serial port. The function - * call will block until one or more bytes of data has been read successfully, - * or until an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @returns The number of bytes read. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * serial_port.read_some(asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().read_some( - this->get_implementation(), buffers, ec); - asio::detail::throw_error(ec, "read_some"); - return s; - } - - /// Read some data from the serial port. - /** - * This function is used to read data from the serial port. The function - * call will block until one or more bytes of data has been read successfully, - * or until an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes read. Returns 0 if an error occurred. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers, - asio::error_code& ec) - { - return this->get_service().read_some( - this->get_implementation(), buffers, ec); - } - - /// Start an asynchronous read. - /** - * This function is used to asynchronously read data from the serial port. - * The function call always returns immediately. - * - * @param buffers One or more buffers into which the data will be read. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The read operation may not read all of the requested number of bytes. - * Consider using the @ref async_read function if you need to ensure that the - * requested amount of data is read before the asynchronous operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * serial_port.async_read_some(asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_read_some( - this->get_implementation(), buffers, init.completion_handler); - - return init.result.get(); - } -}; -#endif // defined(ASIO_ENABLE_OLD_SERVICES) } // namespace asio -#include "asio/detail/pop_options.hpp" - -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) diff --git a/3rdparty/asio/include/asio/serial_port_base.hpp b/3rdparty/asio/include/asio/serial_port_base.hpp index b4ab4f30df3..479d69796e7 100644 --- a/3rdparty/asio/include/asio/serial_port_base.hpp +++ b/3rdparty/asio/include/asio/serial_port_base.hpp @@ -2,7 +2,7 @@ // serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying diff --git a/3rdparty/asio/include/asio/serial_port_service.hpp b/3rdparty/asio/include/asio/serial_port_service.hpp deleted file mode 100644 index 4f47e57602d..00000000000 --- a/3rdparty/asio/include/asio/serial_port_service.hpp +++ /dev/null @@ -1,249 +0,0 @@ -// -// serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_SERIAL_PORT_SERVICE_HPP -#define ASIO_SERIAL_PORT_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_SERIAL_PORT) \ - || defined(GENERATING_DOCUMENTATION) - -#include <cstddef> -#include <string> -#include "asio/async_result.hpp" -#include "asio/detail/reactive_serial_port_service.hpp" -#include "asio/detail/win_iocp_serial_port_service.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" -#include "asio/serial_port_base.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a serial port. -class serial_port_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<serial_port_service> -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - -private: - // The type of the platform-specific implementation. -#if defined(ASIO_HAS_IOCP) - typedef detail::win_iocp_serial_port_service service_impl_type; -#else - typedef detail::reactive_serial_port_service service_impl_type; -#endif - -public: - /// The type of a serial port implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef service_impl_type::implementation_type implementation_type; -#endif - - /// The native handle type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new serial port service for the specified io_context. - explicit serial_port_service(asio::io_context& io_context) - : asio::detail::service_base<serial_port_service>(io_context), - service_impl_(io_context) - { - } - - /// Construct a new serial port implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new serial port implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another serial port implementation. - void move_assign(implementation_type& impl, - serial_port_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a serial port implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Open a serial port. - ASIO_SYNC_OP_VOID open(implementation_type& impl, - const std::string& device, asio::error_code& ec) - { - service_impl_.open(impl, device, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Assign an existing native handle to a serial port. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const native_handle_type& handle, asio::error_code& ec) - { - service_impl_.assign(impl, handle, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the handle is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a serial port implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native handle implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the handle. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Set a serial port option. - template <typename SettableSerialPortOption> - ASIO_SYNC_OP_VOID set_option(implementation_type& impl, - const SettableSerialPortOption& option, asio::error_code& ec) - { - service_impl_.set_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get a serial port option. - template <typename GettableSerialPortOption> - ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, - GettableSerialPortOption& option, asio::error_code& ec) const - { - service_impl_.get_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Send a break sequence to the serial port. - ASIO_SYNC_OP_VOID send_break(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.send_break(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Write the given data to the stream. - template <typename ConstBufferSequence> - std::size_t write_some(implementation_type& impl, - const ConstBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.write_some(impl, buffers, ec); - } - - /// Start an asynchronous write. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_write_some(impl, buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the stream. - template <typename MutableBufferSequence> - std::size_t read_some(implementation_type& impl, - const MutableBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.read_some(impl, buffers, ec); - } - - /// Start an asynchronous read. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_read_some(impl, buffers, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_HAS_SERIAL_PORT) - // || defined(GENERATING_DOCUMENTATION) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_SERIAL_PORT_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/signal_set.hpp b/3rdparty/asio/include/asio/signal_set.hpp index 085090139f9..b2e189d01d7 100644 --- a/3rdparty/asio/include/asio/signal_set.hpp +++ b/3rdparty/asio/include/asio/signal_set.hpp @@ -2,7 +2,7 @@ // signal_set.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,431 +16,12 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" -#include "asio/detail/handler_type_requirements.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/basic_signal_set.hpp" -#else // defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/detail/signal_set_service.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) +#include "asio/basic_signal_set.hpp" namespace asio { -#if defined(ASIO_ENABLE_OLD_SERVICES) -// Typedef for the typical usage of a signal set. +/// Typedef for the typical usage of a signal set. typedef basic_signal_set<> signal_set; -#else // defined(ASIO_ENABLE_OLD_SERVICES) -/// Provides signal functionality. -/** - * The signal_set class provides the ability to perform an asynchronous wait - * for one or more signals to occur. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - * - * @par Example - * Performing an asynchronous wait: - * @code - * void handler( - * const asio::error_code& error, - * int signal_number) - * { - * if (!error) - * { - * // A signal occurred. - * } - * } - * - * ... - * - * // Construct a signal set registered for process termination. - * asio::signal_set signals(io_context, SIGINT, SIGTERM); - * - * // Start an asynchronous wait for one of the signals to occur. - * signals.async_wait(handler); - * @endcode - * - * @par Queueing of signal notifications - * - * If a signal is registered with a signal_set, and the signal occurs when - * there are no waiting handlers, then the signal notification is queued. The - * next async_wait operation on that signal_set will dequeue the notification. - * If multiple notifications are queued, subsequent async_wait operations - * dequeue them one at a time. Signal notifications are dequeued in order of - * ascending signal number. - * - * If a signal number is removed from a signal_set (using the @c remove or @c - * erase member functions) then any queued notifications for that signal are - * discarded. - * - * @par Multiple registration of signals - * - * The same signal number may be registered with different signal_set objects. - * When the signal occurs, one handler is called for each signal_set object. - * - * Note that multiple registration only works for signals that are registered - * using Asio. The application must not also register a signal handler using - * functions such as @c signal() or @c sigaction(). - * - * @par Signal masking on POSIX platforms - * - * POSIX allows signals to be blocked using functions such as @c sigprocmask() - * and @c pthread_sigmask(). For signals to be delivered, programs must ensure - * that any signals registered using signal_set objects are unblocked in at - * least one thread. - */ -class signal_set - : ASIO_SVC_ACCESS basic_io_object<detail::signal_set_service> -{ -public: - /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; - - /// Construct a signal set without adding any signals. - /** - * This constructor creates a signal set without registering for any signals. - * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. - */ - explicit signal_set(asio::io_context& io_context) - : basic_io_object<detail::signal_set_service>(io_context) - { - } - - /// Construct a signal set and add one signal. - /** - * This constructor creates a signal set and registers for one signal. - * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. - * - * @param signal_number_1 The signal number to be added. - * - * @note This constructor is equivalent to performing: - * @code asio::signal_set signals(io_context); - * signals.add(signal_number_1); @endcode - */ - signal_set(asio::io_context& io_context, int signal_number_1) - : basic_io_object<detail::signal_set_service>(io_context) - { - asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number_1, ec); - asio::detail::throw_error(ec, "add"); - } - - /// Construct a signal set and add two signals. - /** - * This constructor creates a signal set and registers for two signals. - * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. - * - * @param signal_number_1 The first signal number to be added. - * - * @param signal_number_2 The second signal number to be added. - * - * @note This constructor is equivalent to performing: - * @code asio::signal_set signals(io_context); - * signals.add(signal_number_1); - * signals.add(signal_number_2); @endcode - */ - signal_set(asio::io_context& io_context, int signal_number_1, - int signal_number_2) - : basic_io_object<detail::signal_set_service>(io_context) - { - asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number_1, ec); - asio::detail::throw_error(ec, "add"); - this->get_service().add(this->get_implementation(), signal_number_2, ec); - asio::detail::throw_error(ec, "add"); - } - - /// Construct a signal set and add three signals. - /** - * This constructor creates a signal set and registers for three signals. - * - * @param io_context The io_context object that the signal set will use to - * dispatch handlers for any asynchronous operations performed on the set. - * - * @param signal_number_1 The first signal number to be added. - * - * @param signal_number_2 The second signal number to be added. - * - * @param signal_number_3 The third signal number to be added. - * - * @note This constructor is equivalent to performing: - * @code asio::signal_set signals(io_context); - * signals.add(signal_number_1); - * signals.add(signal_number_2); - * signals.add(signal_number_3); @endcode - */ - signal_set(asio::io_context& io_context, int signal_number_1, - int signal_number_2, int signal_number_3) - : basic_io_object<detail::signal_set_service>(io_context) - { - asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number_1, ec); - asio::detail::throw_error(ec, "add"); - this->get_service().add(this->get_implementation(), signal_number_2, ec); - asio::detail::throw_error(ec, "add"); - this->get_service().add(this->get_implementation(), signal_number_3, ec); - asio::detail::throw_error(ec, "add"); - } - - /// Destroys the signal set. - /** - * This function destroys the signal set, cancelling any outstanding - * asynchronous wait operations associated with the signal set as if by - * calling @c cancel. - */ - ~signal_set() - { - } - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<detail::signal_set_service>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<detail::signal_set_service>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - - /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT - { - return basic_io_object<detail::signal_set_service>::get_executor(); - } - - /// Add a signal to a signal_set. - /** - * This function adds the specified signal to the set. It has no effect if the - * signal is already in the set. - * - * @param signal_number The signal to be added to the set. - * - * @throws asio::system_error Thrown on failure. - */ - void add(int signal_number) - { - asio::error_code ec; - this->get_service().add(this->get_implementation(), signal_number, ec); - asio::detail::throw_error(ec, "add"); - } - - /// Add a signal to a signal_set. - /** - * This function adds the specified signal to the set. It has no effect if the - * signal is already in the set. - * - * @param signal_number The signal to be added to the set. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID add(int signal_number, - asio::error_code& ec) - { - this->get_service().add(this->get_implementation(), signal_number, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Remove a signal from a signal_set. - /** - * This function removes the specified signal from the set. It has no effect - * if the signal is not in the set. - * - * @param signal_number The signal to be removed from the set. - * - * @throws asio::system_error Thrown on failure. - * - * @note Removes any notifications that have been queued for the specified - * signal number. - */ - void remove(int signal_number) - { - asio::error_code ec; - this->get_service().remove(this->get_implementation(), signal_number, ec); - asio::detail::throw_error(ec, "remove"); - } - - /// Remove a signal from a signal_set. - /** - * This function removes the specified signal from the set. It has no effect - * if the signal is not in the set. - * - * @param signal_number The signal to be removed from the set. - * - * @param ec Set to indicate what error occurred, if any. - * - * @note Removes any notifications that have been queued for the specified - * signal number. - */ - ASIO_SYNC_OP_VOID remove(int signal_number, - asio::error_code& ec) - { - this->get_service().remove(this->get_implementation(), signal_number, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Remove all signals from a signal_set. - /** - * This function removes all signals from the set. It has no effect if the set - * is already empty. - * - * @throws asio::system_error Thrown on failure. - * - * @note Removes all queued notifications. - */ - void clear() - { - asio::error_code ec; - this->get_service().clear(this->get_implementation(), ec); - asio::detail::throw_error(ec, "clear"); - } - - /// Remove all signals from a signal_set. - /** - * This function removes all signals from the set. It has no effect if the set - * is already empty. - * - * @param ec Set to indicate what error occurred, if any. - * - * @note Removes all queued notifications. - */ - ASIO_SYNC_OP_VOID clear(asio::error_code& ec) - { - this->get_service().clear(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Cancel all operations associated with the signal set. - /** - * This function forces the completion of any pending asynchronous wait - * operations against the signal set. The handler for each cancelled - * operation will be invoked with the asio::error::operation_aborted - * error code. - * - * Cancellation does not alter the set of registered signals. - * - * @throws asio::system_error Thrown on failure. - * - * @note If a registered signal occurred before cancel() is called, then the - * handlers for asynchronous wait operations will: - * - * @li have already been invoked; or - * - * @li have been queued for invocation in the near future. - * - * These handlers can no longer be cancelled, and therefore are passed an - * error code that indicates the successful completion of the wait operation. - */ - void cancel() - { - asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); - asio::detail::throw_error(ec, "cancel"); - } - - /// Cancel all operations associated with the signal set. - /** - * This function forces the completion of any pending asynchronous wait - * operations against the signal set. The handler for each cancelled - * operation will be invoked with the asio::error::operation_aborted - * error code. - * - * Cancellation does not alter the set of registered signals. - * - * @param ec Set to indicate what error occurred, if any. - * - * @note If a registered signal occurred before cancel() is called, then the - * handlers for asynchronous wait operations will: - * - * @li have already been invoked; or - * - * @li have been queued for invocation in the near future. - * - * These handlers can no longer be cancelled, and therefore are passed an - * error code that indicates the successful completion of the wait operation. - */ - ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) - { - this->get_service().cancel(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Start an asynchronous operation to wait for a signal to be delivered. - /** - * This function may be used to initiate an asynchronous wait against the - * signal set. It always returns immediately. - * - * For each call to async_wait(), the supplied handler will be called exactly - * once. The handler will be called when: - * - * @li One of the registered signals in the signal set occurs; or - * - * @li The signal set was cancelled, in which case the handler is passed the - * error code asio::error::operation_aborted. - * - * @param handler The handler to be called when the signal occurs. Copies - * will be made of the handler as required. The function signature of the - * handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * int signal_number // Indicates which signal occurred. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - */ - template <typename SignalHandler> - ASIO_INITFN_RESULT_TYPE(SignalHandler, - void (asio::error_code, int)) - async_wait(ASIO_MOVE_ARG(SignalHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a SignalHandler. - ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; - - async_completion<SignalHandler, - void (asio::error_code, int)> init(handler); - - this->get_service().async_wait(this->get_implementation(), - init.completion_handler); - - return init.result.get(); - } -}; -#endif // defined(ASIO_ENABLE_OLD_SERVICES) } // namespace asio diff --git a/3rdparty/asio/include/asio/signal_set_base.hpp b/3rdparty/asio/include/asio/signal_set_base.hpp new file mode 100644 index 00000000000..9863a1598a3 --- /dev/null +++ b/3rdparty/asio/include/asio/signal_set_base.hpp @@ -0,0 +1,171 @@ +// +// signal_set_base.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_SIGNAL_SET_BASE_HPP +#define ASIO_SIGNAL_SET_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// The signal_set_base class is used as a base for the basic_signal_set class +/// templates so that we have a common place to define the flags enum. +class signal_set_base +{ +public: +# if defined(GENERATING_DOCUMENTATION) + /// Enumeration representing the different types of flags that may specified + /// when adding a signal to a set. + enum flags + { + /// Bitmask representing no flags. + none = 0, + + /// Affects the behaviour of interruptible functions such that, if the + /// function would have failed with error::interrupted when interrupted by + /// the specified signal, the function shall instead be restarted and not + /// fail with error::interrupted. + restart = implementation_defined, + + /// Do not generate SIGCHLD when child processes stop or stopped child + /// processes continue. + no_child_stop = implementation_defined, + + /// Do not transform child processes into zombies when they terminate. + no_child_wait = implementation_defined, + + /// Special value to indicate that the signal registration does not care + /// which flags are set, and so will not conflict with any prior + /// registrations of the same signal. + dont_care = -1 + }; + + /// Portability typedef. + typedef flags flags_t; + +#else // defined(GENERATING_DOCUMENTATION) + + enum class flags : int + { + none = 0, + restart = ASIO_OS_DEF(SA_RESTART), + no_child_stop = ASIO_OS_DEF(SA_NOCLDSTOP), + no_child_wait = ASIO_OS_DEF(SA_NOCLDWAIT), + dont_care = -1 + }; + + typedef flags flags_t; + +#endif // defined(GENERATING_DOCUMENTATION) + +protected: + /// Protected destructor to prevent deletion through this type. + ~signal_set_base() + { + } +}; + +/// Negation operator. +/** + * @relates signal_set_base::flags + */ +inline constexpr bool operator!(signal_set_base::flags_t x) +{ + return static_cast<int>(x) == 0; +} + +/// Bitwise and operator. +/** + * @relates signal_set_base::flags + */ +inline constexpr signal_set_base::flags_t operator&( + signal_set_base::flags_t x, signal_set_base::flags_t y) +{ + return static_cast<signal_set_base::flags_t>( + static_cast<int>(x) & static_cast<int>(y)); +} + +/// Bitwise or operator. +/** + * @relates signal_set_base::flags + */ +inline constexpr signal_set_base::flags_t operator|( + signal_set_base::flags_t x, signal_set_base::flags_t y) +{ + return static_cast<signal_set_base::flags_t>( + static_cast<int>(x) | static_cast<int>(y)); +} + +/// Bitwise xor operator. +/** + * @relates signal_set_base::flags + */ +inline constexpr signal_set_base::flags_t operator^( + signal_set_base::flags_t x, signal_set_base::flags_t y) +{ + return static_cast<signal_set_base::flags_t>( + static_cast<int>(x) ^ static_cast<int>(y)); +} + +/// Bitwise negation operator. +/** + * @relates signal_set_base::flags + */ +inline constexpr signal_set_base::flags_t operator~( + signal_set_base::flags_t x) +{ + return static_cast<signal_set_base::flags_t>(~static_cast<int>(x)); +} + +/// Bitwise and-assignment operator. +/** + * @relates signal_set_base::flags + */ +inline signal_set_base::flags_t& operator&=( + signal_set_base::flags_t& x, signal_set_base::flags_t y) +{ + x = x & y; + return x; +} + +/// Bitwise or-assignment operator. +/** + * @relates signal_set_base::flags + */ +inline signal_set_base::flags_t& operator|=( + signal_set_base::flags_t& x, signal_set_base::flags_t y) +{ + x = x | y; + return x; +} + +/// Bitwise xor-assignment operator. +/** + * @relates signal_set_base::flags + */ +inline signal_set_base::flags_t& operator^=( + signal_set_base::flags_t& x, signal_set_base::flags_t y) +{ + x = x ^ y; + return x; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SIGNAL_SET_BASE_HPP diff --git a/3rdparty/asio/include/asio/signal_set_service.hpp b/3rdparty/asio/include/asio/signal_set_service.hpp deleted file mode 100644 index d4c54b82771..00000000000 --- a/3rdparty/asio/include/asio/signal_set_service.hpp +++ /dev/null @@ -1,142 +0,0 @@ -// -// signal_set_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_SIGNAL_SET_SERVICE_HPP -#define ASIO_SIGNAL_SET_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include "asio/async_result.hpp" -#include "asio/detail/signal_set_service.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a signal set. -class signal_set_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<signal_set_service> -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - -public: - /// The type of a signal set implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef detail::signal_set_service::implementation_type implementation_type; -#endif - - /// Construct a new signal set service for the specified io_context. - explicit signal_set_service(asio::io_context& io_context) - : asio::detail::service_base<signal_set_service>(io_context), - service_impl_(io_context) - { - } - - /// Construct a new signal set implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - - /// Destroy a signal set implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Add a signal to a signal_set. - ASIO_SYNC_OP_VOID add(implementation_type& impl, - int signal_number, asio::error_code& ec) - { - service_impl_.add(impl, signal_number, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Remove a signal to a signal_set. - ASIO_SYNC_OP_VOID remove(implementation_type& impl, - int signal_number, asio::error_code& ec) - { - service_impl_.remove(impl, signal_number, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Remove all signals from a signal_set. - ASIO_SYNC_OP_VOID clear(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.clear(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Cancel all operations associated with the signal set. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - // Start an asynchronous operation to wait for a signal to be delivered. - template <typename SignalHandler> - ASIO_INITFN_RESULT_TYPE(SignalHandler, - void (asio::error_code, int)) - async_wait(implementation_type& impl, - ASIO_MOVE_ARG(SignalHandler) handler) - { - async_completion<SignalHandler, - void (asio::error_code, int)> init(handler); - - service_impl_.async_wait(impl, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // Perform any fork-related housekeeping. - void notify_fork(asio::io_context::fork_event event) - { - service_impl_.notify_fork(event); - } - - // The platform-specific implementation. - detail::signal_set_service service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_SIGNAL_SET_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/socket_acceptor_service.hpp b/3rdparty/asio/include/asio/socket_acceptor_service.hpp deleted file mode 100644 index b9c33ff9892..00000000000 --- a/3rdparty/asio/include/asio/socket_acceptor_service.hpp +++ /dev/null @@ -1,361 +0,0 @@ -// -// socket_acceptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_SOCKET_ACCEPTOR_SERVICE_HPP -#define ASIO_SOCKET_ACCEPTOR_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include "asio/basic_socket.hpp" -#include "asio/detail/type_traits.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/null_socket_service.hpp" -#elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -#else -# include "asio/detail/reactive_socket_service.hpp" -#endif - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a socket acceptor. -template <typename Protocol> -class socket_acceptor_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<socket_acceptor_service<Protocol> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The protocol type. - typedef Protocol protocol_type; - - /// The endpoint type. - typedef typename protocol_type::endpoint endpoint_type; - -private: - // The type of the platform-specific implementation. -#if defined(ASIO_WINDOWS_RUNTIME) - typedef detail::null_socket_service<Protocol> service_impl_type; -#elif defined(ASIO_HAS_IOCP) - typedef detail::win_iocp_socket_service<Protocol> service_impl_type; -#else - typedef detail::reactive_socket_service<Protocol> service_impl_type; -#endif - -public: - /// The native type of the socket acceptor. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// The native acceptor type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef typename service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new socket acceptor service for the specified io_context. - explicit socket_acceptor_service(asio::io_context& io_context) - : asio::detail::service_base< - socket_acceptor_service<Protocol> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new socket acceptor implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new socket acceptor implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another socket acceptor implementation. - void move_assign(implementation_type& impl, - socket_acceptor_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } - - /// Move-construct a new socket acceptor implementation from another protocol - /// type. - template <typename Protocol1> - void converting_move_construct(implementation_type& impl, - typename socket_acceptor_service< - Protocol1>::implementation_type& other_impl, - typename enable_if<is_convertible< - Protocol1, Protocol>::value>::type* = 0) - { - service_impl_.template converting_move_construct<Protocol1>( - impl, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a socket acceptor implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Open a new socket acceptor implementation. - ASIO_SYNC_OP_VOID open(implementation_type& impl, - const protocol_type& protocol, asio::error_code& ec) - { - service_impl_.open(impl, protocol, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Assign an existing native acceptor to a socket acceptor. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const protocol_type& protocol, const native_handle_type& native_acceptor, - asio::error_code& ec) - { - service_impl_.assign(impl, protocol, native_acceptor, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the acceptor is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Cancel all asynchronous operations associated with the acceptor. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Bind the socket acceptor to the specified local endpoint. - ASIO_SYNC_OP_VOID bind(implementation_type& impl, - const endpoint_type& endpoint, asio::error_code& ec) - { - service_impl_.bind(impl, endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Place the socket acceptor into the state where it will listen for new - /// connections. - ASIO_SYNC_OP_VOID listen(implementation_type& impl, int backlog, - asio::error_code& ec) - { - service_impl_.listen(impl, backlog, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Close a socket acceptor implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native acceptor implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Set a socket option. - template <typename SettableSocketOption> - ASIO_SYNC_OP_VOID set_option(implementation_type& impl, - const SettableSocketOption& option, asio::error_code& ec) - { - service_impl_.set_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get a socket option. - template <typename GettableSocketOption> - ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, - GettableSocketOption& option, asio::error_code& ec) const - { - service_impl_.get_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform an IO control command on the socket. - template <typename IoControlCommand> - ASIO_SYNC_OP_VOID io_control(implementation_type& impl, - IoControlCommand& command, asio::error_code& ec) - { - service_impl_.io_control(impl, command, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the acceptor. - bool non_blocking(const implementation_type& impl) const - { - return service_impl_.non_blocking(impl); - } - - /// Sets the non-blocking mode of the acceptor. - ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the native acceptor implementation. - bool native_non_blocking(const implementation_type& impl) const - { - return service_impl_.native_non_blocking(impl); - } - - /// Sets the non-blocking mode of the native acceptor implementation. - ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.native_non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the local endpoint. - endpoint_type local_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.local_endpoint(impl, ec); - } - - /// Wait for the acceptor to become ready to read, ready to write, or to have - /// pending error conditions. - ASIO_SYNC_OP_VOID wait(implementation_type& impl, - socket_base::wait_type w, asio::error_code& ec) - { - service_impl_.wait(impl, w, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Asynchronously wait for the acceptor to become ready to read, ready to - /// write, or to have pending error conditions. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, socket_base::wait_type w, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, w, init.completion_handler); - - return init.result.get(); - } - - /// Accept a new connection. - template <typename Protocol1, typename SocketService> - ASIO_SYNC_OP_VOID accept(implementation_type& impl, - basic_socket<Protocol1, SocketService>& peer, - endpoint_type* peer_endpoint, asio::error_code& ec, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) - { - service_impl_.accept(impl, peer, peer_endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - -#if defined(ASIO_HAS_MOVE) - /// Accept a new connection. - typename Protocol::socket accept(implementation_type& impl, - io_context* peer_io_context, endpoint_type* peer_endpoint, - asio::error_code& ec) - { - return service_impl_.accept(impl, peer_io_context, peer_endpoint, ec); - } -#endif // defined(ASIO_HAS_MOVE) - - /// Start an asynchronous accept. - template <typename Protocol1, typename SocketService, typename AcceptHandler> - ASIO_INITFN_RESULT_TYPE(AcceptHandler, - void (asio::error_code)) - async_accept(implementation_type& impl, - basic_socket<Protocol1, SocketService>& peer, - endpoint_type* peer_endpoint, - ASIO_MOVE_ARG(AcceptHandler) handler, - typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) - { - async_completion<AcceptHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_accept(impl, - peer, peer_endpoint, init.completion_handler); - - return init.result.get(); - } - -#if defined(ASIO_HAS_MOVE) - /// Start an asynchronous accept. - template <typename MoveAcceptHandler> - ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, - void (asio::error_code, typename Protocol::socket)) - async_accept(implementation_type& impl, - asio::io_context* peer_io_context, endpoint_type* peer_endpoint, - ASIO_MOVE_ARG(MoveAcceptHandler) handler) - { - async_completion<MoveAcceptHandler, - void (asio::error_code, - typename Protocol::socket)> init(handler); - - service_impl_.async_accept(impl, - peer_io_context, peer_endpoint, init.completion_handler); - - return init.result.get(); - } -#endif // defined(ASIO_HAS_MOVE) - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_SOCKET_ACCEPTOR_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/socket_base.hpp b/3rdparty/asio/include/asio/socket_base.hpp index 99ef3779af0..5d509790d3d 100644 --- a/3rdparty/asio/include/asio/socket_base.hpp +++ b/3rdparty/asio/include/asio/socket_base.hpp @@ -2,7 +2,7 @@ // socket_base.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -98,7 +98,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::socket_base::broadcast option(true); * socket.set_option(option); @@ -107,7 +107,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::socket_base::broadcast option; * socket.get_option(option); @@ -132,7 +132,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::debug option(true); * socket.set_option(option); @@ -141,7 +141,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::debug option; * socket.get_option(option); @@ -165,7 +165,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::socket_base::do_not_route option(true); * socket.set_option(option); @@ -174,7 +174,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::udp::socket socket(io_context); + * asio::ip::udp::socket socket(my_context); * ... * asio::socket_base::do_not_route option; * socket.get_option(option); @@ -199,7 +199,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::keep_alive option(true); * socket.set_option(option); @@ -208,7 +208,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::keep_alive option; * socket.get_option(option); @@ -232,7 +232,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::send_buffer_size option(8192); * socket.set_option(option); @@ -241,7 +241,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::send_buffer_size option; * socket.get_option(option); @@ -266,7 +266,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::send_low_watermark option(1024); * socket.set_option(option); @@ -275,7 +275,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::send_low_watermark option; * socket.get_option(option); @@ -300,7 +300,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::receive_buffer_size option(8192); * socket.set_option(option); @@ -309,7 +309,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::receive_buffer_size option; * socket.get_option(option); @@ -334,7 +334,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::receive_low_watermark option(1024); * socket.set_option(option); @@ -343,7 +343,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::receive_low_watermark option; * socket.get_option(option); @@ -369,7 +369,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::socket_base::reuse_address option(true); * acceptor.set_option(option); @@ -378,7 +378,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::socket_base::reuse_address option; * acceptor.get_option(option); @@ -404,7 +404,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::linger option(true, 30); * socket.set_option(option); @@ -413,7 +413,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::linger option; * socket.get_option(option); @@ -432,6 +432,40 @@ public: linger; #endif + /// Socket option for putting received out-of-band data inline. + /** + * Implements the SOL_SOCKET/SO_OOBINLINE socket option. + * + * @par Examples + * Setting the option: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::socket_base::out_of_band_inline option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * asio::ip::tcp::socket socket(my_context); + * ... + * asio::socket_base::out_of_band_inline option; + * socket.get_option(option); + * bool value = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined out_of_band_inline; +#else + typedef asio::detail::socket_option::boolean< + ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_OOBINLINE)> + out_of_band_inline; +#endif + /// Socket option to report aborted connections on accept. /** * Implements a custom socket option that determines whether or not an accept @@ -441,7 +475,7 @@ public: * @par Examples * Setting the option: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::socket_base::enable_connection_aborted option(true); * acceptor.set_option(option); @@ -450,7 +484,7 @@ public: * @par * Getting the current option value: * @code - * asio::ip::tcp::acceptor acceptor(io_context); + * asio::ip::tcp::acceptor acceptor(my_context); * ... * asio::socket_base::enable_connection_aborted option; * acceptor.get_option(option); @@ -476,7 +510,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::socket_base::bytes_readable command(true); * socket.io_control(command); diff --git a/3rdparty/asio/include/asio/spawn.hpp b/3rdparty/asio/include/asio/spawn.hpp index cffe4312e5d..eeacb49de6d 100644 --- a/3rdparty/asio/include/asio/spawn.hpp +++ b/3rdparty/asio/include/asio/spawn.hpp @@ -2,7 +2,7 @@ // spawn.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,28 +16,162 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include <boost/coroutine/all.hpp> -#include "asio/bind_executor.hpp" +#include "asio/any_io_executor.hpp" +#include "asio/cancellation_signal.hpp" +#include "asio/cancellation_state.hpp" +#include "asio/detail/exception.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/type_traits.hpp" -#include "asio/detail/wrapped_handler.hpp" -#include "asio/executor.hpp" #include "asio/io_context.hpp" #include "asio/is_executor.hpp" #include "asio/strand.hpp" +#if defined(ASIO_HAS_BOOST_COROUTINE) +# include <boost/coroutine/all.hpp> +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + +// Base class for all spawn()-ed thread implementations. +class spawned_thread_base +{ +public: + spawned_thread_base() + : owner_(0), + has_context_switched_(false), + throw_if_cancelled_(false), + terminal_(false) + { + } + + virtual ~spawned_thread_base() {} + virtual void resume() = 0; + virtual void suspend_with(void (*fn)(void*), void* arg) = 0; + virtual void destroy() = 0; + + void attach(spawned_thread_base** owner) + { + owner_ = owner; + *owner_ = this; + } + + void detach() + { + if (owner_) + *owner_ = 0; + owner_ = 0; + } + + void suspend() + { + suspend_with(0, 0); + } + + template <typename F> + void suspend_with(F f) + { + suspend_with(&spawned_thread_base::call<F>, &f); + } + + cancellation_slot get_cancellation_slot() const noexcept + { + return cancellation_state_.slot(); + } + + cancellation_state get_cancellation_state() const noexcept + { + return cancellation_state_; + } + + void reset_cancellation_state() + { + cancellation_state_ = cancellation_state(parent_cancellation_slot_); + } + + template <typename Filter> + void reset_cancellation_state(Filter filter) + { + cancellation_state_ = cancellation_state( + parent_cancellation_slot_, filter, filter); + } + + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(InFilter in_filter, OutFilter out_filter) + { + cancellation_state_ = cancellation_state( + parent_cancellation_slot_, in_filter, out_filter); + } + + cancellation_type_t cancelled() const noexcept + { + return cancellation_state_.cancelled(); + } + + bool has_context_switched() const noexcept + { + return has_context_switched_; + } + + bool throw_if_cancelled() const noexcept + { + return throw_if_cancelled_; + } -/// Context object the represents the currently executing coroutine. + void throw_if_cancelled(bool value) noexcept + { + throw_if_cancelled_ = value; + } + +protected: + spawned_thread_base** owner_; // Points to data member in active handler. + asio::cancellation_slot parent_cancellation_slot_; + asio::cancellation_state cancellation_state_; + bool has_context_switched_; + bool throw_if_cancelled_; + bool terminal_; + +private: + // Disallow copying and assignment. + spawned_thread_base(const spawned_thread_base&) = delete; + spawned_thread_base& operator=(const spawned_thread_base&) = delete; + + template <typename F> + static void call(void* f) + { + (*static_cast<F*>(f))(); + } +}; + + +template <typename T> +struct spawn_signature +{ + typedef void type(exception_ptr, T); +}; + +template <> +struct spawn_signature<void> +{ + typedef void type(exception_ptr); +}; + +template <typename Executor> +class initiate_spawn; + +} // namespace detail + +/// A @ref completion_token that represents the currently executing coroutine. /** - * The basic_yield_context class is used to represent the currently executing - * stackful coroutine. A basic_yield_context may be passed as a handler to an - * asynchronous operation. For example: + * The basic_yield_context class is a completion token type that is used to + * represent the currently executing stackful coroutine. A basic_yield_context + * object may be passed as a completion token to an asynchronous operation. For + * example: * - * @code template <typename Handler> - * void my_coroutine(basic_yield_context<Handler> yield) + * @code template <typename Executor> + * void my_coroutine(basic_yield_context<Executor> yield) * { * ... * std::size_t n = my_socket.async_read_some(buffer, yield); @@ -48,67 +182,112 @@ namespace asio { * current coroutine. The coroutine is resumed when the asynchronous operation * completes, and the result of the operation is returned. */ -template <typename Handler> +template <typename Executor> class basic_yield_context { public: - /// The coroutine callee type, used by the implementation. + /// The executor type associated with the yield context. + typedef Executor executor_type; + + /// The cancellation slot type associated with the yield context. + typedef cancellation_slot cancellation_slot_type; + + /// Construct a yield context from another yield context type. /** - * When using Boost.Coroutine v1, this type is: - * @code typename coroutine<void()> @endcode - * When using Boost.Coroutine v2 (unidirectional coroutines), this type is: - * @code push_coroutine<void> @endcode + * Requires that OtherExecutor be convertible to Executor. */ -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined callee_type; -#elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2) - typedef boost::coroutines::push_coroutine<void> callee_type; -#else - typedef boost::coroutines::coroutine<void()> callee_type; -#endif - - /// The coroutine caller type, used by the implementation. + template <typename OtherExecutor> + basic_yield_context(const basic_yield_context<OtherExecutor>& other, + constraint_t< + is_convertible<OtherExecutor, Executor>::value + > = 0) + : spawned_thread_(other.spawned_thread_), + executor_(other.executor_), + ec_(other.ec_) + { + } + + /// Get the executor associated with the yield context. + executor_type get_executor() const noexcept + { + return executor_; + } + + /// Get the cancellation slot associated with the coroutine. + cancellation_slot_type get_cancellation_slot() const noexcept + { + return spawned_thread_->get_cancellation_slot(); + } + + /// Get the cancellation state associated with the coroutine. + cancellation_state get_cancellation_state() const noexcept + { + return spawned_thread_->get_cancellation_state(); + } + + /// Reset the cancellation state associated with the coroutine. /** - * When using Boost.Coroutine v1, this type is: - * @code typename coroutine<void()>::caller_type @endcode - * When using Boost.Coroutine v2 (unidirectional coroutines), this type is: - * @code pull_coroutine<void> @endcode + * Let <tt>P</tt> be the cancellation slot associated with the current + * coroutine's @ref spawn completion handler. Assigns a new + * asio::cancellation_state object <tt>S</tt>, constructed as + * <tt>S(P)</tt>, into the current coroutine's cancellation state object. */ -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined caller_type; -#elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2) - typedef boost::coroutines::pull_coroutine<void> caller_type; -#else - typedef boost::coroutines::coroutine<void()>::caller_type caller_type; -#endif - - /// Construct a yield context to represent the specified coroutine. + void reset_cancellation_state() const + { + spawned_thread_->reset_cancellation_state(); + } + + /// Reset the cancellation state associated with the coroutine. /** - * Most applications do not need to use this constructor. Instead, the - * spawn() function passes a yield context as an argument to the coroutine - * function. + * Let <tt>P</tt> be the cancellation slot associated with the current + * coroutine's @ref spawn completion handler. Assigns a new + * asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P, + * std::forward<Filter>(filter))</tt>, into the current coroutine's + * cancellation state object. */ - basic_yield_context( - const detail::weak_ptr<callee_type>& coro, - caller_type& ca, Handler& handler) - : coro_(coro), - ca_(ca), - handler_(handler), - ec_(0) + template <typename Filter> + void reset_cancellation_state(Filter&& filter) const { + spawned_thread_->reset_cancellation_state( + static_cast<Filter&&>(filter)); } - /// Construct a yield context from another yield context type. + /// Reset the cancellation state associated with the coroutine. /** - * Requires that OtherHandler be convertible to Handler. + * Let <tt>P</tt> be the cancellation slot associated with the current + * coroutine's @ref spawn completion handler. Assigns a new + * asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P, + * std::forward<InFilter>(in_filter), + * std::forward<OutFilter>(out_filter))</tt>, into the current coroutine's + * cancellation state object. */ - template <typename OtherHandler> - basic_yield_context(const basic_yield_context<OtherHandler>& other) - : coro_(other.coro_), - ca_(other.ca_), - handler_(other.handler_), - ec_(other.ec_) + template <typename InFilter, typename OutFilter> + void reset_cancellation_state(InFilter&& in_filter, + OutFilter&& out_filter) const { + spawned_thread_->reset_cancellation_state( + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)); + } + + /// Determine whether the current coroutine has been cancelled. + cancellation_type_t cancelled() const noexcept + { + return spawned_thread_->cancelled(); + } + + /// Determine whether the coroutine throws if trying to suspend when it has + /// been cancelled. + bool throw_if_cancelled() const noexcept + { + return spawned_thread_->throw_if_cancelled(); + } + + /// Set whether the coroutine throws if trying to suspend when it has been + /// cancelled. + void throw_if_cancelled(bool value) const noexcept + { + spawned_thread_->throw_if_cancelled(value); } /// Return a yield context that sets the specified error_code. @@ -118,8 +297,8 @@ public: * operator may be used to specify an error_code object that should instead be * set with the asynchronous operation's result. For example: * - * @code template <typename Handler> - * void my_coroutine(basic_yield_context<Handler> yield) + * @code template <typename Executor> + * void my_coroutine(basic_yield_context<Executor> yield) * { * ... * std::size_t n = my_socket.async_read_some(buffer, yield[ec]); @@ -137,22 +316,25 @@ public: return tmp; } -#if defined(GENERATING_DOCUMENTATION) -private: -#endif // defined(GENERATING_DOCUMENTATION) - detail::weak_ptr<callee_type> coro_; - caller_type& ca_; - Handler handler_; +#if !defined(GENERATING_DOCUMENTATION) +//private: + basic_yield_context(detail::spawned_thread_base* spawned_thread, + const Executor& ex) + : spawned_thread_(spawned_thread), + executor_(ex), + ec_(0) + { + } + + detail::spawned_thread_base* spawned_thread_; + Executor executor_; asio::error_code* ec_; +#endif // !defined(GENERATING_DOCUMENTATION) }; -#if defined(GENERATING_DOCUMENTATION) -/// Context object that represents the currently executing coroutine. -typedef basic_yield_context<unspecified> yield_context; -#else // defined(GENERATING_DOCUMENTATION) -typedef basic_yield_context< - executor_binder<void(*)(), executor> > yield_context; -#endif // defined(GENERATING_DOCUMENTATION) +/// A @ref completion_token object that represents the currently executing +/// coroutine. +typedef basic_yield_context<any_io_executor> yield_context; /** * @defgroup spawn asio::spawn @@ -163,7 +345,7 @@ typedef basic_yield_context< * library. This function enables programs to implement asynchronous logic in a * synchronous manner, as illustrated by the following example: * - * @code asio::spawn(my_strand, do_echo); + * @code asio::spawn(my_strand, do_echo, asio::detached); * * // ... * @@ -190,23 +372,363 @@ typedef basic_yield_context< */ /*@{*/ -/// Start a new stackful coroutine, calling the specified handler when it -/// completes. +/// Start a new stackful coroutine that executes on a given executor. +/** + * This function is used to launch a new stackful coroutine. + * + * @param ex Identifies the executor that will run the stackful coroutine. + * + * @param function The coroutine function. The function must be callable the + * signature: + * @code void function(basic_yield_context<Executor> yield); @endcode + * + * @param token The @ref completion_token that will handle the notification + * that the coroutine has completed. If the return type @c R of @c function is + * @c void, the function signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the return type of the function object. + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call the basic_yield_context member function + * @c reset_cancellation_state. + */ +template <typename Executor, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) + CompletionToken = default_completion_token_t<Executor>> +auto spawn(const Executor& ex, F&& function, + CompletionToken&& token = default_completion_token_t<Executor>(), +#if defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + !is_same< + decay_t<CompletionToken>, + boost::coroutines::attributes + >::value + > = 0, +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), + token, static_cast<F&&>(function))); + +/// Start a new stackful coroutine that executes on a given execution context. +/** + * This function is used to launch a new stackful coroutine. + * + * @param ctx Identifies the execution context that will run the stackful + * coroutine. + * + * @param function The coroutine function. The function must be callable the + * signature: + * @code void function(basic_yield_context<Executor> yield); @endcode + * + * @param token The @ref completion_token that will handle the notification + * that the coroutine has completed. If the return type @c R of @c function is + * @c void, the function signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the return type of the function object. + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call the basic_yield_context member function + * @c reset_cancellation_state. + */ +template <typename ExecutionContext, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type) + CompletionToken = default_completion_token_t< + typename ExecutionContext::executor_type>> +auto spawn(ExecutionContext& ctx, F&& function, + CompletionToken&& token + = default_completion_token_t<typename ExecutionContext::executor_type>(), +#if defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + !is_same< + decay_t<CompletionToken>, + boost::coroutines::attributes + >::value + > = 0, +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type>( + declval<detail::initiate_spawn< + typename ExecutionContext::executor_type>>(), + token, static_cast<F&&>(function))); + +/// Start a new stackful coroutine, inheriting the executor of another. +/** + * This function is used to launch a new stackful coroutine. + * + * @param ctx Identifies the current coroutine as a parent of the new + * coroutine. This specifies that the new coroutine should inherit the executor + * of the parent. For example, if the parent coroutine is executing in a + * particular strand, then the new coroutine will execute in the same strand. + * + * @param function The coroutine function. The function must be callable the + * signature: + * @code void function(basic_yield_context<Executor> yield); @endcode + * + * @param token The @ref completion_token that will handle the notification + * that the coroutine has completed. If the return type @c R of @c function is + * @c void, the function signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the return type of the function object. + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call the basic_yield_context member function + * @c reset_cancellation_state. + */ +template <typename Executor, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) + CompletionToken = default_completion_token_t<Executor>> +auto spawn(const basic_yield_context<Executor>& ctx, F&& function, + CompletionToken&& token = default_completion_token_t<Executor>(), +#if defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + !is_same< + decay_t<CompletionToken>, + boost::coroutines::attributes + >::value + > = 0, +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), + token, static_cast<F&&>(function))); + +#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) \ + || defined(GENERATING_DOCUMENTATION) + +/// Start a new stackful coroutine that executes on a given executor. +/** + * This function is used to launch a new stackful coroutine using the + * specified stack allocator. + * + * @param ex Identifies the executor that will run the stackful coroutine. + * + * @param stack_allocator Denotes the allocator to be used to allocate the + * underlying coroutine's stack. The type must satisfy the stack-allocator + * concept defined by the Boost.Context library. + * + * @param function The coroutine function. The function must be callable the + * signature: + * @code void function(basic_yield_context<Executor> yield); @endcode + * + * @param token The @ref completion_token that will handle the notification + * that the coroutine has completed. If the return type @c R of @c function is + * @c void, the function signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the return type of the function object. + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call the basic_yield_context member function + * @c reset_cancellation_state. + */ +template <typename Executor, typename StackAllocator, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) + CompletionToken = default_completion_token_t<Executor>> +auto spawn(const Executor& ex, allocator_arg_t, + StackAllocator&& stack_allocator, F&& function, + CompletionToken&& token = default_completion_token_t<Executor>(), + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), + token, allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function))); + +/// Start a new stackful coroutine that executes on a given execution context. +/** + * This function is used to launch a new stackful coroutine. + * + * @param ctx Identifies the execution context that will run the stackful + * coroutine. + * + * @param stack_allocator Denotes the allocator to be used to allocate the + * underlying coroutine's stack. The type must satisfy the stack-allocator + * concept defined by the Boost.Context library. + * + * @param function The coroutine function. The function must be callable the + * signature: + * @code void function(basic_yield_context<Executor> yield); @endcode + * + * @param token The @ref completion_token that will handle the notification + * that the coroutine has completed. If the return type @c R of @c function is + * @c void, the function signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the return type of the function object. + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call the basic_yield_context member function + * @c reset_cancellation_state. + */ +template <typename ExecutionContext, typename StackAllocator, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type) + CompletionToken = default_completion_token_t< + typename ExecutionContext::executor_type>> +auto spawn(ExecutionContext& ctx, allocator_arg_t, + StackAllocator&& stack_allocator, F&& function, + CompletionToken&& token + = default_completion_token_t<typename ExecutionContext::executor_type>(), + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context< + typename ExecutionContext::executor_type>)>>::type>( + declval<detail::initiate_spawn< + typename ExecutionContext::executor_type>>(), + token, allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function))); + +/// Start a new stackful coroutine, inheriting the executor of another. +/** + * This function is used to launch a new stackful coroutine using the + * specified stack allocator. + * + * @param ctx Identifies the current coroutine as a parent of the new + * coroutine. This specifies that the new coroutine should inherit the + * executor of the parent. For example, if the parent coroutine is executing + * in a particular strand, then the new coroutine will execute in the same + * strand. + * + * @param stack_allocator Denotes the allocator to be used to allocate the + * underlying coroutine's stack. The type must satisfy the stack-allocator + * concept defined by the Boost.Context library. + * + * @param function The coroutine function. The function must be callable the + * signature: + * @code void function(basic_yield_context<Executor> yield); @endcode + * + * @param token The @ref completion_token that will handle the notification + * that the coroutine has completed. If the return type @c R of @c function is + * @c void, the function signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * @par Completion Signature + * @code void(std::exception_ptr, R) @endcode + * where @c R is the return type of the function object. + * + * @par Per-Operation Cancellation + * The new thread of execution is created with a cancellation state that + * supports @c cancellation_type::terminal values only. To change the + * cancellation state, call the basic_yield_context member function + * @c reset_cancellation_state. + */ +template <typename Executor, typename StackAllocator, typename F, + ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type) + CompletionToken = default_completion_token_t<Executor>> +auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t, + StackAllocator&& stack_allocator, F&& function, + CompletionToken&& token = default_completion_token_t<Executor>(), + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) + -> decltype( + async_initiate<CompletionToken, + typename detail::spawn_signature< + result_of_t<F(basic_yield_context<Executor>)>>::type>( + declval<detail::initiate_spawn<Executor>>(), + token, allocator_arg_t(), + static_cast<StackAllocator&&>(stack_allocator), + static_cast<F&&>(function))); + +#endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER) + // || defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_BOOST_COROUTINE) \ + || defined(GENERATING_DOCUMENTATION) + +/// (Deprecated: Use overloads with a completion token.) Start a new stackful +/// coroutine, calling the specified handler when it completes. /** * This function is used to launch a new coroutine. * * @param function The coroutine function. The function must have the signature: - * @code void function(basic_yield_context<Handler> yield); @endcode + * @code void function(basic_yield_context<Executor> yield); @endcode + * where Executor is the associated executor type of @c Function. * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function> -void spawn(ASIO_MOVE_ARG(Function) function, +void spawn(Function&& function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); -/// Start a new stackful coroutine, calling the specified handler when it -/// completes. +/// (Deprecated: Use overloads with a completion token.) Start a new stackful +/// coroutine, calling the specified handler when it completes. /** * This function is used to launch a new coroutine. * @@ -216,19 +738,23 @@ void spawn(ASIO_MOVE_ARG(Function) function, * @code void handler(); @endcode * * @param function The coroutine function. The function must have the signature: - * @code void function(basic_yield_context<Handler> yield); @endcode + * @code void function(basic_yield_context<Executor> yield); @endcode + * where Executor is the associated executor type of @c Handler. * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Handler, typename Function> -void spawn(ASIO_MOVE_ARG(Handler) handler, - ASIO_MOVE_ARG(Function) function, +void spawn(Handler&& handler, Function&& function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), - typename enable_if<!is_executor<typename decay<Handler>::type>::value && - !is_convertible<Handler&, execution_context&>::value>::type* = 0); + constraint_t< + !is_executor<decay_t<Handler>>::value && + !execution::is_executor<decay_t<Handler>>::value && + !is_convertible<Handler&, execution_context&>::value + > = 0); -/// Start a new stackful coroutine, inheriting the execution context of another. +/// (Deprecated: Use overloads with a completion token.) Start a new stackful +/// coroutine, inheriting the execution context of another. /** * This function is used to launch a new coroutine. * @@ -239,22 +765,23 @@ void spawn(ASIO_MOVE_ARG(Handler) handler, * same strand. * * @param function The coroutine function. The function must have the signature: - * @code void function(basic_yield_context<Handler> yield); @endcode + * @code void function(basic_yield_context<Executor> yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ -template <typename Handler, typename Function> -void spawn(basic_yield_context<Handler> ctx, - ASIO_MOVE_ARG(Function) function, +template <typename Executor, typename Function> +void spawn(basic_yield_context<Executor> ctx, Function&& function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); -/// Start a new stackful coroutine that executes on a given executor. +/// (Deprecated: Use overloads with a completion token.) Start a new stackful +/// coroutine that executes on a given executor. /** * This function is used to launch a new coroutine. * * @param ex Identifies the executor that will run the coroutine. The new - * coroutine is implicitly given its own strand within this executor. + * coroutine is automatically given its own explicit strand within this + * executor. * * @param function The coroutine function. The function must have the signature: * @code void function(yield_context yield); @endcode @@ -262,13 +789,15 @@ void spawn(basic_yield_context<Handler> ctx, * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function, typename Executor> -void spawn(const Executor& ex, - ASIO_MOVE_ARG(Function) function, +void spawn(const Executor& ex, Function&& function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), - typename enable_if<is_executor<Executor>::value>::type* = 0); + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0); -/// Start a new stackful coroutine that executes on a given strand. +/// (Deprecated: Use overloads with a completion token.) Start a new stackful +/// coroutine that executes on a given strand. /** * This function is used to launch a new coroutine. * @@ -280,12 +809,14 @@ void spawn(const Executor& ex, * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function, typename Executor> -void spawn(const strand<Executor>& ex, - ASIO_MOVE_ARG(Function) function, +void spawn(const strand<Executor>& ex, Function&& function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); -/// Start a new stackful coroutine that executes in the context of a strand. +#if !defined(ASIO_NO_TS_EXECUTORS) + +/// (Deprecated: Use overloads with a completion token.) Start a new stackful +/// coroutine that executes in the context of a strand. /** * This function is used to launch a new coroutine. * @@ -299,12 +830,14 @@ void spawn(const strand<Executor>& ex, * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function> -void spawn(const asio::io_context::strand& s, - ASIO_MOVE_ARG(Function) function, +void spawn(const asio::io_context::strand& s, Function&& function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); -/// Start a new stackful coroutine that executes on a given execution context. +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +/// (Deprecated: Use overloads with a completion token.) Start a new stackful +/// coroutine that executes on a given execution context. /** * This function is used to launch a new coroutine. * @@ -318,12 +851,15 @@ void spawn(const asio::io_context::strand& s, * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function, typename ExecutionContext> -void spawn(ExecutionContext& ctx, - ASIO_MOVE_ARG(Function) function, +void spawn(ExecutionContext& ctx, Function&& function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), - typename enable_if<is_convertible< - ExecutionContext&, execution_context&>::value>::type* = 0); + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0); + +#endif // defined(ASIO_HAS_BOOST_COROUTINE) + // || defined(GENERATING_DOCUMENTATION) /*@}*/ diff --git a/3rdparty/asio/include/asio/ssl.hpp b/3rdparty/asio/include/asio/ssl.hpp index bc3dae03c9c..4180dab6f42 100644 --- a/3rdparty/asio/include/asio/ssl.hpp +++ b/3rdparty/asio/include/asio/ssl.hpp @@ -2,7 +2,7 @@ // ssl.hpp // ~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,7 @@ #include "asio/ssl/context_base.hpp" #include "asio/ssl/error.hpp" #include "asio/ssl/rfc2818_verification.hpp" +#include "asio/ssl/host_name_verification.hpp" #include "asio/ssl/stream.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/verify_context.hpp" diff --git a/3rdparty/asio/include/asio/ssl/context.hpp b/3rdparty/asio/include/asio/ssl/context.hpp index 6e3f2ad3013..a41904a4089 100644 --- a/3rdparty/asio/include/asio/ssl/context.hpp +++ b/3rdparty/asio/include/asio/ssl/context.hpp @@ -2,7 +2,7 @@ // ssl/context.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -43,7 +43,9 @@ public: /// Constructor. ASIO_DECL explicit context(method m); -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct to take ownership of a native handle. + ASIO_DECL explicit context(native_handle_type native_handle); + /// Move-construct a context from another. /** * This constructor moves an SSL context from one object to another. @@ -69,7 +71,6 @@ public: * @li As a target for move-assignment. */ ASIO_DECL context& operator=(context&& other); -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. ASIO_DECL ~context(); @@ -738,6 +739,9 @@ private: // Helper function to make a BIO from a memory buffer. ASIO_DECL BIO* make_buffer_bio(const const_buffer& b); + // Translate an SSL error into an error code. + ASIO_DECL static asio::error_code translate_error(long error); + // The underlying native implementation. native_handle_type handle_; diff --git a/3rdparty/asio/include/asio/ssl/context_base.hpp b/3rdparty/asio/include/asio/ssl/context_base.hpp index b3af107d513..36271012b06 100644 --- a/3rdparty/asio/include/asio/ssl/context_base.hpp +++ b/3rdparty/asio/include/asio/ssl/context_base.hpp @@ -2,7 +2,7 @@ // ssl/context_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -83,56 +83,82 @@ public: tlsv12_client, /// TLS version 1.2 server. - tlsv12_server + tlsv12_server, + + /// Generic TLS version 1.3. + tlsv13, + + /// TLS version 1.3 client. + tlsv13_client, + + /// TLS version 1.3 server. + tlsv13_server, + + /// Generic TLS. + tls, + + /// TLS client. + tls_client, + + /// TLS server. + tls_server }; /// Bitmask type for SSL options. - typedef long options; + typedef uint64_t options; #if defined(GENERATING_DOCUMENTATION) /// Implement various bug workarounds. - static const long default_workarounds = implementation_defined; + static const uint64_t default_workarounds = implementation_defined; /// Always create a new key when using tmp_dh parameters. - static const long single_dh_use = implementation_defined; + static const uint64_t single_dh_use = implementation_defined; /// Disable SSL v2. - static const long no_sslv2 = implementation_defined; + static const uint64_t no_sslv2 = implementation_defined; /// Disable SSL v3. - static const long no_sslv3 = implementation_defined; + static const uint64_t no_sslv3 = implementation_defined; /// Disable TLS v1. - static const long no_tlsv1 = implementation_defined; + static const uint64_t no_tlsv1 = implementation_defined; /// Disable TLS v1.1. - static const long no_tlsv1_1 = implementation_defined; + static const uint64_t no_tlsv1_1 = implementation_defined; /// Disable TLS v1.2. - static const long no_tlsv1_2 = implementation_defined; + static const uint64_t no_tlsv1_2 = implementation_defined; + + /// Disable TLS v1.3. + static const uint64_t no_tlsv1_3 = implementation_defined; /// Disable compression. Compression is disabled by default. - static const long no_compression = implementation_defined; + static const uint64_t no_compression = implementation_defined; #else - ASIO_STATIC_CONSTANT(long, default_workarounds = SSL_OP_ALL); - ASIO_STATIC_CONSTANT(long, single_dh_use = SSL_OP_SINGLE_DH_USE); - ASIO_STATIC_CONSTANT(long, no_sslv2 = SSL_OP_NO_SSLv2); - ASIO_STATIC_CONSTANT(long, no_sslv3 = SSL_OP_NO_SSLv3); - ASIO_STATIC_CONSTANT(long, no_tlsv1 = SSL_OP_NO_TLSv1); + ASIO_STATIC_CONSTANT(uint64_t, default_workarounds = SSL_OP_ALL); + ASIO_STATIC_CONSTANT(uint64_t, single_dh_use = SSL_OP_SINGLE_DH_USE); + ASIO_STATIC_CONSTANT(uint64_t, no_sslv2 = SSL_OP_NO_SSLv2); + ASIO_STATIC_CONSTANT(uint64_t, no_sslv3 = SSL_OP_NO_SSLv3); + ASIO_STATIC_CONSTANT(uint64_t, no_tlsv1 = SSL_OP_NO_TLSv1); # if defined(SSL_OP_NO_TLSv1_1) - ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = SSL_OP_NO_TLSv1_1); + ASIO_STATIC_CONSTANT(uint64_t, no_tlsv1_1 = SSL_OP_NO_TLSv1_1); # else // defined(SSL_OP_NO_TLSv1_1) - ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = 0x10000000L); + ASIO_STATIC_CONSTANT(uint64_t, no_tlsv1_1 = 0x10000000L); # endif // defined(SSL_OP_NO_TLSv1_1) # if defined(SSL_OP_NO_TLSv1_2) - ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = SSL_OP_NO_TLSv1_2); + ASIO_STATIC_CONSTANT(uint64_t, no_tlsv1_2 = SSL_OP_NO_TLSv1_2); # else // defined(SSL_OP_NO_TLSv1_2) - ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = 0x08000000L); + ASIO_STATIC_CONSTANT(uint64_t, no_tlsv1_2 = 0x08000000L); # endif // defined(SSL_OP_NO_TLSv1_2) +# if defined(SSL_OP_NO_TLSv1_3) + ASIO_STATIC_CONSTANT(uint64_t, no_tlsv1_3 = SSL_OP_NO_TLSv1_3); +# else // defined(SSL_OP_NO_TLSv1_3) + ASIO_STATIC_CONSTANT(uint64_t, no_tlsv1_3 = 0x20000000L); +# endif // defined(SSL_OP_NO_TLSv1_3) # if defined(SSL_OP_NO_COMPRESSION) - ASIO_STATIC_CONSTANT(long, no_compression = SSL_OP_NO_COMPRESSION); + ASIO_STATIC_CONSTANT(uint64_t, no_compression = SSL_OP_NO_COMPRESSION); # else // defined(SSL_OP_NO_COMPRESSION) - ASIO_STATIC_CONSTANT(long, no_compression = 0x20000L); + ASIO_STATIC_CONSTANT(uint64_t, no_compression = 0x20000L); # endif // defined(SSL_OP_NO_COMPRESSION) #endif diff --git a/3rdparty/asio/include/asio/ssl/detail/buffered_handshake_op.hpp b/3rdparty/asio/include/asio/ssl/detail/buffered_handshake_op.hpp index e661bdef392..4dba7120929 100644 --- a/3rdparty/asio/include/asio/ssl/detail/buffered_handshake_op.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/buffered_handshake_op.hpp @@ -2,7 +2,7 @@ // ssl/detail/buffered_handshake_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -29,6 +29,11 @@ template <typename ConstBufferSequence> class buffered_handshake_op { public: + static constexpr const char* tracking_name() + { + return "ssl::stream<>::async_buffered_handshake"; + } + buffered_handshake_op(stream_base::handshake_type type, const ConstBufferSequence& buffers) : type_(type), @@ -51,7 +56,7 @@ public: const asio::error_code& ec, const std::size_t& bytes_transferred) const { - handler(ec, bytes_transferred); + static_cast<Handler&&>(handler)(ec, bytes_transferred); } private: diff --git a/3rdparty/asio/include/asio/ssl/detail/engine.hpp b/3rdparty/asio/include/asio/ssl/detail/engine.hpp index c9ea33b1bb9..e500ca529da 100644 --- a/3rdparty/asio/include/asio/ssl/detail/engine.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/engine.hpp @@ -2,7 +2,7 @@ // ssl/detail/engine.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -58,9 +58,18 @@ public: // Construct a new engine for the specified context. ASIO_DECL explicit engine(SSL_CTX* context); + // Construct a new engine for an existing native SSL implementation. + ASIO_DECL explicit engine(SSL* ssl_impl); + + // Move construct from another engine. + ASIO_DECL engine(engine&& other) noexcept; + // Destructor. ASIO_DECL ~engine(); + // Move assign from another engine. + ASIO_DECL engine& operator=(engine&& other) noexcept; + // Get the underlying implementation in the native type. ASIO_DECL SSL* native_handle(); diff --git a/3rdparty/asio/include/asio/ssl/detail/handshake_op.hpp b/3rdparty/asio/include/asio/ssl/detail/handshake_op.hpp index b6848ea62e5..53533eb7a80 100644 --- a/3rdparty/asio/include/asio/ssl/detail/handshake_op.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/handshake_op.hpp @@ -2,7 +2,7 @@ // ssl/detail/handshake_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -28,6 +28,11 @@ namespace detail { class handshake_op { public: + static constexpr const char* tracking_name() + { + return "ssl::stream<>::async_handshake"; + } + handshake_op(stream_base::handshake_type type) : type_(type) { @@ -46,7 +51,7 @@ public: const asio::error_code& ec, const std::size_t&) const { - handler(ec); + static_cast<Handler&&>(handler)(ec); } private: diff --git a/3rdparty/asio/include/asio/ssl/detail/impl/engine.ipp b/3rdparty/asio/include/asio/ssl/detail/impl/engine.ipp index 55661492952..91588cd6b47 100644 --- a/3rdparty/asio/include/asio/ssl/detail/impl/engine.ipp +++ b/3rdparty/asio/include/asio/ssl/detail/impl/engine.ipp @@ -2,7 +2,7 @@ // ssl/detail/impl/engine.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -55,16 +55,57 @@ engine::engine(SSL_CTX* context) ::SSL_set_bio(ssl_, int_bio, int_bio); } +engine::engine(SSL* ssl_impl) + : ssl_(ssl_impl) +{ +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) + accept_mutex().init(); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + + ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE); + ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); +#if defined(SSL_MODE_RELEASE_BUFFERS) + ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS); +#endif // defined(SSL_MODE_RELEASE_BUFFERS) + + ::BIO* int_bio = 0; + ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0); + ::SSL_set_bio(ssl_, int_bio, int_bio); +} + +engine::engine(engine&& other) noexcept + : ssl_(other.ssl_), + ext_bio_(other.ext_bio_) +{ + other.ssl_ = 0; + other.ext_bio_ = 0; +} + engine::~engine() { - if (SSL_get_app_data(ssl_)) + if (ssl_ && SSL_get_app_data(ssl_)) { delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_)); SSL_set_app_data(ssl_, 0); } - ::BIO_free(ext_bio_); - ::SSL_free(ssl_); + if (ext_bio_) + ::BIO_free(ext_bio_); + + if (ssl_) + ::SSL_free(ssl_); +} + +engine& engine::operator=(engine&& other) noexcept +{ + if (this != &other) + { + ssl_ = other.ssl_; + ext_bio_ = other.ext_bio_; + other.ssl_ = 0; + other.ext_bio_ = 0; + } + return *this; } SSL* engine::native_handle() @@ -204,7 +245,7 @@ const asio::error_code& engine::map_error_code( // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the // underlying transport is passed through. #if (OPENSSL_VERSION_NUMBER < 0x10100000L) - if (ssl_->version == SSL2_VERSION) + if (SSL_version(ssl_) == SSL2_VERSION) return ec; #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) @@ -240,14 +281,23 @@ engine::want engine::perform(int (engine::* op)(void*, std::size_t), { ec = asio::error_code(sys_error, asio::error::get_ssl_category()); - return want_nothing; + return pending_output_after > pending_output_before + ? want_output : want_nothing; } if (ssl_error == SSL_ERROR_SYSCALL) { - ec = asio::error_code(sys_error, - asio::error::get_system_category()); - return want_nothing; + if (sys_error == 0) + { + ec = asio::ssl::error::unspecified_system_error; + } + else + { + ec = asio::error_code(sys_error, + asio::error::get_ssl_category()); + } + return pending_output_after > pending_output_before + ? want_output : want_nothing; } if (result > 0 && bytes_transferred) @@ -268,16 +318,21 @@ engine::want engine::perform(int (engine::* op)(void*, std::size_t), ec = asio::error_code(); return want_input_and_retry; } - else if (::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) + else if (ssl_error == SSL_ERROR_ZERO_RETURN) { ec = asio::error::eof; return want_nothing; } - else + else if (ssl_error == SSL_ERROR_NONE) { ec = asio::error_code(); return want_nothing; } + else + { + ec = asio::ssl::error::unexpected_result; + return want_nothing; + } } int engine::do_accept(void*, std::size_t) diff --git a/3rdparty/asio/include/asio/ssl/detail/impl/openssl_init.ipp b/3rdparty/asio/include/asio/ssl/detail/impl/openssl_init.ipp index 392eff9bc14..7a10cc2aa8a 100644 --- a/3rdparty/asio/include/asio/ssl/detail/impl/openssl_init.ipp +++ b/3rdparty/asio/include/asio/ssl/detail/impl/openssl_init.ipp @@ -3,7 +3,7 @@ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -35,11 +35,11 @@ class openssl_init_base::do_init public: do_init() { +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) ::SSL_library_init(); ::SSL_load_error_strings(); ::OpenSSL_add_all_algorithms(); -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) mutexes_.resize(::CRYPTO_num_locks()); for (size_t i = 0; i < mutexes_.size(); ++i) mutexes_[i].reset(new asio::detail::mutex); @@ -79,13 +79,19 @@ public: ::ERR_remove_thread_state(NULL); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) #if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \ - && (OPENSSL_VERSION_NUMBER < 0x10100000L) + && (OPENSSL_VERSION_NUMBER < 0x10100000L) \ + && !defined(SSL_OP_NO_COMPRESSION) ::SSL_COMP_free_compression_methods(); #endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L) // && (OPENSSL_VERSION_NUMBER < 0x10100000L) -#if !defined(OPENSSL_IS_BORINGSSL) + // && !defined(SSL_OP_NO_COMPRESSION) +#if !defined(OPENSSL_IS_BORINGSSL) \ + && !defined(ASIO_USE_WOLFSSL) \ + && (OPENSSL_VERSION_NUMBER < 0x30000000L) ::CONF_modules_unload(1); #endif // !defined(OPENSSL_IS_BORINGSSL) + // && !defined(ASIO_USE_WOLFSSL) + // && (OPENSSL_VERSION_NUMBER < 0x30000000L) #if !defined(OPENSSL_NO_ENGINE) \ && (OPENSSL_VERSION_NUMBER < 0x10100000L) ::ENGINE_cleanup(); @@ -128,7 +134,7 @@ private: // Mutexes to be used in locking callbacks. std::vector<asio::detail::shared_ptr< - asio::detail::mutex> > mutexes_; + asio::detail::mutex>> mutexes_; #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) #if !defined(SSL_OP_NO_COMPRESSION) \ diff --git a/3rdparty/asio/include/asio/ssl/detail/io.hpp b/3rdparty/asio/include/asio/ssl/detail/io.hpp index 5d35ba45707..d951db593af 100644 --- a/3rdparty/asio/include/asio/ssl/detail/io.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/io.hpp @@ -2,7 +2,7 @@ // ssl/detail/io.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,6 +17,8 @@ #include "asio/detail/config.hpp" +#include "asio/detail/base_from_cancellation_state.hpp" +#include "asio/detail/handler_tracking.hpp" #include "asio/ssl/detail/engine.hpp" #include "asio/ssl/detail/stream_core.hpp" #include "asio/write.hpp" @@ -31,6 +33,7 @@ template <typename Stream, typename Operation> std::size_t io(Stream& next_layer, stream_core& core, const Operation& op, asio::error_code& ec) { + asio::error_code io_ec; std::size_t bytes_transferred = 0; do switch (op(core.engine_, ec, bytes_transferred)) { @@ -39,8 +42,12 @@ std::size_t io(Stream& next_layer, stream_core& core, // If the input buffer is empty then we need to read some more data from // the underlying transport. if (core.input_.size() == 0) + { core.input_ = asio::buffer(core.input_buffer_, - next_layer.read_some(core.input_buffer_, ec)); + next_layer.read_some(core.input_buffer_, io_ec)); + if (!ec) + ec = io_ec; + } // Pass the new input data to the engine. core.input_ = core.engine_.put_input(core.input_); @@ -53,7 +60,9 @@ std::size_t io(Stream& next_layer, stream_core& core, // Get output data from the engine and write it to the underlying // transport. asio::write(next_layer, - core.engine_.get_output(core.output_buffer_), ec); + core.engine_.get_output(core.output_buffer_), io_ec); + if (!ec) + ec = io_ec; // Try the operation again. continue; @@ -63,7 +72,9 @@ std::size_t io(Stream& next_layer, stream_core& core, // Get output data from the engine and write it to the underlying // transport. asio::write(next_layer, - core.engine_.get_output(core.output_buffer_), ec); + core.engine_.get_output(core.output_buffer_), io_ec); + if (!ec) + ec = io_ec; // Operation is complete. Return result to caller. core.engine_.map_error_code(ec); @@ -84,23 +95,25 @@ std::size_t io(Stream& next_layer, stream_core& core, template <typename Stream, typename Operation, typename Handler> class io_op + : public asio::detail::base_from_cancellation_state<Handler> { public: io_op(Stream& next_layer, stream_core& core, const Operation& op, Handler& handler) - : next_layer_(next_layer), + : asio::detail::base_from_cancellation_state<Handler>(handler), + next_layer_(next_layer), core_(core), op_(op), start_(0), want_(engine::want_nothing), bytes_transferred_(0), - handler_(ASIO_MOVE_CAST(Handler)(handler)) + handler_(static_cast<Handler&&>(handler)) { } -#if defined(ASIO_HAS_MOVE) io_op(const io_op& other) - : next_layer_(other.next_layer_), + : asio::detail::base_from_cancellation_state<Handler>(other), + next_layer_(other.next_layer_), core_(other.core_), op_(other.op_), start_(other.start_), @@ -112,17 +125,19 @@ public: } io_op(io_op&& other) - : next_layer_(other.next_layer_), + : asio::detail::base_from_cancellation_state<Handler>( + static_cast< + asio::detail::base_from_cancellation_state<Handler>&&>(other)), + next_layer_(other.next_layer_), core_(other.core_), - op_(other.op_), + op_(static_cast<Operation&&>(other.op_)), start_(other.start_), want_(other.want_), ec_(other.ec_), bytes_transferred_(other.bytes_transferred_), - handler_(ASIO_MOVE_CAST(Handler)(other.handler_)) + handler_(static_cast<Handler&&>(other.handler_)) { } -#endif // defined(ASIO_HAS_MOVE) void operator()(asio::error_code ec, std::size_t bytes_transferred = ~std::size_t(0), int start = 0) @@ -153,15 +168,21 @@ public: // Prevent other read operations from being started. core_.pending_read_.expires_at(core_.pos_infin()); + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Start reading some data from the underlying transport. next_layer_.async_read_some( asio::buffer(core_.input_buffer_), - ASIO_MOVE_CAST(io_op)(*this)); + static_cast<io_op&&>(*this)); } else { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Wait until the current read operation completes. - core_.pending_read_.async_wait(ASIO_MOVE_CAST(io_op)(*this)); + core_.pending_read_.async_wait(static_cast<io_op&&>(*this)); } // Yield control until asynchronous operation completes. Control @@ -180,15 +201,21 @@ public: // Prevent other write operations from being started. core_.pending_write_.expires_at(core_.pos_infin()); + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Start writing all the data to the underlying transport. asio::async_write(next_layer_, core_.engine_.get_output(core_.output_buffer_), - ASIO_MOVE_CAST(io_op)(*this)); + static_cast<io_op&&>(*this)); } else { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Wait until the current write operation completes. - core_.pending_write_.async_wait(ASIO_MOVE_CAST(io_op)(*this)); + core_.pending_write_.async_wait(static_cast<io_op&&>(*this)); } // Yield control until asynchronous operation completes. Control @@ -204,9 +231,12 @@ public: // read so the handler runs "as-if" posted using io_context::post(). if (start) { + ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + next_layer_.async_read_some( asio::buffer(core_.input_buffer_, 0), - ASIO_MOVE_CAST(io_op)(*this)); + static_cast<io_op&&>(*this)); // Yield control until asynchronous operation completes. Control // resumes at the "default:" label below. @@ -237,6 +267,13 @@ public: // Release any waiting read operations. core_.pending_read_.expires_at(core_.neg_infin()); + // Check for cancellation before continuing. + if (this->cancelled() != cancellation_type::none) + { + ec_ = asio::error::operation_aborted; + break; + } + // Try the operation again. continue; @@ -245,6 +282,13 @@ public: // Release any waiting write operations. core_.pending_write_.expires_at(core_.neg_infin()); + // Check for cancellation before continuing. + if (this->cancelled() != cancellation_type::none) + { + ec_ = asio::error::operation_aborted; + break; + } + // Try the operation again. continue; @@ -284,22 +328,6 @@ public: }; template <typename Stream, typename Operation, typename Handler> -inline void* asio_handler_allocate(std::size_t size, - io_op<Stream, Operation, Handler>* this_handler) -{ - return asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); -} - -template <typename Stream, typename Operation, typename Handler> -inline void asio_handler_deallocate(void* pointer, std::size_t size, - io_op<Stream, Operation, Handler>* this_handler) -{ - asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); -} - -template <typename Stream, typename Operation, typename Handler> inline bool asio_handler_is_continuation( io_op<Stream, Operation, Handler>* this_handler) { @@ -307,24 +335,6 @@ inline bool asio_handler_is_continuation( : asio_handler_cont_helpers::is_continuation(this_handler->handler_); } -template <typename Function, typename Stream, - typename Operation, typename Handler> -inline void asio_handler_invoke(Function& function, - io_op<Stream, Operation, Handler>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); -} - -template <typename Function, typename Stream, - typename Operation, typename Handler> -inline void asio_handler_invoke(const Function& function, - io_op<Stream, Operation, Handler>* this_handler) -{ - asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); -} - template <typename Stream, typename Operation, typename Handler> inline void async_io(Stream& next_layer, stream_core& core, const Operation& op, Handler& handler) @@ -337,31 +347,25 @@ inline void async_io(Stream& next_layer, stream_core& core, } // namespace detail } // namespace ssl -template <typename Stream, typename Operation, - typename Handler, typename Allocator> -struct associated_allocator< - ssl::detail::io_op<Stream, Operation, Handler>, Allocator> +template <template <typename, typename> class Associator, + typename Stream, typename Operation, + typename Handler, typename DefaultCandidate> +struct associator<Associator, + ssl::detail::io_op<Stream, Operation, Handler>, + DefaultCandidate> + : Associator<Handler, DefaultCandidate> { - typedef typename associated_allocator<Handler, Allocator>::type type; - - static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, - const Allocator& a = Allocator()) ASIO_NOEXCEPT + static typename Associator<Handler, DefaultCandidate>::type get( + const ssl::detail::io_op<Stream, Operation, Handler>& h) noexcept { - return associated_allocator<Handler, Allocator>::get(h.handler_, a); + return Associator<Handler, DefaultCandidate>::get(h.handler_); } -}; - -template <typename Stream, typename Operation, - typename Handler, typename Executor> -struct associated_executor< - ssl::detail::io_op<Stream, Operation, Handler>, Executor> -{ - typedef typename associated_executor<Handler, Executor>::type type; - static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, - const Executor& ex = Executor()) ASIO_NOEXCEPT + static auto get(const ssl::detail::io_op<Stream, Operation, Handler>& h, + const DefaultCandidate& c) noexcept + -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c)) { - return associated_executor<Handler, Executor>::get(h.handler_, ex); + return Associator<Handler, DefaultCandidate>::get(h.handler_, c); } }; diff --git a/3rdparty/asio/include/asio/ssl/detail/openssl_init.hpp b/3rdparty/asio/include/asio/ssl/detail/openssl_init.hpp index 6144534c989..c66d9d62692 100644 --- a/3rdparty/asio/include/asio/ssl/detail/openssl_init.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/openssl_init.hpp @@ -2,7 +2,7 @@ // ssl/detail/openssl_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ssl/detail/openssl_types.hpp b/3rdparty/asio/include/asio/ssl/detail/openssl_types.hpp index eda740d8099..25f080f1e8e 100644 --- a/3rdparty/asio/include/asio/ssl/detail/openssl_types.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/openssl_types.hpp @@ -2,7 +2,7 @@ // ssl/detail/openssl_types.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,6 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/socket_types.hpp" +#if defined(ASIO_USE_WOLFSSL) +# include <wolfssl/options.h> +#endif // defined(ASIO_USE_WOLFSSL) #include <openssl/conf.h> #include <openssl/ssl.h> #if !defined(OPENSSL_NO_ENGINE) @@ -24,7 +28,7 @@ #include <openssl/dh.h> #include <openssl/err.h> #include <openssl/rsa.h> +#include <openssl/x509.h> #include <openssl/x509v3.h> -#include "asio/detail/socket_types.hpp" #endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP diff --git a/3rdparty/asio/include/asio/ssl/detail/password_callback.hpp b/3rdparty/asio/include/asio/ssl/detail/password_callback.hpp index abff36c6f33..03ac7db0f06 100644 --- a/3rdparty/asio/include/asio/ssl/detail/password_callback.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/password_callback.hpp @@ -2,7 +2,7 @@ // ssl/detail/password_callback.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ssl/detail/read_op.hpp b/3rdparty/asio/include/asio/ssl/detail/read_op.hpp index 2195bc892eb..5cb4249556f 100644 --- a/3rdparty/asio/include/asio/ssl/detail/read_op.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/read_op.hpp @@ -2,7 +2,7 @@ // ssl/detail/read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,6 +30,11 @@ template <typename MutableBufferSequence> class read_op { public: + static constexpr const char* tracking_name() + { + return "ssl::stream<>::async_read_some"; + } + read_op(const MutableBufferSequence& buffers) : buffers_(buffers) { @@ -51,7 +56,7 @@ public: const asio::error_code& ec, const std::size_t& bytes_transferred) const { - handler(ec, bytes_transferred); + static_cast<Handler&&>(handler)(ec, bytes_transferred); } private: diff --git a/3rdparty/asio/include/asio/ssl/detail/shutdown_op.hpp b/3rdparty/asio/include/asio/ssl/detail/shutdown_op.hpp index 974eaa0a423..1f6b91e17c1 100644 --- a/3rdparty/asio/include/asio/ssl/detail/shutdown_op.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/shutdown_op.hpp @@ -2,7 +2,7 @@ // ssl/detail/shutdown_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -28,6 +28,11 @@ namespace detail { class shutdown_op { public: + static constexpr const char* tracking_name() + { + return "ssl::stream<>::async_shutdown"; + } + engine::want operator()(engine& eng, asio::error_code& ec, std::size_t& bytes_transferred) const @@ -41,7 +46,17 @@ public: const asio::error_code& ec, const std::size_t&) const { - handler(ec); + if (ec == asio::error::eof) + { + // The engine only generates an eof when the shutdown notification has + // been received from the peer. This indicates that the shutdown has + // completed successfully, and thus need not be passed on to the handler. + static_cast<Handler&&>(handler)(asio::error_code()); + } + else + { + static_cast<Handler&&>(handler)(ec); + } } }; diff --git a/3rdparty/asio/include/asio/ssl/detail/stream_core.hpp b/3rdparty/asio/include/asio/ssl/detail/stream_core.hpp index 1872912c018..0ec763d4a2b 100644 --- a/3rdparty/asio/include/asio/ssl/detail/stream_core.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/stream_core.hpp @@ -2,7 +2,7 @@ // ssl/detail/stream_core.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -37,10 +37,11 @@ struct stream_core // sufficient to hold the largest possible TLS record. enum { max_tls_record_size = 17 * 1024 }; - stream_core(SSL_CTX* context, asio::io_context& io_context) + template <typename Executor> + stream_core(SSL_CTX* context, const Executor& ex) : engine_(context), - pending_read_(io_context), - pending_write_(io_context), + pending_read_(ex), + pending_write_(ex), output_buffer_space_(max_tls_record_size), output_buffer_(asio::buffer(output_buffer_space_)), input_buffer_space_(max_tls_record_size), @@ -50,10 +51,92 @@ struct stream_core pending_write_.expires_at(neg_infin()); } + template <typename Executor> + stream_core(SSL* ssl_impl, const Executor& ex) + : engine_(ssl_impl), + pending_read_(ex), + pending_write_(ex), + output_buffer_space_(max_tls_record_size), + output_buffer_(asio::buffer(output_buffer_space_)), + input_buffer_space_(max_tls_record_size), + input_buffer_(asio::buffer(input_buffer_space_)) + { + pending_read_.expires_at(neg_infin()); + pending_write_.expires_at(neg_infin()); + } + + stream_core(stream_core&& other) + : engine_(static_cast<engine&&>(other.engine_)), +#if defined(ASIO_HAS_BOOST_DATE_TIME) + pending_read_( + static_cast<asio::deadline_timer&&>( + other.pending_read_)), + pending_write_( + static_cast<asio::deadline_timer&&>( + other.pending_write_)), +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + pending_read_( + static_cast<asio::steady_timer&&>( + other.pending_read_)), + pending_write_( + static_cast<asio::steady_timer&&>( + other.pending_write_)), +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + output_buffer_space_( + static_cast<std::vector<unsigned char>&&>( + other.output_buffer_space_)), + output_buffer_(other.output_buffer_), + input_buffer_space_( + static_cast<std::vector<unsigned char>&&>( + other.input_buffer_space_)), + input_buffer_(other.input_buffer_), + input_(other.input_) + { + other.output_buffer_ = asio::mutable_buffer(0, 0); + other.input_buffer_ = asio::mutable_buffer(0, 0); + other.input_ = asio::const_buffer(0, 0); + } + ~stream_core() { } + stream_core& operator=(stream_core&& other) + { + if (this != &other) + { + engine_ = static_cast<engine&&>(other.engine_); +#if defined(ASIO_HAS_BOOST_DATE_TIME) + pending_read_ = + static_cast<asio::deadline_timer&&>( + other.pending_read_); + pending_write_ = + static_cast<asio::deadline_timer&&>( + other.pending_write_); +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + pending_read_ = + static_cast<asio::steady_timer&&>( + other.pending_read_); + pending_write_ = + static_cast<asio::steady_timer&&>( + other.pending_write_); +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + output_buffer_space_ = + static_cast<std::vector<unsigned char>&&>( + other.output_buffer_space_); + output_buffer_ = other.output_buffer_; + input_buffer_space_ = + static_cast<std::vector<unsigned char>&&>( + other.input_buffer_space_); + input_buffer_ = other.input_buffer_; + input_ = other.input_; + other.output_buffer_ = asio::mutable_buffer(0, 0); + other.input_buffer_ = asio::mutable_buffer(0, 0); + other.input_ = asio::const_buffer(0, 0); + } + return *this; + } + // The SSL engine. engine engine_; @@ -113,13 +196,13 @@ struct stream_core std::vector<unsigned char> output_buffer_space_; // A buffer that may be used to prepare output intended for the transport. - const asio::mutable_buffer output_buffer_; + asio::mutable_buffer output_buffer_; // Buffer space used to read input intended for the engine. std::vector<unsigned char> input_buffer_space_; // A buffer that may be used to read input intended for the engine. - const asio::mutable_buffer input_buffer_; + asio::mutable_buffer input_buffer_; // The buffer pointing to the engine's unconsumed input. asio::const_buffer input_; diff --git a/3rdparty/asio/include/asio/ssl/detail/verify_callback.hpp b/3rdparty/asio/include/asio/ssl/detail/verify_callback.hpp index 288ff66db48..54169c9e6b8 100644 --- a/3rdparty/asio/include/asio/ssl/detail/verify_callback.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/verify_callback.hpp @@ -1,8 +1,8 @@ // // ssl/detail/verify_callback.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ssl/detail/write_op.hpp b/3rdparty/asio/include/asio/ssl/detail/write_op.hpp index d40719e0fa5..edcbcad5850 100644 --- a/3rdparty/asio/include/asio/ssl/detail/write_op.hpp +++ b/3rdparty/asio/include/asio/ssl/detail/write_op.hpp @@ -2,7 +2,7 @@ // ssl/detail/write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -30,6 +30,11 @@ template <typename ConstBufferSequence> class write_op { public: + static constexpr const char* tracking_name() + { + return "ssl::stream<>::async_write_some"; + } + write_op(const ConstBufferSequence& buffers) : buffers_(buffers) { @@ -39,9 +44,13 @@ public: asio::error_code& ec, std::size_t& bytes_transferred) const { + unsigned char storage[ + asio::detail::buffer_sequence_adapter<asio::const_buffer, + ConstBufferSequence>::linearisation_storage_size]; + asio::const_buffer buffer = asio::detail::buffer_sequence_adapter<asio::const_buffer, - ConstBufferSequence>::first(buffers_); + ConstBufferSequence>::linearise(buffers_, asio::buffer(storage)); return eng.write(buffer, ec, bytes_transferred); } @@ -51,7 +60,7 @@ public: const asio::error_code& ec, const std::size_t& bytes_transferred) const { - handler(ec, bytes_transferred); + static_cast<Handler&&>(handler)(ec, bytes_transferred); } private: diff --git a/3rdparty/asio/include/asio/ssl/error.hpp b/3rdparty/asio/include/asio/ssl/error.hpp index 3efef0ccf32..e126f52c1c7 100644 --- a/3rdparty/asio/include/asio/ssl/error.hpp +++ b/3rdparty/asio/include/asio/ssl/error.hpp @@ -2,7 +2,7 @@ // ssl/error.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,6 +17,7 @@ #include "asio/detail/config.hpp" #include "asio/error_code.hpp" +#include "asio/ssl/detail/openssl_types.hpp" #include "asio/detail/push_options.hpp" @@ -31,7 +32,8 @@ enum ssl_errors extern ASIO_DECL const asio::error_category& get_ssl_category(); -static const asio::error_category& ssl_category +static const asio::error_category& + ssl_category ASIO_UNUSED_VARIABLE = asio::error::get_ssl_category(); } // namespace error @@ -42,25 +44,39 @@ enum stream_errors { #if defined(GENERATING_DOCUMENTATION) /// The underlying stream closed before the ssl stream gracefully shut down. - stream_truncated -#elif (OPENSSL_VERSION_NUMBER < 0x10100000L) && !defined(OPENSSL_IS_BORINGSSL) - stream_truncated = ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ) -#else - stream_truncated = 1 -#endif + stream_truncated, + + /// The underlying SSL library returned a system error without providing + /// further information. + unspecified_system_error, + + /// The underlying SSL library generated an unexpected result from a function + /// call. + unexpected_result +#else // defined(GENERATING_DOCUMENTATION) +# if (OPENSSL_VERSION_NUMBER < 0x10100000L) \ + && !defined(OPENSSL_IS_BORINGSSL) \ + && !defined(ASIO_USE_WOLFSSL) + stream_truncated = ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), +# else + stream_truncated = 1, +# endif + unspecified_system_error = 2, + unexpected_result = 3 +#endif // defined(GENERATING_DOCUMENTATION) }; extern ASIO_DECL const asio::error_category& get_stream_category(); -static const asio::error_category& stream_category +static const asio::error_category& + stream_category ASIO_UNUSED_VARIABLE = asio::ssl::error::get_stream_category(); } // namespace error } // namespace ssl } // namespace asio -#if defined(ASIO_HAS_STD_SYSTEM_ERROR) namespace std { template<> struct is_error_code_enum<asio::error::ssl_errors> @@ -74,7 +90,6 @@ template<> struct is_error_code_enum<asio::ssl::error::stream_errors> }; } // namespace std -#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) namespace asio { namespace error { diff --git a/3rdparty/asio/include/asio/ssl/host_name_verification.hpp b/3rdparty/asio/include/asio/ssl/host_name_verification.hpp new file mode 100644 index 00000000000..adb6ac8c0f7 --- /dev/null +++ b/3rdparty/asio/include/asio/ssl/host_name_verification.hpp @@ -0,0 +1,90 @@ +// +// ssl/host_name_verification.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_SSL_HOST_NAME_VERIFICATION_HPP +#define ASIO_SSL_HOST_NAME_VERIFICATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <string> +#include "asio/ssl/detail/openssl_types.hpp" +#include "asio/ssl/verify_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +/// Verifies a certificate against a host_name according to the rules described +/// in RFC 6125. +/** + * @par Example + * The following example shows how to synchronously open a secure connection to + * a given host name: + * @code + * using asio::ip::tcp; + * namespace ssl = asio::ssl; + * typedef ssl::stream<tcp::socket> ssl_socket; + * + * // Create a context that uses the default paths for finding CA certificates. + * ssl::context ctx(ssl::context::sslv23); + * ctx.set_default_verify_paths(); + * + * // Open a socket and connect it to the remote host. + * asio::io_context io_context; + * ssl_socket sock(io_context, ctx); + * tcp::resolver resolver(io_context); + * tcp::resolver::query query("host.name", "https"); + * asio::connect(sock.lowest_layer(), resolver.resolve(query)); + * sock.lowest_layer().set_option(tcp::no_delay(true)); + * + * // Perform SSL handshake and verify the remote host's certificate. + * sock.set_verify_mode(ssl::verify_peer); + * sock.set_verify_callback(ssl::host_name_verification("host.name")); + * sock.handshake(ssl_socket::client); + * + * // ... read and write as normal ... + * @endcode + */ +class host_name_verification +{ +public: + /// The type of the function object's result. + typedef bool result_type; + + /// Constructor. + explicit host_name_verification(const std::string& host) + : host_(host) + { + } + + /// Perform certificate verification. + ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const; + +private: + // Helper function to check a host name against an IPv4 address + // The host name to be checked. + std::string host_; +}; + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HEADER_ONLY) +# include "asio/ssl/impl/host_name_verification.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SSL_HOST_NAME_VERIFICATION_HPP diff --git a/3rdparty/asio/include/asio/ssl/impl/context.hpp b/3rdparty/asio/include/asio/ssl/impl/context.hpp index 2b5a1616bf9..2324a9880aa 100644 --- a/3rdparty/asio/include/asio/ssl/impl/context.hpp +++ b/3rdparty/asio/include/asio/ssl/impl/context.hpp @@ -3,7 +3,7 @@ // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ssl/impl/context.ipp b/3rdparty/asio/include/asio/ssl/impl/context.ipp index 2b0c38d373c..8711048b9a7 100644 --- a/3rdparty/asio/include/asio/ssl/impl/context.ipp +++ b/3rdparty/asio/include/asio/ssl/impl/context.ipp @@ -3,7 +3,7 @@ // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -47,6 +47,7 @@ struct context::evp_pkey_cleanup ~evp_pkey_cleanup() { if (p) ::EVP_PKEY_free(p); } }; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) struct context::rsa_cleanup { RSA* p; @@ -58,6 +59,7 @@ struct context::dh_cleanup DH* p; ~dh_cleanup() { if (p) ::DH_free(p); } }; +#endif // (OPENSSL_VERSION_NUMBER < 0x30000000L) context::context(context::method m) : handle_(0) @@ -66,16 +68,15 @@ context::context(context::method m) switch (m) { -#if defined(OPENSSL_NO_SSL2) \ - || (OPENSSL_VERSION_NUMBER >= 0x10100000L) + // SSL v2. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) case context::sslv2: case context::sslv2_client: case context::sslv2_server: asio::detail::throw_error( asio::error::invalid_argument, "context"); break; -#else // defined(OPENSSL_NO_SSL2) - // || (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) case context::sslv2: handle_ = ::SSL_CTX_new(::SSLv2_method()); break; @@ -85,9 +86,35 @@ context::context(context::method m) case context::sslv2_server: handle_ = ::SSL_CTX_new(::SSLv2_server_method()); break; -#endif // defined(OPENSSL_NO_SSL2) - // || (OPENSSL_VERSION_NUMBER >= 0x10100000L) -#if defined(OPENSSL_NO_SSL3) +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) + + // SSL v3. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::sslv3: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); + SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); + } + break; + case context::sslv3_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); + SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); + } + break; + case context::sslv3_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); + SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); + } + break; +#elif defined(OPENSSL_NO_SSL3) case context::sslv3: case context::sslv3_client: case context::sslv3_server: @@ -105,7 +132,34 @@ context::context(context::method m) handle_ = ::SSL_CTX_new(::SSLv3_server_method()); break; #endif // defined(OPENSSL_NO_SSL3) -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + + // TLS v1.0. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv1: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); + } + break; + case context::tlsv1_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); + } + break; + case context::tlsv1_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); + } + break; +#elif defined(SSL_TXT_TLSV1) case context::tlsv1: handle_ = ::SSL_CTX_new(::TLSv1_method()); break; @@ -115,18 +169,42 @@ context::context(context::method m) case context::tlsv1_server: handle_ = ::SSL_CTX_new(::TLSv1_server_method()); break; -#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) - case context::sslv23: - handle_ = ::SSL_CTX_new(::SSLv23_method()); +#else // defined(SSL_TXT_TLSV1) + case context::tlsv1: + case context::tlsv1_client: + case context::tlsv1_server: + asio::detail::throw_error( + asio::error::invalid_argument, "context"); break; - case context::sslv23_client: - handle_ = ::SSL_CTX_new(::SSLv23_client_method()); +#endif // defined(SSL_TXT_TLSV1) + + // TLS v1.1. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv11: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); + } break; - case context::sslv23_server: - handle_ = ::SSL_CTX_new(::SSLv23_server_method()); + case context::tlsv11_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); + } + break; + case context::tlsv11_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); + } break; -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) -#if defined(SSL_TXT_TLSV1_1) +#elif defined(SSL_TXT_TLSV1_1) case context::tlsv11: handle_ = ::SSL_CTX_new(::TLSv1_1_method()); break; @@ -144,7 +222,34 @@ context::context(context::method m) asio::error::invalid_argument, "context"); break; #endif // defined(SSL_TXT_TLSV1_1) -#if defined(SSL_TXT_TLSV1_2) + + // TLS v1.2. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv12: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); + } + break; + case context::tlsv12_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); + } + break; + case context::tlsv12_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); + } + break; +#elif defined(SSL_TXT_TLSV1_2) case context::tlsv12: handle_ = ::SSL_CTX_new(::TLSv1_2_method()); break; @@ -154,31 +259,99 @@ context::context(context::method m) case context::tlsv12_server: handle_ = ::SSL_CTX_new(::TLSv1_2_server_method()); break; -#else // defined(SSL_TXT_TLSV1_2) +#else // defined(SSL_TXT_TLSV1_2) case context::tlsv12: case context::tlsv12_client: case context::tlsv12_server: asio::detail::throw_error( asio::error::invalid_argument, "context"); break; -#endif // defined(SSL_TXT_TLSV1_2) -#else // (OPENSSL_VERSION_NUMBER < 0x10100000L) - case context::tlsv1: - case context::tlsv11: - case context::tlsv12: +#endif // defined(SSL_TXT_TLSV1_2) + + // TLS v1.3. +#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) \ + && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv13: handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION); + } break; - case context::tlsv1_client: - case context::tlsv11_client: - case context::tlsv12_client: + case context::tlsv13_client: handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION); + } break; - case context::tlsv1_server: - case context::tlsv11_server: - case context::tlsv12_server: + case context::tlsv13_server: + handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + { + SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION); + } + break; +#else // (OPENSSL_VERSION_NUMBER >= 0x10101000L) + // && !defined(LIBRESSL_VERSION_NUMBER) + case context::tlsv13: + case context::tlsv13_client: + case context::tlsv13_server: + asio::detail::throw_error( + asio::error::invalid_argument, "context"); + break; +#endif // (OPENSSL_VERSION_NUMBER >= 0x10101000L) + // && !defined(LIBRESSL_VERSION_NUMBER) + + // Any supported SSL/TLS version. + case context::sslv23: + handle_ = ::SSL_CTX_new(::SSLv23_method()); + break; + case context::sslv23_client: + handle_ = ::SSL_CTX_new(::SSLv23_client_method()); + break; + case context::sslv23_server: + handle_ = ::SSL_CTX_new(::SSLv23_server_method()); + break; + + // Any supported TLS version. +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) + case context::tls: + handle_ = ::SSL_CTX_new(::TLS_method()); + if (handle_) + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + break; + case context::tls_client: + handle_ = ::SSL_CTX_new(::TLS_client_method()); + if (handle_) + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + break; + case context::tls_server: handle_ = ::SSL_CTX_new(::TLS_server_method()); + if (handle_) + SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); + break; +#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + case context::tls: + handle_ = ::SSL_CTX_new(::SSLv23_method()); + if (handle_) + SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + break; + case context::tls_client: + handle_ = ::SSL_CTX_new(::SSLv23_client_method()); + if (handle_) + SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + break; + case context::tls_server: + handle_ = ::SSL_CTX_new(::SSLv23_server_method()); + if (handle_) + SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); break; -#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) +#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) + default: handle_ = ::SSL_CTX_new(0); break; @@ -186,16 +359,23 @@ context::context(context::method m) if (handle_ == 0) { - asio::error_code ec( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + asio::error_code ec = translate_error(::ERR_get_error()); asio::detail::throw_error(ec, "context"); } set_options(no_compression); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +context::context(context::native_handle_type native_handle) + : handle_(native_handle) +{ + if (!handle_) + { + asio::detail::throw_error( + asio::error::invalid_argument, "context"); + } +} + context::context(context&& other) { handle_ = other.handle_; @@ -204,18 +384,20 @@ context::context(context&& other) context& context::operator=(context&& other) { - context tmp(ASIO_MOVE_CAST(context)(*this)); + context tmp(static_cast<context&&>(*this)); handle_ = other.handle_; other.handle_ = 0; return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) context::~context() { if (handle_) { -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ + && (!defined(LIBRESSL_VERSION_NUMBER) \ + || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \ + || defined(ASIO_USE_WOLFSSL) void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) void* cb_userdata = handle_->default_passwd_callback_userdata; @@ -226,7 +408,10 @@ context::~context() static_cast<detail::password_callback_base*>( cb_userdata); delete callback; -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ + && (!defined(LIBRESSL_VERSION_NUMBER) \ + || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \ + || defined(ASIO_USE_WOLFSSL) ::SSL_CTX_set_default_passwd_cb_userdata(handle_, 0); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) handle_->default_passwd_callback_userdata = 0; @@ -358,9 +543,7 @@ ASIO_SYNC_OP_VOID context::load_verify_file( if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -383,23 +566,32 @@ ASIO_SYNC_OP_VOID context::add_certificate_authority( bio_cleanup bio = { make_buffer_bio(ca) }; if (bio.p) { - x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; - if (cert.p) + if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_)) { - if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_)) + for (bool added = false;; added = true) { - if (::X509_STORE_add_cert(store, cert.p) == 1) + x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; + if (!cert.p) { - ec = asio::error_code(); + unsigned long err = ::ERR_get_error(); + if (added && ERR_GET_LIB(err) == ERR_LIB_PEM + && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) + break; + + ec = translate_error(err); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + if (::X509_STORE_add_cert(store, cert.p) != 1) + { + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } } } } - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = asio::error_code(); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -417,9 +609,7 @@ ASIO_SYNC_OP_VOID context::set_default_verify_paths( if (::SSL_CTX_set_default_verify_paths(handle_) != 1) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -441,9 +631,7 @@ ASIO_SYNC_OP_VOID context::add_verify_path( if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -497,9 +685,7 @@ ASIO_SYNC_OP_VOID context::use_certificate( ASIO_SYNC_OP_VOID_RETURN(ec); } - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -535,9 +721,7 @@ ASIO_SYNC_OP_VOID context::use_certificate_file( if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -560,7 +744,10 @@ ASIO_SYNC_OP_VOID context::use_certificate_chain( bio_cleanup bio = { make_buffer_bio(chain) }; if (bio.p) { -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ + && (!defined(LIBRESSL_VERSION_NUMBER) \ + || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \ + || defined(ASIO_USE_WOLFSSL) pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) @@ -573,21 +760,21 @@ ASIO_SYNC_OP_VOID context::use_certificate_chain( cb_userdata) }; if (!cert.p) { - ec = asio::error_code(ERR_R_PEM_LIB, - asio::error::get_ssl_category()); + ec = translate_error(ERR_R_PEM_LIB); ASIO_SYNC_OP_VOID_RETURN(ec); } int result = ::SSL_CTX_use_certificate(handle_, cert.p); if (result == 0 || ::ERR_peek_error() != 0) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } -#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) +#if ((OPENSSL_VERSION_NUMBER >= 0x10002000L) \ + && (!defined(LIBRESSL_VERSION_NUMBER) \ + || LIBRESSL_VERSION_NUMBER >= 0x2090100fL)) \ + || defined(ASIO_USE_WOLFSSL) ::SSL_CTX_clear_chain_certs(handle_); #else if (handle_->extra_certs) @@ -603,9 +790,7 @@ ASIO_SYNC_OP_VOID context::use_certificate_chain( { if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert)) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } } @@ -620,9 +805,7 @@ ASIO_SYNC_OP_VOID context::use_certificate_chain( } } - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -640,9 +823,7 @@ ASIO_SYNC_OP_VOID context::use_certificate_chain_file( if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -664,7 +845,10 @@ ASIO_SYNC_OP_VOID context::use_private_key( { ::ERR_clear_error(); -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ + && (!defined(LIBRESSL_VERSION_NUMBER) \ + || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \ + || defined(ASIO_USE_WOLFSSL) pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) @@ -703,9 +887,7 @@ ASIO_SYNC_OP_VOID context::use_private_key( } } - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -731,17 +913,55 @@ ASIO_SYNC_OP_VOID context::use_rsa_private_key( { ::ERR_clear_error(); -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) - pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); - void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); +#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ + && (!defined(LIBRESSL_VERSION_NUMBER) \ + || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \ + || defined(ASIO_USE_WOLFSSL) + pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); + void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) - pem_password_cb* callback = handle_->default_passwd_callback; - void* cb_userdata = handle_->default_passwd_callback_userdata; + pem_password_cb* callback = handle_->default_passwd_callback; + void* cb_userdata = handle_->default_passwd_callback_userdata; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) bio_cleanup bio = { make_buffer_bio(private_key) }; if (bio.p) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + evp_pkey_cleanup evp_private_key = { 0 }; + switch (format) + { + case context_base::asn1: + evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0); + break; + case context_base::pem: + evp_private_key.p = ::PEM_read_bio_PrivateKey( + bio.p, 0, callback, + cb_userdata); + break; + default: + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + if (evp_private_key.p) + { + if (::EVP_PKEY_is_a(evp_private_key.p, "RSA") == 0) + { + ec = translate_error( + ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY)); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } +#else // (OPENSSL_VERSION_NUMBER >= 0x30000000L) rsa_cleanup rsa_private_key = { 0 }; switch (format) { @@ -768,11 +988,10 @@ ASIO_SYNC_OP_VOID context::use_rsa_private_key( ASIO_SYNC_OP_VOID_RETURN(ec); } } +#endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L) } - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -800,9 +1019,7 @@ ASIO_SYNC_OP_VOID context::use_private_key_file( if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -822,6 +1039,53 @@ ASIO_SYNC_OP_VOID context::use_rsa_private_key_file( const std::string& filename, context::file_format format, asio::error_code& ec) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + ::ERR_clear_error(); + + pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); + void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); + + bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") }; + if (bio.p) + { + evp_pkey_cleanup evp_private_key = { 0 }; + switch (format) + { + case context_base::asn1: + evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0); + break; + case context_base::pem: + evp_private_key.p = ::PEM_read_bio_PrivateKey( + bio.p, 0, callback, + cb_userdata); + break; + default: + { + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + if (evp_private_key.p) + { + if (::EVP_PKEY_is_a(evp_private_key.p, "RSA") == 0) + { + ec = translate_error( + ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY)); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + } + + ec = translate_error(::ERR_get_error()); + ASIO_SYNC_OP_VOID_RETURN(ec); +#else // (OPENSSL_VERSION_NUMBER >= 0x30000000L) int file_type; switch (format) { @@ -843,14 +1107,13 @@ ASIO_SYNC_OP_VOID context::use_rsa_private_key_file( if (::SSL_CTX_use_RSAPrivateKey_file( handle_, filename.c_str(), file_type) != 1) { - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } ec = asio::error_code(); ASIO_SYNC_OP_VOID_RETURN(ec); +#endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L) } void context::use_tmp_dh(const const_buffer& dh) @@ -871,9 +1134,7 @@ ASIO_SYNC_OP_VOID context::use_tmp_dh( return do_use_tmp_dh(bio.p, ec); } - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -895,9 +1156,7 @@ ASIO_SYNC_OP_VOID context::use_tmp_dh_file( return do_use_tmp_dh(bio.p, ec); } - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -906,6 +1165,19 @@ ASIO_SYNC_OP_VOID context::do_use_tmp_dh( { ::ERR_clear_error(); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY* p = ::PEM_read_bio_Parameters(bio, 0); + if (p) + { + if (::SSL_CTX_set0_tmp_dh_pkey(handle_, p) == 1) + { + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + else + ::EVP_PKEY_free(p); + } +#else // (OPENSSL_VERSION_NUMBER >= 0x30000000L) dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) }; if (dh.p) { @@ -915,10 +1187,9 @@ ASIO_SYNC_OP_VOID context::do_use_tmp_dh( ASIO_SYNC_OP_VOID_RETURN(ec); } } +#endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L) - ec = asio::error_code( - static_cast<int>(::ERR_get_error()), - asio::error::get_ssl_category()); + ec = translate_error(::ERR_get_error()); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -970,7 +1241,10 @@ int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx) ASIO_SYNC_OP_VOID context::do_set_password_callback( detail::password_callback_base* callback, asio::error_code& ec) { -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ + && (!defined(LIBRESSL_VERSION_NUMBER) \ + || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)) \ + || defined(ASIO_USE_WOLFSSL) void* old_callback = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); ::SSL_CTX_set_default_passwd_cb_userdata(handle_, callback); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) @@ -1022,6 +1296,21 @@ BIO* context::make_buffer_bio(const const_buffer& b) static_cast<int>(b.size())); } +asio::error_code context::translate_error(long error) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if (ERR_SYSTEM_ERROR(error)) + { + return asio::error_code( + static_cast<int>(ERR_GET_REASON(error)), + asio::error::get_system_category()); + } +#endif // (OPENSSL_VERSION_NUMBER >= 0x30000000L) + + return asio::error_code(static_cast<int>(error), + asio::error::get_ssl_category()); +} + } // namespace ssl } // namespace asio diff --git a/3rdparty/asio/include/asio/ssl/impl/error.ipp b/3rdparty/asio/include/asio/ssl/impl/error.ipp index 268fc9664cf..7ff6e8a7359 100644 --- a/3rdparty/asio/include/asio/ssl/impl/error.ipp +++ b/3rdparty/asio/include/asio/ssl/impl/error.ipp @@ -2,7 +2,7 @@ // ssl/impl/error.ipp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -28,15 +28,37 @@ namespace detail { class ssl_category : public asio::error_category { public: - const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + const char* name() const noexcept { return "asio.ssl"; } std::string message(int value) const { - const char* s = ::ERR_reason_error_string(value); - return s ? s : "asio.ssl error"; + const char* reason = ::ERR_reason_error_string(value); + if (reason) + { + const char* lib = ::ERR_lib_error_string(value); +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + const char* func = ::ERR_func_error_string(value); +#else // (OPENSSL_VERSION_NUMBER < 0x30000000L) + const char* func = 0; +#endif // (OPENSSL_VERSION_NUMBER < 0x30000000L) + std::string result(reason); + if (lib || func) + { + result += " ("; + if (lib) + result += lib; + if (lib && func) + result += ", "; + if (func) + result += func; + result += ")"; + } + return result; + } + return "asio.ssl error"; } }; @@ -66,7 +88,7 @@ namespace detail { class stream_category : public asio::error_category { public: - const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + const char* name() const noexcept { return "asio.ssl.stream"; } @@ -76,6 +98,8 @@ public: switch (value) { case stream_truncated: return "stream truncated"; + case unspecified_system_error: return "unspecified system error"; + case unexpected_result: return "unexpected result"; default: return "asio.ssl.stream error"; } } diff --git a/3rdparty/asio/include/asio/ssl/impl/host_name_verification.ipp b/3rdparty/asio/include/asio/ssl/impl/host_name_verification.ipp new file mode 100644 index 00000000000..198d1f3989c --- /dev/null +++ b/3rdparty/asio/include/asio/ssl/impl/host_name_verification.ipp @@ -0,0 +1,73 @@ +// +// ssl/impl/host_name_verification.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_SSL_IMPL_HOST_NAME_VERIFICATION_IPP +#define ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include <cctype> +#include <cstring> +#include "asio/ip/address.hpp" +#include "asio/ssl/host_name_verification.hpp" +#include "asio/ssl/detail/openssl_types.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace ssl { + +bool host_name_verification::operator()( + bool preverified, verify_context& ctx) const +{ + using namespace std; // For memcmp. + + // Don't bother looking at certificates that have failed pre-verification. + if (!preverified) + return false; + + // We're only interested in checking the certificate at the end of the chain. + int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); + if (depth > 0) + return true; + + // Try converting the host name to an address. If it is an address then we + // need to look for an IP address in the certificate rather than a host name. + asio::error_code ec; + ip::address address = ip::make_address(host_, ec); + const bool is_address = !ec; + (void)address; + + X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + + if (is_address) + { + return X509_check_ip_asc(cert, host_.c_str(), 0) == 1; + } + else + { + char* peername = 0; + const int result = X509_check_host(cert, + host_.c_str(), host_.size(), 0, &peername); + OPENSSL_free(peername); + return result == 1; + } +} + +} // namespace ssl +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP diff --git a/3rdparty/asio/include/asio/ssl/impl/rfc2818_verification.ipp b/3rdparty/asio/include/asio/ssl/impl/rfc2818_verification.ipp index f84b02573ae..93e161daa85 100644 --- a/3rdparty/asio/include/asio/ssl/impl/rfc2818_verification.ipp +++ b/3rdparty/asio/include/asio/ssl/impl/rfc2818_verification.ipp @@ -2,7 +2,7 @@ // ssl/impl/rfc2818_verification.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,6 +17,8 @@ #include "asio/detail/config.hpp" +#if !defined(ASIO_NO_DEPRECATED) + #include <cctype> #include <cstring> #include "asio/ip/address.hpp" @@ -157,4 +159,6 @@ bool rfc2818_verification::match_pattern(const char* pattern, #include "asio/detail/pop_options.hpp" +#endif // !defined(ASIO_NO_DEPRECATED) + #endif // ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP diff --git a/3rdparty/asio/include/asio/ssl/impl/src.hpp b/3rdparty/asio/include/asio/ssl/impl/src.hpp index e6e269f9998..5ffb95fdcd6 100644 --- a/3rdparty/asio/include/asio/ssl/impl/src.hpp +++ b/3rdparty/asio/include/asio/ssl/impl/src.hpp @@ -2,7 +2,7 @@ // impl/ssl/src.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -23,6 +23,7 @@ #include "asio/ssl/impl/error.ipp" #include "asio/ssl/detail/impl/engine.ipp" #include "asio/ssl/detail/impl/openssl_init.ipp" +#include "asio/ssl/impl/host_name_verification.ipp" #include "asio/ssl/impl/rfc2818_verification.ipp" #endif // ASIO_SSL_IMPL_SRC_HPP diff --git a/3rdparty/asio/include/asio/ssl/rfc2818_verification.hpp b/3rdparty/asio/include/asio/ssl/rfc2818_verification.hpp index a4ab67b2aee..db2831045d9 100644 --- a/3rdparty/asio/include/asio/ssl/rfc2818_verification.hpp +++ b/3rdparty/asio/include/asio/ssl/rfc2818_verification.hpp @@ -2,7 +2,7 @@ // ssl/rfc2818_verification.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,6 +17,8 @@ #include "asio/detail/config.hpp" +#if !defined(ASIO_NO_DEPRECATED) + #include <string> #include "asio/ssl/detail/openssl_types.hpp" #include "asio/ssl/verify_context.hpp" @@ -26,8 +28,8 @@ namespace asio { namespace ssl { -/// Verifies a certificate against a hostname according to the rules described -/// in RFC 2818. +/// (Deprecated. Use ssl::host_name_verification.) Verifies a certificate +/// against a hostname according to the rules described in RFC 2818. /** * @par Example * The following example shows how to synchronously open a secure connection to @@ -91,4 +93,6 @@ private: # include "asio/ssl/impl/rfc2818_verification.ipp" #endif // defined(ASIO_HEADER_ONLY) +#endif // !defined(ASIO_NO_DEPRECATED) + #endif // ASIO_SSL_RFC2818_VERIFICATION_HPP diff --git a/3rdparty/asio/include/asio/ssl/stream.hpp b/3rdparty/asio/include/asio/ssl/stream.hpp index bc259b59ca7..befcc287e7f 100644 --- a/3rdparty/asio/include/asio/ssl/stream.hpp +++ b/3rdparty/asio/include/asio/ssl/stream.hpp @@ -2,7 +2,7 @@ // ssl/stream.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,8 +18,10 @@ #include "asio/detail/config.hpp" #include "asio/async_result.hpp" +#include "asio/buffer.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/type_traits.hpp" #include "asio/ssl/context.hpp" @@ -51,9 +53,9 @@ namespace ssl { * @par Example * To use the SSL stream template with an ip::tcp::socket, you would write: * @code - * asio::io_context io_context; + * asio::io_context my_context; * asio::ssl::context ctx(asio::ssl::context::sslv23); - * asio::ssl::stream<asio:ip::tcp::socket> sock(io_context, ctx); + * asio::ssl::stream<asio::ip::tcp::socket> sock(my_context, ctx); * @endcode * * @par Concepts: @@ -64,6 +66,13 @@ class stream : public stream_base, private noncopyable { +private: + class initiate_async_handshake; + class initiate_async_buffered_handshake; + class initiate_async_shutdown; + class initiate_async_write_some; + class initiate_async_read_some; + public: /// The native handle type of the SSL stream. typedef SSL* native_handle_type; @@ -75,7 +84,7 @@ public: }; /// The type of the next layer. - typedef typename remove_reference<Stream>::type next_layer_type; + typedef remove_reference_t<Stream> next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; @@ -83,7 +92,6 @@ public: /// The type of the executor associated with the object. typedef typename lowest_layer_type::executor_type executor_type; -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Construct a stream. /** * This constructor creates a stream and initialises the underlying stream @@ -95,20 +103,57 @@ public: */ template <typename Arg> stream(Arg&& arg, context& ctx) - : next_layer_(ASIO_MOVE_CAST(Arg)(arg)), - core_(ctx.native_handle(), - next_layer_.lowest_layer().get_executor().context()) + : next_layer_(static_cast<Arg&&>(arg)), + core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor()) { } -#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Construct a stream from an existing native implementation. + /** + * This constructor creates a stream and initialises the underlying stream + * object. On success, ownership of the native implementation is transferred + * to the stream, and it will be cleaned up when the stream is destroyed. + * + * @param arg The argument to be passed to initialise the underlying stream. + * + * @param handle An existing native SSL implementation. + */ template <typename Arg> - stream(Arg& arg, context& ctx) - : next_layer_(arg), - core_(ctx.native_handle(), - next_layer_.lowest_layer().get_executor().context()) + stream(Arg&& arg, native_handle_type handle) + : next_layer_(static_cast<Arg&&>(arg)), + core_(handle, next_layer_.lowest_layer().get_executor()) + { + } + + /// Move-construct a stream from another. + /** + * @param other The other stream object from which the move will occur. Must + * have no outstanding asynchronous operations associated with it. Following + * the move, @c other has a valid but unspecified state where the only safe + * operation is destruction, or use as the target of a move assignment. + */ + stream(stream&& other) + : next_layer_(static_cast<Stream&&>(other.next_layer_)), + core_(static_cast<detail::stream_core&&>(other.core_)) { } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Move-assign a stream from another. + /** + * @param other The other stream object from which the move will occur. Must + * have no outstanding asynchronous operations associated with it. Following + * the move, @c other has a valid but unspecified state where the only safe + * operation is destruction, or use as the target of a move assignment. + */ + stream& operator=(stream&& other) + { + if (this != &other) + { + next_layer_ = static_cast<Stream&&>(other.next_layer_); + core_ = static_cast<detail::stream_core&&>(other.core_); + } + return *this; + } /// Destructor. /** @@ -126,27 +171,11 @@ public: * * @return A copy of the executor that stream will use to dispatch handlers. */ - executor_type get_executor() ASIO_NOEXCEPT + executor_type get_executor() noexcept { return next_layer_.lowest_layer().get_executor(); } -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_context() - { - return next_layer_.lowest_layer().get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - asio::io_context& get_io_service() - { - return next_layer_.lowest_layer().get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the @@ -158,7 +187,7 @@ public: * suitable for passing to functions such as @c SSL_get_verify_result and * @c SSL_get_peer_certificate: * @code - * asio::ssl::stream<asio:ip::tcp::socket> sock(io_context, ctx); + * asio::ssl::stream<asio::ip::tcp::socket> sock(io_ctx, ctx); * * // ... establish connection and perform handshake ... * @@ -435,41 +464,59 @@ public: /// Start an asynchronous SSL handshake. /** * This function is used to asynchronously perform an SSL handshake on the - * stream. This function call always returns immediately. + * stream. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * - * @param handler The handler to be called when the handshake operation - * completes. Copies will be made of the handler as required. The equivalent - * function signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the handshake completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c Stream type's @c async_read_some and + * @c async_write_some operations. */ - template <typename HandshakeHandler> - ASIO_INITFN_RESULT_TYPE(HandshakeHandler, - void (asio::error_code)) - async_handshake(handshake_type type, - ASIO_MOVE_ARG(HandshakeHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + HandshakeToken = default_completion_token_t<executor_type>> + auto async_handshake(handshake_type type, + HandshakeToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<HandshakeToken, + void (asio::error_code)>( + declval<initiate_async_handshake>(), token, type)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a HandshakeHandler. - ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check; - - asio::async_completion<HandshakeHandler, - void (asio::error_code)> init(handler); - - detail::async_io(next_layer_, core_, - detail::handshake_op(type), init.completion_handler); - - return init.result.get(); + return async_initiate<HandshakeToken, + void (asio::error_code)>( + initiate_async_handshake(this), token, type); } /// Start an asynchronous SSL handshake. /** * This function is used to asynchronously perform an SSL handshake on the - * stream. This function call always returns immediately. + * stream. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. @@ -477,35 +524,54 @@ public: * @param buffers The buffered data to be reused for the handshake. Although * the buffers object may be copied as necessary, ownership of the underlying * buffers is retained by the caller, which must guarantee that they remain - * valid until the handler is called. + * valid until the completion handler is called. * - * @param handler The handler to be called when the handshake operation - * completes. Copies will be made of the handler as required. The equivalent - * function signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the handshake completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Amount of buffers used in handshake. * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c Stream type's @c async_read_some and + * @c async_write_some operations. */ - template <typename ConstBufferSequence, typename BufferedHandshakeHandler> - ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, - void (asio::error_code, std::size_t)) - async_handshake(handshake_type type, const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(BufferedHandshakeHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) BufferedHandshakeToken + = default_completion_token_t<executor_type>> + auto async_handshake(handshake_type type, const ConstBufferSequence& buffers, + BufferedHandshakeToken&& token + = default_completion_token_t<executor_type>(), + constraint_t< + is_const_buffer_sequence<ConstBufferSequence>::value + > = 0) + -> decltype( + async_initiate<BufferedHandshakeToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_buffered_handshake>(), token, type, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a BufferedHandshakeHandler. - ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( - BufferedHandshakeHandler, handler) type_check; - - asio::async_completion<BufferedHandshakeHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::async_io(next_layer_, core_, - detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), - init.completion_handler); - - return init.result.get(); + return async_initiate<BufferedHandshakeToken, + void (asio::error_code, std::size_t)>( + initiate_async_buffered_handshake(this), token, type, buffers); } /// Shut down SSL on the stream. @@ -537,32 +603,51 @@ public: /// Asynchronously shut down SSL on the stream. /** - * This function is used to asynchronously shut down SSL on the stream. This - * function call always returns immediately. - * - * @param handler The handler to be called when the handshake operation - * completes. Copies will be made of the handler as required. The equivalent - * function signature of the handler must be: + * This function is used to asynchronously shut down SSL on the stream. It is + * an initiating function for an @ref asynchronous_operation, and always + * returns immediately. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the shutdown completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c Stream type's @c async_read_some and + * @c async_write_some operations. */ - template <typename ShutdownHandler> - ASIO_INITFN_RESULT_TYPE(ShutdownHandler, - void (asio::error_code)) - async_shutdown(ASIO_MOVE_ARG(ShutdownHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + ShutdownToken + = default_completion_token_t<executor_type>> + auto async_shutdown( + ShutdownToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ShutdownToken, + void (asio::error_code)>( + declval<initiate_async_shutdown>(), token)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ShutdownHandler. - ASIO_SHUTDOWN_HANDLER_CHECK(ShutdownHandler, handler) type_check; - - asio::async_completion<ShutdownHandler, - void (asio::error_code)> init(handler); - - detail::async_io(next_layer_, core_, detail::shutdown_op(), - init.completion_handler); - - return init.result.get(); + return async_initiate<ShutdownToken, + void (asio::error_code)>( + initiate_async_shutdown(this), token); } /// Write some data to the stream. @@ -617,43 +702,60 @@ public: /// Start an asynchronous write. /** * This function is used to asynchronously write one or more bytes of data to - * the stream. The function call always returns immediately. + * the stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers The data to be written to the stream. Although the buffers * object may be copied as necessary, ownership of the underlying buffers is * retained by the caller, which must guarantee that they remain valid until - * the handler is called. + * the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The equivalent function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_write_some operation may not transmit all of the data to * the peer. Consider using the @ref async_write function if you need to - * ensure that all data is written before the blocking operation completes. + * ensure that all data is written before the asynchronous operation + * completes. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c Stream type's @c async_read_some and + * @c async_write_some operations. */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_write_some>(), token, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - asio::async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - detail::async_io(next_layer_, core_, - detail::write_op<ConstBufferSequence>(buffers), - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some(this), token, buffers); } /// Read some data from the stream. @@ -708,47 +810,226 @@ public: /// Start an asynchronous read. /** * This function is used to asynchronously read one or more bytes of data from - * the stream. The function call always returns immediately. + * the stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * @param buffers The buffers into which the data will be read. Although the * buffers object may be copied as necessary, ownership of the underlying * buffers is retained by the caller, which must guarantee that they remain - * valid until the handler is called. + * valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The equivalent function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The async_read_some operation may not read all of the requested * number of bytes. Consider using the @ref async_read function if you need to * ensure that the requested amount of data is read before the asynchronous * operation completes. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c Stream type's @c async_read_some and + * @c async_write_some operations. */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some>(), token, buffers)) + { + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some(this), token, buffers); + } + +private: + class initiate_async_handshake { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + public: + typedef typename stream::executor_type executor_type; - asio::async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); + explicit initiate_async_handshake(stream* self) + : self_(self) + { + } - detail::async_io(next_layer_, core_, - detail::read_op<MutableBufferSequence>(buffers), - init.completion_handler); + executor_type get_executor() const noexcept + { + return self_->get_executor(); + } - return init.result.get(); - } + template <typename HandshakeHandler> + void operator()(HandshakeHandler&& handler, + handshake_type type) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a HandshakeHandler. + ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check; + + asio::detail::non_const_lvalue<HandshakeHandler> handler2(handler); + detail::async_io(self_->next_layer_, self_->core_, + detail::handshake_op(type), handler2.value); + } + + private: + stream* self_; + }; + + class initiate_async_buffered_handshake + { + public: + typedef typename stream::executor_type executor_type; + + explicit initiate_async_buffered_handshake(stream* self) + : self_(self) + { + } + + executor_type get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename BufferedHandshakeHandler, typename ConstBufferSequence> + void operator()(BufferedHandshakeHandler&& handler, + handshake_type type, const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for a + // BufferedHandshakeHandler. + ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( + BufferedHandshakeHandler, handler) type_check; + + asio::detail::non_const_lvalue< + BufferedHandshakeHandler> handler2(handler); + detail::async_io(self_->next_layer_, self_->core_, + detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), + handler2.value); + } + + private: + stream* self_; + }; + + class initiate_async_shutdown + { + public: + typedef typename stream::executor_type executor_type; + + explicit initiate_async_shutdown(stream* self) + : self_(self) + { + } + + executor_type get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ShutdownHandler> + void operator()(ShutdownHandler&& handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ShutdownHandler. + ASIO_HANDSHAKE_HANDLER_CHECK(ShutdownHandler, handler) type_check; + + asio::detail::non_const_lvalue<ShutdownHandler> handler2(handler); + detail::async_io(self_->next_layer_, self_->core_, + detail::shutdown_op(), handler2.value); + } + + private: + stream* self_; + }; + + class initiate_async_write_some + { + public: + typedef typename stream::executor_type executor_type; + + explicit initiate_async_write_some(stream* self) + : self_(self) + { + } + + executor_type get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + asio::detail::non_const_lvalue<WriteHandler> handler2(handler); + detail::async_io(self_->next_layer_, self_->core_, + detail::write_op<ConstBufferSequence>(buffers), handler2.value); + } + + private: + stream* self_; + }; + + class initiate_async_read_some + { + public: + typedef typename stream::executor_type executor_type; + + explicit initiate_async_read_some(stream* self) + : self_(self) + { + } + + executor_type get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + asio::detail::non_const_lvalue<ReadHandler> handler2(handler); + detail::async_io(self_->next_layer_, self_->core_, + detail::read_op<MutableBufferSequence>(buffers), handler2.value); + } + + private: + stream* self_; + }; -private: Stream next_layer_; detail::stream_core core_; }; diff --git a/3rdparty/asio/include/asio/ssl/stream_base.hpp b/3rdparty/asio/include/asio/ssl/stream_base.hpp index 275d3e3821e..2728ec8ca1b 100644 --- a/3rdparty/asio/include/asio/ssl/stream_base.hpp +++ b/3rdparty/asio/include/asio/ssl/stream_base.hpp @@ -2,7 +2,7 @@ // ssl/stream_base.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ssl/verify_context.hpp b/3rdparty/asio/include/asio/ssl/verify_context.hpp index 560ffcc7ad8..7251856f08e 100644 --- a/3rdparty/asio/include/asio/ssl/verify_context.hpp +++ b/3rdparty/asio/include/asio/ssl/verify_context.hpp @@ -2,7 +2,7 @@ // ssl/verify_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ssl/verify_mode.hpp b/3rdparty/asio/include/asio/ssl/verify_mode.hpp index 7a2bd5654c7..919e308c8a4 100644 --- a/3rdparty/asio/include/asio/ssl/verify_mode.hpp +++ b/3rdparty/asio/include/asio/ssl/verify_mode.hpp @@ -2,7 +2,7 @@ // ssl/verify_mode.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/static_thread_pool.hpp b/3rdparty/asio/include/asio/static_thread_pool.hpp new file mode 100644 index 00000000000..636afe1cee5 --- /dev/null +++ b/3rdparty/asio/include/asio/static_thread_pool.hpp @@ -0,0 +1,31 @@ +// +// static_thread_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_STATIC_THREAD_POOL_HPP +#define ASIO_STATIC_THREAD_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/thread_pool.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +typedef thread_pool static_thread_pool; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_STATIC_THREAD_POOL_HPP diff --git a/3rdparty/asio/include/asio/steady_timer.hpp b/3rdparty/asio/include/asio/steady_timer.hpp index 746ac04a81b..5db00250b71 100644 --- a/3rdparty/asio/include/asio/steady_timer.hpp +++ b/3rdparty/asio/include/asio/steady_timer.hpp @@ -2,7 +2,7 @@ // steady_timer.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) - #include "asio/basic_waitable_timer.hpp" #include "asio/detail/chrono.hpp" @@ -37,6 +34,4 @@ typedef basic_waitable_timer<chrono::steady_clock> steady_timer; } // namespace asio -#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) - #endif // ASIO_STEADY_TIMER_HPP diff --git a/3rdparty/asio/include/asio/strand.hpp b/3rdparty/asio/include/asio/strand.hpp index c70162ba387..c63592b8649 100644 --- a/3rdparty/asio/include/asio/strand.hpp +++ b/3rdparty/asio/include/asio/strand.hpp @@ -2,7 +2,7 @@ // strand.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,6 +18,9 @@ #include "asio/detail/config.hpp" #include "asio/detail/strand_executor_service.hpp" #include "asio/detail/type_traits.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" +#include "asio/is_executor.hpp" #include "asio/detail/push_options.hpp" @@ -38,21 +41,27 @@ public: */ strand() : executor_(), - impl_(use_service<detail::strand_executor_service>( - executor_.context()).create_implementation()) + impl_(strand::create_implementation(executor_)) { } /// Construct a strand for the specified executor. - explicit strand(const Executor& e) + template <typename Executor1> + explicit strand(const Executor1& e, + constraint_t< + conditional_t< + !is_same<Executor1, strand>::value, + is_convertible<Executor1, Executor>, + false_type + >::value + > = 0) : executor_(e), - impl_(use_service<detail::strand_executor_service>( - executor_.context()).create_implementation()) + impl_(strand::create_implementation(executor_)) { } /// Copy constructor. - strand(const strand& other) ASIO_NOEXCEPT + strand(const strand& other) noexcept : executor_(other.executor_), impl_(other.impl_) { @@ -65,14 +74,14 @@ public: */ template <class OtherExecutor> strand( - const strand<OtherExecutor>& other) ASIO_NOEXCEPT + const strand<OtherExecutor>& other) noexcept : executor_(other.executor_), impl_(other.impl_) { } /// Assignment operator. - strand& operator=(const strand& other) ASIO_NOEXCEPT + strand& operator=(const strand& other) noexcept { executor_ = other.executor_; impl_ = other.impl_; @@ -86,18 +95,17 @@ public: */ template <class OtherExecutor> strand& operator=( - const strand<OtherExecutor>& other) ASIO_NOEXCEPT + const strand<OtherExecutor>& other) noexcept { executor_ = other.executor_; impl_ = other.impl_; return *this; } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. - strand(strand&& other) ASIO_NOEXCEPT - : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)), - impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)) + strand(strand&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)), + impl_(static_cast<implementation_type&&>(other.impl_)) { } @@ -107,17 +115,17 @@ public: * to @c Executor. */ template <class OtherExecutor> - strand(strand<OtherExecutor>&& other) ASIO_NOEXCEPT - : executor_(ASIO_MOVE_CAST(OtherExecutor)(other)), - impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)) + strand(strand<OtherExecutor>&& other) noexcept + : executor_(static_cast<OtherExecutor&&>(other.executor_)), + impl_(static_cast<implementation_type&&>(other.impl_)) { } /// Move assignment operator. - strand& operator=(strand&& other) ASIO_NOEXCEPT + strand& operator=(strand&& other) noexcept { - executor_ = ASIO_MOVE_CAST(Executor)(other); - impl_ = ASIO_MOVE_CAST(implementation_type)(other.impl_); + executor_ = static_cast<Executor&&>(other.executor_); + impl_ = static_cast<implementation_type&&>(other.impl_); return *this; } @@ -127,28 +135,97 @@ public: * convertible to @c Executor. */ template <class OtherExecutor> - strand& operator=( - const strand<OtherExecutor>&& other) ASIO_NOEXCEPT + strand& operator=(strand<OtherExecutor>&& other) noexcept { - executor_ = ASIO_MOVE_CAST(OtherExecutor)(other); - impl_ = ASIO_MOVE_CAST(implementation_type)(other.impl_); + executor_ = static_cast<OtherExecutor&&>(other.executor_); + impl_ = static_cast<implementation_type&&>(other.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. - ~strand() + ~strand() noexcept { } /// Obtain the underlying executor. - inner_executor_type get_inner_executor() const ASIO_NOEXCEPT + inner_executor_type get_inner_executor() const noexcept { return executor_; } + /// Forward a query to the underlying executor. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::strand<my_executor_type> ex = ...; + * if (asio::query(ex, asio::execution::blocking) + * == asio::execution::blocking.never) + * ... @endcode + */ + template <typename Property> + constraint_t< + can_query<const Executor&, Property>::value, + conditional_t< + is_convertible<Property, execution::blocking_t>::value, + execution::blocking_t, + query_result_t<const Executor&, Property> + > + > query(const Property& p) const + noexcept(is_nothrow_query<const Executor&, Property>::value) + { + return this->query_helper( + is_convertible<Property, execution::blocking_t>(), p); + } + + /// Forward a requirement to the underlying executor. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::strand<my_executor_type> ex1 = ...; + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.never); @endcode + */ + template <typename Property> + constraint_t< + can_require<const Executor&, Property>::value + && !is_convertible<Property, execution::blocking_t::always_t>::value, + strand<decay_t<require_result_t<const Executor&, Property>>> + > require(const Property& p) const + noexcept(is_nothrow_require<const Executor&, Property>::value) + { + return strand<decay_t<require_result_t<const Executor&, Property>>>( + asio::require(executor_, p), impl_); + } + + /// Forward a preference to the underlying executor. + /** + * Do not call this function directly. It is intended for use with the + * asio::prefer customisation point. + * + * For example: + * @code asio::strand<my_executor_type> ex1 = ...; + * auto ex2 = asio::prefer(ex1, + * asio::execution::blocking.never); @endcode + */ + template <typename Property> + constraint_t< + can_prefer<const Executor&, Property>::value + && !is_convertible<Property, execution::blocking_t::always_t>::value, + strand<decay_t<prefer_result_t<const Executor&, Property>>> + > prefer(const Property& p) const + noexcept(is_nothrow_prefer<const Executor&, Property>::value) + { + return strand<decay_t<prefer_result_t<const Executor&, Property>>>( + asio::prefer(executor_, p), impl_); + } + +#if !defined(ASIO_NO_TS_EXECUTORS) /// Obtain the underlying execution context. - execution_context& context() ASIO_NOEXCEPT + execution_context& context() const noexcept { return executor_.context(); } @@ -157,7 +234,7 @@ public: /** * The strand delegates this call to its underlying executor. */ - void on_work_started() ASIO_NOEXCEPT + void on_work_started() const noexcept { executor_.on_work_started(); } @@ -166,11 +243,33 @@ public: /** * The strand delegates this call to its underlying executor. */ - void on_work_finished() ASIO_NOEXCEPT + void on_work_finished() const noexcept { executor_.on_work_finished(); } +#endif // !defined(ASIO_NO_TS_EXECUTORS) + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the strand to execute the given function + * object on its underlying executor. The function object will be executed + * according to the properties of the underlying executor. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + */ + template <typename Function> + constraint_t< + traits::execute_member<const Executor&, Function>::is_valid, + void + > execute(Function&& f) const + { + detail::strand_executor_service::execute(impl_, + executor_, static_cast<Function&&>(f)); + } +#if !defined(ASIO_NO_TS_EXECUTORS) /// Request the strand to invoke the given function object. /** * This function is used to ask the strand to execute the given function @@ -187,10 +286,10 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) + void dispatch(Function&& f, const Allocator& a) const { detail::strand_executor_service::dispatch(impl_, - executor_, ASIO_MOVE_CAST(Function)(f), a); + executor_, static_cast<Function&&>(f), a); } /// Request the strand to invoke the given function object. @@ -207,10 +306,10 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) + void post(Function&& f, const Allocator& a) const { detail::strand_executor_service::post(impl_, - executor_, ASIO_MOVE_CAST(Function)(f), a); + executor_, static_cast<Function&&>(f), a); } /// Request the strand to invoke the given function object. @@ -227,11 +326,12 @@ public: * internal storage needed for function invocation. */ template <typename Function, typename Allocator> - void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) + void defer(Function&& f, const Allocator& a) const { detail::strand_executor_service::defer(impl_, - executor_, ASIO_MOVE_CAST(Function)(f), a); + executor_, static_cast<Function&&>(f), a); } +#endif // !defined(ASIO_NO_TS_EXECUTORS) /// Determine whether the strand is running in the current thread. /** @@ -239,7 +339,7 @@ public: * submitted to the strand using post(), dispatch() or defer(). Otherwise * returns @c false. */ - bool running_in_this_thread() const ASIO_NOEXCEPT + bool running_in_this_thread() const noexcept { return detail::strand_executor_service::running_in_this_thread(impl_); } @@ -249,7 +349,7 @@ public: * Two strands are equal if they refer to the same ordered, non-concurrent * state. */ - friend bool operator==(const strand& a, const strand& b) ASIO_NOEXCEPT + friend bool operator==(const strand& a, const strand& b) noexcept { return a.impl_ == b.impl_; } @@ -259,18 +359,189 @@ public: * Two strands are equal if they refer to the same ordered, non-concurrent * state. */ - friend bool operator!=(const strand& a, const strand& b) ASIO_NOEXCEPT + friend bool operator!=(const strand& a, const strand& b) noexcept { return a.impl_ != b.impl_; } +#if defined(GENERATING_DOCUMENTATION) private: - Executor executor_; +#endif // defined(GENERATING_DOCUMENTATION) typedef detail::strand_executor_service::implementation_type implementation_type; + + template <typename InnerExecutor> + static implementation_type create_implementation(const InnerExecutor& ex, + constraint_t< + can_query<InnerExecutor, execution::context_t>::value + > = 0) + { + return use_service<detail::strand_executor_service>( + asio::query(ex, execution::context)).create_implementation(); + } + + template <typename InnerExecutor> + static implementation_type create_implementation(const InnerExecutor& ex, + constraint_t< + !can_query<InnerExecutor, execution::context_t>::value + > = 0) + { + return use_service<detail::strand_executor_service>( + ex.context()).create_implementation(); + } + + strand(const Executor& ex, const implementation_type& impl) + : executor_(ex), + impl_(impl) + { + } + + template <typename Property> + query_result_t<const Executor&, Property> query_helper( + false_type, const Property& property) const + { + return asio::query(executor_, property); + } + + template <typename Property> + execution::blocking_t query_helper(true_type, const Property& property) const + { + execution::blocking_t result = asio::query(executor_, property); + return result == execution::blocking.always + ? execution::blocking.possibly : result; + } + + Executor executor_; implementation_type impl_; }; +/** @defgroup make_strand asio::make_strand + * + * @brief The asio::make_strand function creates a @ref strand object for + * an executor or execution context. + */ +/*@{*/ + +/// Create a @ref strand object for an executor. +/** + * @param ex An executor. + * + * @returns A strand constructed with the specified executor. + */ +template <typename Executor> +inline strand<Executor> make_strand(const Executor& ex, + constraint_t< + is_executor<Executor>::value || execution::is_executor<Executor>::value + > = 0) +{ + return strand<Executor>(ex); +} + +/// Create a @ref strand object for an execution context. +/** + * @param ctx An execution context, from which an executor will be obtained. + * + * @returns A strand constructed with the execution context's executor, obtained + * by performing <tt>ctx.get_executor()</tt>. + */ +template <typename ExecutionContext> +inline strand<typename ExecutionContext::executor_type> +make_strand(ExecutionContext& ctx, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) +{ + return strand<typename ExecutionContext::executor_type>(ctx.get_executor()); +} + +/*@}*/ + +#if !defined(GENERATING_DOCUMENTATION) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename Executor> +struct equality_comparable<strand<Executor>> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename Executor, typename Function> +struct execute_member<strand<Executor>, Function, + enable_if_t< + traits::execute_member<const Executor&, Function>::is_valid + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Executor, typename Property> +struct query_member<strand<Executor>, Property, + enable_if_t< + can_query<const Executor&, Property>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_query<Executor, Property>::value; + typedef conditional_t< + is_convertible<Property, execution::blocking_t>::value, + execution::blocking_t, query_result_t<Executor, Property>> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Executor, typename Property> +struct require_member<strand<Executor>, Property, + enable_if_t< + can_require<const Executor&, Property>::value + && !is_convertible<Property, execution::blocking_t::always_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_require<Executor, Property>::value; + typedef strand<decay_t<require_result_t<Executor, Property>>> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template <typename Executor, typename Property> +struct prefer_member<strand<Executor>, Property, + enable_if_t< + can_prefer<const Executor&, Property>::value + && !is_convertible<Property, execution::blocking_t::always_t>::value + >> +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = + is_nothrow_prefer<Executor, Property>::value; + typedef strand<decay_t<prefer_result_t<Executor, Property>>> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/stream_file.hpp b/3rdparty/asio/include/asio/stream_file.hpp new file mode 100644 index 00000000000..ef059a987e5 --- /dev/null +++ b/3rdparty/asio/include/asio/stream_file.hpp @@ -0,0 +1,35 @@ +// +// stream_file.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_STREAM_FILE_HPP +#define ASIO_STREAM_FILE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_FILE) \ + || defined(GENERATING_DOCUMENTATION) + +#include "asio/basic_stream_file.hpp" + +namespace asio { + +/// Typedef for the typical usage of a stream-oriented file. +typedef basic_stream_file<> stream_file; + +} // namespace asio + +#endif // defined(ASIO_HAS_FILE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_STREAM_FILE_HPP diff --git a/3rdparty/asio/include/asio/stream_socket_service.hpp b/3rdparty/asio/include/asio/stream_socket_service.hpp deleted file mode 100644 index 5cea56533d8..00000000000 --- a/3rdparty/asio/include/asio/stream_socket_service.hpp +++ /dev/null @@ -1,401 +0,0 @@ -// -// stream_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_STREAM_SOCKET_SERVICE_HPP -#define ASIO_STREAM_SOCKET_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/type_traits.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/winrt_ssocket_service.hpp" -#elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -#else -# include "asio/detail/reactive_socket_service.hpp" -#endif - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a stream socket. -template <typename Protocol> -class stream_socket_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<stream_socket_service<Protocol> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The protocol type. - typedef Protocol protocol_type; - - /// The endpoint type. - typedef typename Protocol::endpoint endpoint_type; - -private: - // The type of the platform-specific implementation. -#if defined(ASIO_WINDOWS_RUNTIME) - typedef detail::winrt_ssocket_service<Protocol> service_impl_type; -#elif defined(ASIO_HAS_IOCP) - typedef detail::win_iocp_socket_service<Protocol> service_impl_type; -#else - typedef detail::reactive_socket_service<Protocol> service_impl_type; -#endif - -public: - /// The type of a stream socket implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef typename service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new stream socket service for the specified io_context. - explicit stream_socket_service(asio::io_context& io_context) - : asio::detail::service_base< - stream_socket_service<Protocol> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new stream socket implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new stream socket implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another stream socket implementation. - void move_assign(implementation_type& impl, - stream_socket_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } - - /// Move-construct a new stream socket implementation from another protocol - /// type. - template <typename Protocol1> - void converting_move_construct(implementation_type& impl, - typename stream_socket_service< - Protocol1>::implementation_type& other_impl, - typename enable_if<is_convertible< - Protocol1, Protocol>::value>::type* = 0) - { - service_impl_.template converting_move_construct<Protocol1>( - impl, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a stream socket implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Open a stream socket. - ASIO_SYNC_OP_VOID open(implementation_type& impl, - const protocol_type& protocol, asio::error_code& ec) - { - if (protocol.type() == ASIO_OS_DEF(SOCK_STREAM)) - service_impl_.open(impl, protocol, ec); - else - ec = asio::error::invalid_argument; - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Assign an existing native socket to a stream socket. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const protocol_type& protocol, const native_handle_type& native_socket, - asio::error_code& ec) - { - service_impl_.assign(impl, protocol, native_socket, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a stream socket implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native socket implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the socket. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.at_mark(impl, ec); - } - - /// Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.available(impl, ec); - } - - /// Bind the stream socket to the specified local endpoint. - ASIO_SYNC_OP_VOID bind(implementation_type& impl, - const endpoint_type& endpoint, asio::error_code& ec) - { - service_impl_.bind(impl, endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Connect the stream socket to the specified endpoint. - ASIO_SYNC_OP_VOID connect(implementation_type& impl, - const endpoint_type& peer_endpoint, asio::error_code& ec) - { - service_impl_.connect(impl, peer_endpoint, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Start an asynchronous connect. - template <typename ConnectHandler> - ASIO_INITFN_RESULT_TYPE(ConnectHandler, - void (asio::error_code)) - async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(ConnectHandler) handler) - { - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); - - return init.result.get(); - } - - /// Set a socket option. - template <typename SettableSocketOption> - ASIO_SYNC_OP_VOID set_option(implementation_type& impl, - const SettableSocketOption& option, asio::error_code& ec) - { - service_impl_.set_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get a socket option. - template <typename GettableSocketOption> - ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, - GettableSocketOption& option, asio::error_code& ec) const - { - service_impl_.get_option(impl, option, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform an IO control command on the socket. - template <typename IoControlCommand> - ASIO_SYNC_OP_VOID io_control(implementation_type& impl, - IoControlCommand& command, asio::error_code& ec) - { - service_impl_.io_control(impl, command, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the socket. - bool non_blocking(const implementation_type& impl) const - { - return service_impl_.non_blocking(impl); - } - - /// Sets the non-blocking mode of the socket. - ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Gets the non-blocking mode of the native socket implementation. - bool native_non_blocking(const implementation_type& impl) const - { - return service_impl_.native_non_blocking(impl); - } - - /// Sets the non-blocking mode of the native socket implementation. - ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, - bool mode, asio::error_code& ec) - { - service_impl_.native_non_blocking(impl, mode, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the local endpoint. - endpoint_type local_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.local_endpoint(impl, ec); - } - - /// Get the remote endpoint. - endpoint_type remote_endpoint(const implementation_type& impl, - asio::error_code& ec) const - { - return service_impl_.remote_endpoint(impl, ec); - } - - /// Disable sends or receives on the socket. - ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, - socket_base::shutdown_type what, asio::error_code& ec) - { - service_impl_.shutdown(impl, what, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Wait for the socket to become ready to read, ready to write, or to have - /// pending error conditions. - ASIO_SYNC_OP_VOID wait(implementation_type& impl, - socket_base::wait_type w, asio::error_code& ec) - { - service_impl_.wait(impl, w, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Asynchronously wait for the socket to become ready to read, ready to - /// write, or to have pending error conditions. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, socket_base::wait_type w, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, w, init.completion_handler); - - return init.result.get(); - } - - /// Send the given data to the peer. - template <typename ConstBufferSequence> - std::size_t send(implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.send(impl, buffers, flags, ec); - } - - /// Start an asynchronous send. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_send(implementation_type& impl, - const ConstBufferSequence& buffers, - socket_base::message_flags flags, - ASIO_MOVE_ARG(WriteHandler) handler) - { - async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_send(impl, buffers, flags, init.completion_handler); - - return init.result.get(); - } - - /// Receive some data from the peer. - template <typename MutableBufferSequence> - std::size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, asio::error_code& ec) - { - return service_impl_.receive(impl, buffers, flags, ec); - } - - /// Start an asynchronous receive. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, - ASIO_MOVE_ARG(ReadHandler) handler) - { - async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_receive(impl, buffers, flags, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_STREAM_SOCKET_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/streambuf.hpp b/3rdparty/asio/include/asio/streambuf.hpp index 8e613e9de91..d7745245cb8 100644 --- a/3rdparty/asio/include/asio/streambuf.hpp +++ b/3rdparty/asio/include/asio/streambuf.hpp @@ -2,7 +2,7 @@ // streambuf.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/system_context.hpp b/3rdparty/asio/include/asio/system_context.hpp new file mode 100644 index 00000000000..132ce615677 --- /dev/null +++ b/3rdparty/asio/include/asio/system_context.hpp @@ -0,0 +1,90 @@ +// +// system_context.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_SYSTEM_CONTEXT_HPP +#define ASIO_SYSTEM_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/scheduler.hpp" +#include "asio/detail/thread_group.hpp" +#include "asio/execution.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Blocking, typename Relationship, typename Allocator> +class basic_system_executor; + +/// The executor context for the system executor. +class system_context : public execution_context +{ +public: + /// The executor type associated with the context. + typedef basic_system_executor< + execution::blocking_t::possibly_t, + execution::relationship_t::fork_t, + std::allocator<void> + > executor_type; + + /// Destructor shuts down all threads in the system thread pool. + ASIO_DECL ~system_context(); + + /// Obtain an executor for the context. + executor_type get_executor() noexcept; + + /// Signal all threads in the system thread pool to stop. + ASIO_DECL void stop(); + + /// Determine whether the system thread pool has been stopped. + ASIO_DECL bool stopped() const noexcept; + + /// Join all threads in the system thread pool. + ASIO_DECL void join(); + +#if defined(GENERATING_DOCUMENTATION) +private: +#endif // defined(GENERATING_DOCUMENTATION) + // Constructor creates all threads in the system thread pool. + ASIO_DECL system_context(); + +private: + template <typename, typename, typename> friend class basic_system_executor; + + struct thread_function; + + // Helper function to create the underlying scheduler. + ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s); + + // The underlying scheduler. + detail::scheduler& scheduler_; + + // The threads in the system thread pool. + detail::thread_group threads_; + + // The number of threads in the pool. + std::size_t num_threads_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/system_context.hpp" +#if defined(ASIO_HEADER_ONLY) +# include "asio/impl/system_context.ipp" +#endif // defined(ASIO_HEADER_ONLY) + +#endif // ASIO_SYSTEM_CONTEXT_HPP diff --git a/3rdparty/asio/include/asio/system_error.hpp b/3rdparty/asio/include/asio/system_error.hpp index 6c7a1e1424d..d7f932627bd 100644 --- a/3rdparty/asio/include/asio/system_error.hpp +++ b/3rdparty/asio/include/asio/system_error.hpp @@ -2,7 +2,7 @@ // system_error.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,114 +16,14 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_STD_SYSTEM_ERROR) -# include <system_error> -#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) -# include <cerrno> -# include <exception> -# include <string> -# include "asio/error_code.hpp" -# include "asio/detail/scoped_ptr.hpp" -#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) +#include <system_error> #include "asio/detail/push_options.hpp" namespace asio { -#if defined(ASIO_HAS_STD_SYSTEM_ERROR) - typedef std::system_error system_error; -#else // defined(ASIO_HAS_STD_SYSTEM_ERROR) - -/// The system_error class is used to represent system conditions that -/// prevent the library from operating correctly. -class system_error - : public std::exception -{ -public: - /// Construct with an error code. - system_error(const error_code& ec) - : code_(ec), - context_() - { - } - - /// Construct with an error code and context. - system_error(const error_code& ec, const std::string& context) - : code_(ec), - context_(context) - { - } - - /// Copy constructor. - system_error(const system_error& other) - : std::exception(other), - code_(other.code_), - context_(other.context_), - what_() - { - } - - /// Destructor. - virtual ~system_error() throw () - { - } - - /// Assignment operator. - system_error& operator=(const system_error& e) - { - context_ = e.context_; - code_ = e.code_; - what_.reset(); - return *this; - } - - /// Get a string representation of the exception. - virtual const char* what() const throw () - { -#if !defined(ASIO_NO_EXCEPTIONS) - try -#endif // !defined(ASIO_NO_EXCEPTIONS) - { - if (!what_.get()) - { - std::string tmp(context_); - if (tmp.length()) - tmp += ": "; - tmp += code_.message(); - what_.reset(new std::string(tmp)); - } - return what_->c_str(); - } -#if !defined(ASIO_NO_EXCEPTIONS) - catch (std::exception&) - { - return "system_error"; - } -#endif // !defined(ASIO_NO_EXCEPTIONS) - } - - /// Get the error code associated with the exception. - error_code code() const - { - return code_; - } - -private: - // The code associated with the error. - error_code code_; - - // The context associated with the error. - std::string context_; - - // The string representation of the error. - mutable asio::detail::scoped_ptr<std::string> what_; -}; - -#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR) - } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/system_executor.hpp b/3rdparty/asio/include/asio/system_executor.hpp index f23e35f04b6..19b6d30e322 100644 --- a/3rdparty/asio/include/asio/system_executor.hpp +++ b/3rdparty/asio/include/asio/system_executor.hpp @@ -2,7 +2,7 @@ // system_executor.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,32 +16,321 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/detail/scheduler.hpp" -#include "asio/detail/thread_group.hpp" -#include "asio/execution_context.hpp" +#include "asio/detail/memory.hpp" +#include "asio/execution.hpp" #include "asio/detail/push_options.hpp" namespace asio { +class system_context; + /// An executor that uses arbitrary threads. /** * The system executor represents an execution context where functions are - * permitted to run on arbitrary threads. The post() and defer() functions - * schedule the function to run on an unspecified system thread pool, and - * dispatch() invokes the function immediately. + * permitted to run on arbitrary threads. When the blocking.never property is + * established, the system executor will schedule the function to run on an + * unspecified system thread pool. When either blocking.possibly or + * blocking.always is established, the executor invokes the function + * immediately. */ -class system_executor +template <typename Blocking, typename Relationship, typename Allocator> +class basic_system_executor { public: + /// Default constructor. + basic_system_executor() noexcept + : allocator_(Allocator()) + { + } + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_require_fn::impl; + friend struct asio_prefer_fn::impl; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Obtain an executor with the @c blocking.possibly property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::system_executor ex1; + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.possibly); @endcode + */ + basic_system_executor<execution::blocking_t::possibly_t, + Relationship, Allocator> + require(execution::blocking_t::possibly_t) const + { + return basic_system_executor<execution::blocking_t::possibly_t, + Relationship, Allocator>(allocator_); + } + + /// Obtain an executor with the @c blocking.always property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::system_executor ex1; + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.always); @endcode + */ + basic_system_executor<execution::blocking_t::always_t, + Relationship, Allocator> + require(execution::blocking_t::always_t) const + { + return basic_system_executor<execution::blocking_t::always_t, + Relationship, Allocator>(allocator_); + } + + /// Obtain an executor with the @c blocking.never property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::system_executor ex1; + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.never); @endcode + */ + basic_system_executor<execution::blocking_t::never_t, + Relationship, Allocator> + require(execution::blocking_t::never_t) const + { + return basic_system_executor<execution::blocking_t::never_t, + Relationship, Allocator>(allocator_); + } + + /// Obtain an executor with the @c relationship.continuation property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::system_executor ex1; + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.continuation); @endcode + */ + basic_system_executor<Blocking, + execution::relationship_t::continuation_t, Allocator> + require(execution::relationship_t::continuation_t) const + { + return basic_system_executor<Blocking, + execution::relationship_t::continuation_t, Allocator>(allocator_); + } + + /// Obtain an executor with the @c relationship.fork property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::system_executor ex1; + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.fork); @endcode + */ + basic_system_executor<Blocking, + execution::relationship_t::fork_t, Allocator> + require(execution::relationship_t::fork_t) const + { + return basic_system_executor<Blocking, + execution::relationship_t::fork_t, Allocator>(allocator_); + } + + /// Obtain an executor with the specified @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::system_executor ex1; + * auto ex2 = asio::require(ex1, + * asio::execution::allocator(my_allocator)); @endcode + */ + template <typename OtherAllocator> + basic_system_executor<Blocking, Relationship, OtherAllocator> + require(execution::allocator_t<OtherAllocator> a) const + { + return basic_system_executor<Blocking, + Relationship, OtherAllocator>(a.value()); + } + + /// Obtain an executor with the default @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code asio::system_executor ex1; + * auto ex2 = asio::require(ex1, + * asio::execution::allocator); @endcode + */ + basic_system_executor<Blocking, Relationship, std::allocator<void>> + require(execution::allocator_t<void>) const + { + return basic_system_executor<Blocking, + Relationship, std::allocator<void>>(); + } + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_query_fn::impl; + friend struct asio::execution::detail::blocking_t<0>; + friend struct asio::execution::detail::mapping_t<0>; + friend struct asio::execution::detail::outstanding_work_t<0>; + friend struct asio::execution::detail::relationship_t<0>; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Query the current value of the @c mapping property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::system_executor ex; + * if (asio::query(ex, asio::execution::mapping) + * == asio::execution::mapping.thread) + * ... @endcode + */ + static constexpr execution::mapping_t query( + execution::mapping_t) noexcept + { + return execution::mapping.thread; + } + + /// Query the current value of the @c context property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::system_executor ex; + * asio::system_context& pool = asio::query( + * ex, asio::execution::context); @endcode + */ + static system_context& query(execution::context_t) noexcept; + + /// Query the current value of the @c blocking property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::system_executor ex; + * if (asio::query(ex, asio::execution::blocking) + * == asio::execution::blocking.always) + * ... @endcode + */ + static constexpr execution::blocking_t query( + execution::blocking_t) noexcept + { + return Blocking(); + } + + /// Query the current value of the @c relationship property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::system_executor ex; + * if (asio::query(ex, asio::execution::relationship) + * == asio::execution::relationship.continuation) + * ... @endcode + */ + static constexpr execution::relationship_t query( + execution::relationship_t) noexcept + { + return Relationship(); + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::system_executor ex; + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + template <typename OtherAllocator> + constexpr Allocator query( + execution::allocator_t<OtherAllocator>) const noexcept + { + return allocator_; + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::system_executor ex; + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + constexpr Allocator query( + execution::allocator_t<void>) const noexcept + { + return allocator_; + } + + /// Query the occupancy (recommended number of work items) for the system + /// context. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code asio::system_executor ex; + * std::size_t occupancy = asio::query( + * ex, asio::execution::occupancy); @endcode + */ + std::size_t query(execution::occupancy_t) const noexcept; + +public: + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator==(const basic_system_executor&, + const basic_system_executor&) noexcept + { + return true; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator!=(const basic_system_executor&, + const basic_system_executor&) noexcept + { + return false; + } + + /// Execution function. + template <typename Function> + void execute(Function&& f) const + { + this->do_execute(static_cast<Function&&>(f), Blocking()); + } + +#if !defined(ASIO_NO_TS_EXECUTORS) +public: /// Obtain the underlying execution context. - execution_context& context() const ASIO_NOEXCEPT; + system_context& context() const noexcept; /// Inform the executor that it has some outstanding work to do. /** * For the system executor, this is a no-op. */ - void on_work_started() const ASIO_NOEXCEPT + void on_work_started() const noexcept { } @@ -49,7 +338,7 @@ public: /** * For the system executor, this is a no-op. */ - void on_work_finished() const ASIO_NOEXCEPT + void on_work_finished() const noexcept { } @@ -65,8 +354,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void dispatch(Function&& f, const OtherAllocator& a) const; /// Request the system executor to invoke the given function object. /** @@ -81,8 +370,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void post(Function&& f, const OtherAllocator& a) const; /// Request the system executor to invoke the given function object. /** @@ -97,57 +386,286 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void defer(Function&& f, const OtherAllocator& a) const; +#endif // !defined(ASIO_NO_TS_EXECUTORS) - /// Compare two executors for equality. - /** - * System executors always compare equal. - */ - friend bool operator==(const system_executor&, - const system_executor&) ASIO_NOEXCEPT +private: + template <typename, typename, typename> friend class basic_system_executor; + + // Constructor used by require(). + basic_system_executor(const Allocator& a) + : allocator_(a) { - return true; } - /// Compare two executors for inequality. - /** - * System executors always compare equal. - */ - friend bool operator!=(const system_executor&, - const system_executor&) ASIO_NOEXCEPT + /// Execution helper implementation for the possibly blocking property. + template <typename Function> + void do_execute(Function&& f, + execution::blocking_t::possibly_t) const; + + /// Execution helper implementation for the always blocking property. + template <typename Function> + void do_execute(Function&& f, + execution::blocking_t::always_t) const; + + /// Execution helper implementation for the never blocking property. + template <typename Function> + void do_execute(Function&& f, + execution::blocking_t::never_t) const; + + // The allocator used for execution functions. + Allocator allocator_; +}; + +/// An executor that uses arbitrary threads. +/** + * The system executor represents an execution context where functions are + * permitted to run on arbitrary threads. When the blocking.never property is + * established, the system executor will schedule the function to run on an + * unspecified system thread pool. When either blocking.possibly or + * blocking.always is established, the executor invokes the function + * immediately. + */ +typedef basic_system_executor<execution::blocking_t::possibly_t, + execution::relationship_t::fork_t, std::allocator<void>> + system_executor; + +#if !defined(GENERATING_DOCUMENTATION) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename Blocking, typename Relationship, typename Allocator> +struct equality_comparable< + asio::basic_system_executor<Blocking, Relationship, Allocator> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename Blocking, typename Relationship, + typename Allocator, typename Function> +struct execute_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + Function + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Blocking, typename Relationship, typename Allocator> +struct require_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::blocking_t::possibly_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::basic_system_executor< + asio::execution::blocking_t::possibly_t, + Relationship, Allocator> result_type; +}; + +template <typename Blocking, typename Relationship, typename Allocator> +struct require_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::blocking_t::always_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::basic_system_executor< + asio::execution::blocking_t::always_t, + Relationship, Allocator> result_type; +}; + +template <typename Blocking, typename Relationship, typename Allocator> +struct require_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::blocking_t::never_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::basic_system_executor< + asio::execution::blocking_t::never_t, + Relationship, Allocator> result_type; +}; + +template <typename Blocking, typename Relationship, typename Allocator> +struct require_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::relationship_t::fork_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::basic_system_executor<Blocking, + asio::execution::relationship_t::fork_t, + Allocator> result_type; +}; + +template <typename Blocking, typename Relationship, typename Allocator> +struct require_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::relationship_t::continuation_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::basic_system_executor<Blocking, + asio::execution::relationship_t::continuation_t, + Allocator> result_type; +}; + +template <typename Blocking, typename Relationship, typename Allocator> +struct require_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::allocator_t<void> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::basic_system_executor<Blocking, + Relationship, std::allocator<void>> result_type; +}; + +template <typename Blocking, typename Relationship, + typename Allocator, typename OtherAllocator> +struct require_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::allocator_t<OtherAllocator> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::basic_system_executor<Blocking, + Relationship, OtherAllocator> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename Blocking, typename Relationship, + typename Allocator, typename Property> +struct query_static_constexpr_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::mapping_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::mapping_t::thread_t result_type; + + static constexpr result_type value() noexcept { - return false; + return result_type(); } +}; -private: - struct thread_function; +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) - // Hidden implementation of the system execution context. - struct context_impl - : public execution_context - { - // Constructor creates all threads in the system thread pool. - ASIO_DECL context_impl(); +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Blocking, typename Relationship, + typename Allocator, typename Property> +struct query_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::blocking_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::blocking_t result_type; +}; - // Destructor shuts down all threads in the system thread pool. - ASIO_DECL ~context_impl(); +template <typename Blocking, typename Relationship, + typename Allocator, typename Property> +struct query_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::relationship_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::relationship_t result_type; +}; - // The underlying scheduler. - detail::scheduler& scheduler_; +template <typename Blocking, typename Relationship, typename Allocator> +struct query_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::context_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::system_context& result_type; +}; - // The threads in the system thread pool. - detail::thread_group threads_; - }; +template <typename Blocking, typename Relationship, typename Allocator> +struct query_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::allocator_t<void> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Allocator result_type; }; +template <typename Blocking, typename Relationship, typename Allocator> +struct query_member< + asio::basic_system_executor<Blocking, Relationship, Allocator>, + asio::execution::allocator_t<Allocator> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Allocator result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/impl/system_executor.hpp" -#if defined(ASIO_HEADER_ONLY) -# include "asio/impl/system_executor.ipp" -#endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_SYSTEM_EXECUTOR_HPP diff --git a/3rdparty/asio/include/asio/system_timer.hpp b/3rdparty/asio/include/asio/system_timer.hpp index d28e92c2dd4..7b5e768032f 100644 --- a/3rdparty/asio/include/asio/system_timer.hpp +++ b/3rdparty/asio/include/asio/system_timer.hpp @@ -2,7 +2,7 @@ // system_timer.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) - #include "asio/basic_waitable_timer.hpp" #include "asio/detail/chrono.hpp" @@ -37,6 +34,4 @@ typedef basic_waitable_timer<chrono::system_clock> system_timer; } // namespace asio -#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) - #endif // ASIO_SYSTEM_TIMER_HPP diff --git a/3rdparty/asio/include/asio/this_coro.hpp b/3rdparty/asio/include/asio/this_coro.hpp new file mode 100644 index 00000000000..37381b92abf --- /dev/null +++ b/3rdparty/asio/include/asio/this_coro.hpp @@ -0,0 +1,267 @@ +// +// this_coro.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_THIS_CORO_HPP +#define ASIO_THIS_CORO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace this_coro { + +/// Awaitable type that returns the executor of the current coroutine. +struct executor_t +{ + constexpr executor_t() + { + } +}; + +/// Awaitable object that returns the executor of the current coroutine. +constexpr executor_t executor; + +/// Awaitable type that returns the cancellation state of the current coroutine. +struct cancellation_state_t +{ + constexpr cancellation_state_t() + { + } +}; + +/// Awaitable object that returns the cancellation state of the current +/// coroutine. +/** + * @par Example + * @code asio::awaitable<void> my_coroutine() + * { + * asio::cancellation_state cs + * = co_await asio::this_coro::cancellation_state; + * + * // ... + * + * if (cs.cancelled() != asio::cancellation_type::none) + * // ... + * } @endcode + */ +constexpr cancellation_state_t cancellation_state; + +#if defined(GENERATING_DOCUMENTATION) + +/// Returns an awaitable object that may be used to reset the cancellation state +/// of the current coroutine. +/** + * Let <tt>P</tt> be the cancellation slot associated with the current + * coroutine's @ref co_spawn completion handler. Assigns a new + * asio::cancellation_state object <tt>S</tt>, constructed as + * <tt>S(P)</tt>, into the current coroutine's cancellation state object. + * + * @par Example + * @code asio::awaitable<void> my_coroutine() + * { + * co_await asio::this_coro::reset_cancellation_state(); + * + * // ... + * } @endcode + * + * @note The cancellation state is shared by all coroutines in the same "thread + * of execution" that was created using asio::co_spawn. + */ +ASIO_NODISCARD constexpr unspecified +reset_cancellation_state(); + +/// Returns an awaitable object that may be used to reset the cancellation state +/// of the current coroutine. +/** + * Let <tt>P</tt> be the cancellation slot associated with the current + * coroutine's @ref co_spawn completion handler. Assigns a new + * asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P, + * std::forward<Filter>(filter))</tt>, into the current coroutine's + * cancellation state object. + * + * @par Example + * @code asio::awaitable<void> my_coroutine() + * { + * co_await asio::this_coro::reset_cancellation_state( + * asio::enable_partial_cancellation()); + * + * // ... + * } @endcode + * + * @note The cancellation state is shared by all coroutines in the same "thread + * of execution" that was created using asio::co_spawn. + */ +template <typename Filter> +ASIO_NODISCARD constexpr unspecified +reset_cancellation_state(Filter&& filter); + +/// Returns an awaitable object that may be used to reset the cancellation state +/// of the current coroutine. +/** + * Let <tt>P</tt> be the cancellation slot associated with the current + * coroutine's @ref co_spawn completion handler. Assigns a new + * asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P, + * std::forward<InFilter>(in_filter), + * std::forward<OutFilter>(out_filter))</tt>, into the current coroutine's + * cancellation state object. + * + * @par Example + * @code asio::awaitable<void> my_coroutine() + * { + * co_await asio::this_coro::reset_cancellation_state( + * asio::enable_partial_cancellation(), + * asio::disable_cancellation()); + * + * // ... + * } @endcode + * + * @note The cancellation state is shared by all coroutines in the same "thread + * of execution" that was created using asio::co_spawn. + */ +template <typename InFilter, typename OutFilter> +ASIO_NODISCARD constexpr unspecified +reset_cancellation_state( + InFilter&& in_filter, + OutFilter&& out_filter); + +/// Returns an awaitable object that may be used to determine whether the +/// coroutine throws if trying to suspend when it has been cancelled. +/** + * @par Example + * @code asio::awaitable<void> my_coroutine() + * { + * if (co_await asio::this_coro::throw_if_cancelled) + * // ... + * + * // ... + * } @endcode + */ +ASIO_NODISCARD constexpr unspecified +throw_if_cancelled(); + +/// Returns an awaitable object that may be used to specify whether the +/// coroutine throws if trying to suspend when it has been cancelled. +/** + * @par Example + * @code asio::awaitable<void> my_coroutine() + * { + * co_await asio::this_coro::throw_if_cancelled(false); + * + * // ... + * } @endcode + */ +ASIO_NODISCARD constexpr unspecified +throw_if_cancelled(bool value); + +#else // defined(GENERATING_DOCUMENTATION) + +struct reset_cancellation_state_0_t +{ + constexpr reset_cancellation_state_0_t() + { + } +}; + +ASIO_NODISCARD inline constexpr reset_cancellation_state_0_t +reset_cancellation_state() +{ + return reset_cancellation_state_0_t(); +} + +template <typename Filter> +struct reset_cancellation_state_1_t +{ + template <typename F> + explicit constexpr reset_cancellation_state_1_t( + F&& filt) + : filter(static_cast<F&&>(filt)) + { + } + + Filter filter; +}; + +template <typename Filter> +ASIO_NODISCARD inline constexpr reset_cancellation_state_1_t< + decay_t<Filter>> +reset_cancellation_state(Filter&& filter) +{ + return reset_cancellation_state_1_t<decay_t<Filter>>( + static_cast<Filter&&>(filter)); +} + +template <typename InFilter, typename OutFilter> +struct reset_cancellation_state_2_t +{ + template <typename F1, typename F2> + constexpr reset_cancellation_state_2_t( + F1&& in_filt, F2&& out_filt) + : in_filter(static_cast<F1&&>(in_filt)), + out_filter(static_cast<F2&&>(out_filt)) + { + } + + InFilter in_filter; + OutFilter out_filter; +}; + +template <typename InFilter, typename OutFilter> +ASIO_NODISCARD inline constexpr +reset_cancellation_state_2_t<decay_t<InFilter>, decay_t<OutFilter>> +reset_cancellation_state(InFilter&& in_filter, OutFilter&& out_filter) +{ + return reset_cancellation_state_2_t<decay_t<InFilter>, decay_t<OutFilter>>( + static_cast<InFilter&&>(in_filter), + static_cast<OutFilter&&>(out_filter)); +} + +struct throw_if_cancelled_0_t +{ + constexpr throw_if_cancelled_0_t() + { + } +}; + +ASIO_NODISCARD inline constexpr throw_if_cancelled_0_t +throw_if_cancelled() +{ + return throw_if_cancelled_0_t(); +} + +struct throw_if_cancelled_1_t +{ + explicit constexpr throw_if_cancelled_1_t(bool val) + : value(val) + { + } + + bool value; +}; + +ASIO_NODISCARD inline constexpr throw_if_cancelled_1_t +throw_if_cancelled(bool value) +{ + return throw_if_cancelled_1_t(value); +} + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace this_coro +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_THIS_CORO_HPP diff --git a/3rdparty/asio/include/asio/thread.hpp b/3rdparty/asio/include/asio/thread.hpp index 45ae3926d9e..fc57bffdd9e 100644 --- a/3rdparty/asio/include/asio/thread.hpp +++ b/3rdparty/asio/include/asio/thread.hpp @@ -2,7 +2,7 @@ // thread.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/thread_pool.hpp b/3rdparty/asio/include/asio/thread_pool.hpp index f62fc9d880e..f9095d9441a 100644 --- a/3rdparty/asio/include/asio/thread_pool.hpp +++ b/3rdparty/asio/include/asio/thread_pool.hpp @@ -2,7 +2,7 @@ // thread_pool.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,28 +16,78 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/detail/noncopyable.hpp" +#include "asio/detail/atomic_count.hpp" #include "asio/detail/scheduler.hpp" #include "asio/detail/thread_group.hpp" +#include "asio/execution.hpp" #include "asio/execution_context.hpp" #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + struct thread_pool_bits + { + static constexpr unsigned int blocking_never = 1; + static constexpr unsigned int blocking_always = 2; + static constexpr unsigned int blocking_mask = 3; + static constexpr unsigned int relationship_continuation = 4; + static constexpr unsigned int outstanding_work_tracked = 8; + }; +} // namespace detail /// A simple fixed-size thread pool. /** * The thread pool class is an execution context where functions are permitted * to run on one of a fixed number of threads. + * + * @par Submitting tasks to the pool + * + * To submit functions to the thread pool, use the @ref asio::dispatch, + * @ref asio::post or @ref asio::defer free functions. + * + * For example: + * + * @code void my_task() + * { + * ... + * } + * + * ... + * + * // Launch the pool with four threads. + * asio::thread_pool pool(4); + * + * // Submit a function to the pool. + * asio::post(pool, my_task); + * + * // Submit a lambda object to the pool. + * asio::post(pool, + * []() + * { + * ... + * }); + * + * // Wait for all tasks in the pool to complete. + * pool.join(); @endcode */ class thread_pool : public execution_context { public: - class executor_type; + template <typename Allocator, unsigned int Bits> + class basic_executor_type; + + template <typename Allocator, unsigned int Bits> + friend class basic_executor_type; + + /// Executor used to submit functions to a thread pool. + typedef basic_executor_type<std::allocator<void>, 0> executor_type; +#if !defined(ASIO_NO_TS_EXECUTORS) /// Constructs a pool with an automatically determined number of threads. ASIO_DECL thread_pool(); +#endif // !defined(ASIO_NO_TS_EXECUTORS) /// Constructs a pool with a specified number of threads. ASIO_DECL thread_pool(std::size_t num_threads); @@ -49,7 +99,10 @@ public: ASIO_DECL ~thread_pool(); /// Obtains the executor associated with the pool. - executor_type get_executor() ASIO_NOEXCEPT; + executor_type get_executor() noexcept; + + /// Obtains the executor associated with the pool. + executor_type executor() noexcept; /// Stops the threads. /** @@ -58,6 +111,14 @@ public: */ ASIO_DECL void stop(); + /// Attaches the current thread to the pool. + /** + * This function attaches the current thread to the pool so that it may be + * used for executing submitted function objects. Blocks the calling thread + * until the pool is stopped or joined and has no outstanding work. + */ + ASIO_DECL void attach(); + /// Joins the threads. /** * This function blocks until the threads in the pool have completed. If @c @@ -66,23 +127,425 @@ public: */ ASIO_DECL void join(); + /// Waits for threads to complete. + /** + * This function blocks until the threads in the pool have completed. If @c + * stop() is not called prior to @c wait(), the @c wait() call will wait + * until the pool has no more outstanding work. + */ + ASIO_DECL void wait(); + private: - friend class executor_type; + thread_pool(const thread_pool&) = delete; + thread_pool& operator=(const thread_pool&) = delete; + struct thread_function; + // Helper function to create the underlying scheduler. + ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s); + // The underlying scheduler. detail::scheduler& scheduler_; // The threads in the pool. detail::thread_group threads_; + + // The current number of threads in the pool. + detail::atomic_count num_threads_; }; -/// Executor used to submit functions to a thread pool. -class thread_pool::executor_type +/// Executor implementation type used to submit functions to a thread pool. +template <typename Allocator, unsigned int Bits> +class thread_pool::basic_executor_type : detail::thread_pool_bits { public: + /// Copy constructor. + basic_executor_type(const basic_executor_type& other) noexcept + : pool_(other.pool_), + allocator_(other.allocator_), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + if (pool_) + pool_->scheduler_.work_started(); + } + + /// Move constructor. + basic_executor_type(basic_executor_type&& other) noexcept + : pool_(other.pool_), + allocator_(static_cast<Allocator&&>(other.allocator_)), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + other.pool_ = 0; + } + + /// Destructor. + ~basic_executor_type() noexcept + { + if (Bits & outstanding_work_tracked) + if (pool_) + pool_->scheduler_.work_finished(); + } + + /// Assignment operator. + basic_executor_type& operator=(const basic_executor_type& other) noexcept; + + /// Move assignment operator. + basic_executor_type& operator=(basic_executor_type&& other) noexcept; + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_require_fn::impl; + friend struct asio_prefer_fn::impl; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Obtain an executor with the @c blocking.possibly property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.possibly); @endcode + */ + constexpr basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits & ~blocking_mask)> + require(execution::blocking_t::possibly_t) const + { + return basic_executor_type<Allocator, Bits & ~blocking_mask>( + pool_, allocator_, bits_ & ~blocking_mask); + } + + /// Obtain an executor with the @c blocking.always property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.always); @endcode + */ + constexpr basic_executor_type<Allocator, + ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)> + require(execution::blocking_t::always_t) const + { + return basic_executor_type<Allocator, + ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>( + pool_, allocator_, bits_ & ~blocking_mask); + } + + /// Obtain an executor with the @c blocking.never property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::blocking.never); @endcode + */ + constexpr basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits & ~blocking_mask)> + require(execution::blocking_t::never_t) const + { + return basic_executor_type<Allocator, Bits & ~blocking_mask>( + pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never); + } + + /// Obtain an executor with the @c relationship.fork property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.fork); @endcode + */ + constexpr basic_executor_type require(execution::relationship_t::fork_t) const + { + return basic_executor_type(pool_, + allocator_, bits_ & ~relationship_continuation); + } + + /// Obtain an executor with the @c relationship.continuation property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::relationship.continuation); @endcode + */ + constexpr basic_executor_type require( + execution::relationship_t::continuation_t) const + { + return basic_executor_type(pool_, + allocator_, bits_ | relationship_continuation); + } + + /// Obtain an executor with the @c outstanding_work.tracked property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::outstanding_work.tracked); @endcode + */ + constexpr basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)> + require(execution::outstanding_work_t::tracked_t) const + { + return basic_executor_type<Allocator, Bits | outstanding_work_tracked>( + pool_, allocator_, bits_); + } + + /// Obtain an executor with the @c outstanding_work.untracked property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::outstanding_work.untracked); @endcode + */ + constexpr basic_executor_type<Allocator, + ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)> + require(execution::outstanding_work_t::untracked_t) const + { + return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>( + pool_, allocator_, bits_); + } + + /// Obtain an executor with the specified @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::allocator(my_allocator)); @endcode + */ + template <typename OtherAllocator> + constexpr basic_executor_type<OtherAllocator, Bits> + require(execution::allocator_t<OtherAllocator> a) const + { + return basic_executor_type<OtherAllocator, Bits>( + pool_, a.value(), bits_); + } + + /// Obtain an executor with the default @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::require customisation point. + * + * For example: + * @code auto ex1 = my_thread_pool.executor(); + * auto ex2 = asio::require(ex1, + * asio::execution::allocator); @endcode + */ + constexpr basic_executor_type<std::allocator<void>, Bits> + require(execution::allocator_t<void>) const + { + return basic_executor_type<std::allocator<void>, Bits>( + pool_, std::allocator<void>(), bits_); + } + +#if !defined(GENERATING_DOCUMENTATION) +private: + friend struct asio_query_fn::impl; + friend struct asio::execution::detail::mapping_t<0>; + friend struct asio::execution::detail::outstanding_work_t<0>; +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Query the current value of the @c mapping property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * if (asio::query(ex, asio::execution::mapping) + * == asio::execution::mapping.thread) + * ... @endcode + */ + static constexpr execution::mapping_t query(execution::mapping_t) noexcept + { + return execution::mapping.thread; + } + + /// Query the current value of the @c context property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * asio::thread_pool& pool = asio::query( + * ex, asio::execution::context); @endcode + */ + thread_pool& query(execution::context_t) const noexcept + { + return *pool_; + } + + /// Query the current value of the @c blocking property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * if (asio::query(ex, asio::execution::blocking) + * == asio::execution::blocking.always) + * ... @endcode + */ + constexpr execution::blocking_t query(execution::blocking_t) const noexcept + { + return (bits_ & blocking_never) + ? execution::blocking_t(execution::blocking.never) + : ((Bits & blocking_always) + ? execution::blocking_t(execution::blocking.always) + : execution::blocking_t(execution::blocking.possibly)); + } + + /// Query the current value of the @c relationship property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * if (asio::query(ex, asio::execution::relationship) + * == asio::execution::relationship.continuation) + * ... @endcode + */ + constexpr execution::relationship_t query( + execution::relationship_t) const noexcept + { + return (bits_ & relationship_continuation) + ? execution::relationship_t(execution::relationship.continuation) + : execution::relationship_t(execution::relationship.fork); + } + + /// Query the current value of the @c outstanding_work property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * if (asio::query(ex, asio::execution::outstanding_work) + * == asio::execution::outstanding_work.tracked) + * ... @endcode + */ + static constexpr execution::outstanding_work_t query( + execution::outstanding_work_t) noexcept + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + template <typename OtherAllocator> + constexpr Allocator query( + execution::allocator_t<OtherAllocator>) const noexcept + { + return allocator_; + } + + /// Query the current value of the @c allocator property. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * auto alloc = asio::query(ex, + * asio::execution::allocator); @endcode + */ + constexpr Allocator query(execution::allocator_t<void>) const noexcept + { + return allocator_; + } + + /// Query the occupancy (recommended number of work items) for the pool. + /** + * Do not call this function directly. It is intended for use with the + * asio::query customisation point. + * + * For example: + * @code auto ex = my_thread_pool.executor(); + * std::size_t occupancy = asio::query( + * ex, asio::execution::occupancy); @endcode + */ + std::size_t query(execution::occupancy_t) const noexcept + { + return static_cast<std::size_t>(pool_->num_threads_); + } + +public: + /// Determine whether the thread pool is running in the current thread. + /** + * @return @c true if the current thread is running the thread pool. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const noexcept; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator==(const basic_executor_type& a, + const basic_executor_type& b) noexcept + { + return a.pool_ == b.pool_ + && a.allocator_ == b.allocator_ + && a.bits_ == b.bits_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator!=(const basic_executor_type& a, + const basic_executor_type& b) noexcept + { + return a.pool_ != b.pool_ + || a.allocator_ != b.allocator_ + || a.bits_ != b.bits_; + } + + /// Execution function. + template <typename Function> + void execute(Function&& f) const + { + this->do_execute(static_cast<Function&&>(f), + integral_constant<bool, (Bits & blocking_always) != 0>()); + } + +public: +#if !defined(ASIO_NO_TS_EXECUTORS) /// Obtain the underlying execution context. - thread_pool& context() const ASIO_NOEXCEPT; + thread_pool& context() const noexcept; /// Inform the thread pool that it has some outstanding work to do. /** @@ -90,7 +553,7 @@ public: * This ensures that the thread pool's join() function will not return while * the work is underway. */ - void on_work_started() const ASIO_NOEXCEPT; + void on_work_started() const noexcept; /// Inform the thread pool that some work is no longer outstanding. /** @@ -98,7 +561,7 @@ public: * finished. Once the count of unfinished work reaches zero, the thread * pool's join() function is permitted to exit. */ - void on_work_finished() const ASIO_NOEXCEPT; + void on_work_finished() const noexcept; /// Request the thread pool to invoke the given function object. /** @@ -114,8 +577,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void dispatch(Function&& f, const OtherAllocator& a) const; /// Request the thread pool to invoke the given function object. /** @@ -130,8 +593,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void post(Function&& f, const OtherAllocator& a) const; /// Request the thread pool to invoke the given function object. /** @@ -150,46 +613,344 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template <typename Function, typename Allocator> - void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template <typename Function, typename OtherAllocator> + void defer(Function&& f, const OtherAllocator& a) const; +#endif // !defined(ASIO_NO_TS_EXECUTORS) - /// Determine whether the thread pool is running in the current thread. - /** - * @return @c true if the current thread belongs to the pool. Otherwise - * returns @c false. - */ - bool running_in_this_thread() const ASIO_NOEXCEPT; +private: + friend class thread_pool; + template <typename, unsigned int> friend class basic_executor_type; - /// Compare two executors for equality. - /** - * Two executors are equal if they refer to the same underlying thread pool. - */ - friend bool operator==(const executor_type& a, - const executor_type& b) ASIO_NOEXCEPT + // Constructor used by thread_pool::get_executor(). + explicit basic_executor_type(thread_pool& p) noexcept + : pool_(&p), + allocator_(), + bits_(0) { - return &a.pool_ == &b.pool_; + if (Bits & outstanding_work_tracked) + pool_->scheduler_.work_started(); } - /// Compare two executors for inequality. - /** - * Two executors are equal if they refer to the same underlying thread pool. - */ - friend bool operator!=(const executor_type& a, - const executor_type& b) ASIO_NOEXCEPT + // Constructor used by require(). + basic_executor_type(thread_pool* p, + const Allocator& a, unsigned int bits) noexcept + : pool_(p), + allocator_(a), + bits_(bits) { - return &a.pool_ != &b.pool_; + if (Bits & outstanding_work_tracked) + if (pool_) + pool_->scheduler_.work_started(); } -private: - friend class thread_pool; + /// Execution helper implementation for possibly and never blocking. + template <typename Function> + void do_execute(Function&& f, false_type) const; - // Constructor. - explicit executor_type(thread_pool& p) : pool_(p) {} + /// Execution helper implementation for always blocking. + template <typename Function> + void do_execute(Function&& f, true_type) const; // The underlying thread pool. - thread_pool& pool_; + thread_pool* pool_; + + // The allocator used for execution functions. + Allocator allocator_; + + // The runtime-switched properties of the thread pool executor. + unsigned int bits_; +}; + +#if !defined(GENERATING_DOCUMENTATION) + +namespace traits { + +#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename Allocator, unsigned int Bits> +struct equality_comparable< + asio::thread_pool::basic_executor_type<Allocator, Bits> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits, typename Function> +struct execute_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + Function + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef void result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::blocking_t::possibly_t + > : asio::detail::thread_pool_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::thread_pool::basic_executor_type< + Allocator, Bits & ~blocking_mask> result_type; }; +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::blocking_t::always_t + > : asio::detail::thread_pool_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type<Allocator, + (Bits & ~blocking_mask) | blocking_always> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::blocking_t::never_t + > : asio::detail::thread_pool_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type< + Allocator, Bits & ~blocking_mask> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::relationship_t::fork_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::relationship_t::continuation_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type< + Allocator, Bits> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::outstanding_work_t::tracked_t + > : asio::detail::thread_pool_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type< + Allocator, Bits | outstanding_work_tracked> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::outstanding_work_t::untracked_t + > : asio::detail::thread_pool_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type< + Allocator, Bits & ~outstanding_work_tracked> result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<void> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type< + std::allocator<void>, Bits> result_type; +}; + +template <unsigned int Bits, + typename Allocator, typename OtherAllocator> +struct require_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<OtherAllocator> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = false; + typedef asio::thread_pool::basic_executor_type< + OtherAllocator, Bits> result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_static_constexpr_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::outstanding_work_t + >::value + >::type + > : asio::detail::thread_pool_bits +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::outstanding_work_t result_type; + + static constexpr result_type value() noexcept + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } +}; + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_static_constexpr_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::mapping_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::mapping_t::thread_t result_type; + + static constexpr result_type value() noexcept + { + return result_type(); + } +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::blocking_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::blocking_t result_type; +}; + +template <typename Allocator, unsigned int Bits, typename Property> +struct query_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + Property, + typename asio::enable_if< + asio::is_convertible< + Property, + asio::execution::relationship_t + >::value + >::type + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::execution::relationship_t result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct query_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::occupancy_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef std::size_t result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct query_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::context_t + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef asio::thread_pool& result_type; +}; + +template <typename Allocator, unsigned int Bits> +struct query_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<void> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Allocator result_type; +}; + +template <typename Allocator, unsigned int Bits, typename OtherAllocator> +struct query_member< + asio::thread_pool::basic_executor_type<Allocator, Bits>, + asio::execution::allocator_t<OtherAllocator> + > +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef Allocator result_type; +}; + +#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits + +namespace execution { + +template <> +struct is_executor<thread_pool> : false_type +{ +}; + +} // namespace execution + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio #include "asio/detail/pop_options.hpp" diff --git a/3rdparty/asio/include/asio/time_traits.hpp b/3rdparty/asio/include/asio/time_traits.hpp index c046794228a..f3980233eab 100644 --- a/3rdparty/asio/include/asio/time_traits.hpp +++ b/3rdparty/asio/include/asio/time_traits.hpp @@ -2,7 +2,7 @@ // time_traits.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/traits/equality_comparable.hpp b/3rdparty/asio/include/asio/traits/equality_comparable.hpp new file mode 100644 index 00000000000..0a6decf2d93 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/equality_comparable.hpp @@ -0,0 +1,100 @@ +// +// traits/equality_comparable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_EQUALITY_COMPARABLE_HPP +#define ASIO_TRAITS_EQUALITY_COMPARABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +namespace asio { +namespace traits { + +template <typename T, typename = void> +struct equality_comparable_default; + +template <typename T, typename = void> +struct equality_comparable; + +} // namespace traits +namespace detail { + +struct no_equality_comparable +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename T, typename = void> +struct equality_comparable_trait : no_equality_comparable +{ +}; + +template <typename T> +struct equality_comparable_trait<T, + void_t< + decltype( + static_cast<void>( + static_cast<bool>(declval<const T>() == declval<const T>()) + ), + static_cast<void>( + static_cast<bool>(declval<const T>() != declval<const T>()) + ) + ) + >> +{ + static constexpr bool is_valid = true; + + static constexpr bool is_noexcept = + noexcept(declval<const T>() == declval<const T>()) + && noexcept(declval<const T>() != declval<const T>()); +}; + +#else // defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template <typename T, typename = void> +struct equality_comparable_trait : + conditional_t< + is_same<T, decay_t<T>>::value, + no_equality_comparable, + traits::equality_comparable<decay_t<T>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename> +struct equality_comparable_default : detail::equality_comparable_trait<T> +{ +}; + +template <typename T, typename> +struct equality_comparable : equality_comparable_default<T> +{ +}; + +} // namespace traits +} // namespace asio + +#endif // ASIO_TRAITS_EQUALITY_COMPARABLE_HPP diff --git a/3rdparty/asio/include/asio/traits/execute_member.hpp b/3rdparty/asio/include/asio/traits/execute_member.hpp new file mode 100644 index 00000000000..fc0760bef05 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/execute_member.hpp @@ -0,0 +1,104 @@ +// +// traits/execute_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_EXECUTE_MEMBER_HPP +#define ASIO_TRAITS_EXECUTE_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename F, typename = void> +struct execute_member_default; + +template <typename T, typename F, typename = void> +struct execute_member; + +} // namespace traits +namespace detail { + +struct no_execute_member +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename T, typename F, typename = void> +struct execute_member_trait : no_execute_member +{ +}; + +template <typename T, typename F> +struct execute_member_trait<T, F, + void_t< + decltype(declval<T>().execute(declval<F>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + declval<T>().execute(declval<F>())); + + static constexpr bool is_noexcept = + noexcept(declval<T>().execute(declval<F>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template <typename T, typename F, typename = void> +struct execute_member_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<F, decay_t<F>>::value, + no_execute_member, + traits::execute_member< + decay_t<T>, + decay_t<F>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename F, typename> +struct execute_member_default : + detail::execute_member_trait<T, F> +{ +}; + +template <typename T, typename F, typename> +struct execute_member : + execute_member_default<T, F> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_EXECUTE_MEMBER_HPP diff --git a/3rdparty/asio/include/asio/traits/prefer_free.hpp b/3rdparty/asio/include/asio/traits/prefer_free.hpp new file mode 100644 index 00000000000..c6104d636ed --- /dev/null +++ b/3rdparty/asio/include/asio/traits/prefer_free.hpp @@ -0,0 +1,104 @@ +// +// traits/prefer_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_PREFER_FREE_HPP +#define ASIO_TRAITS_PREFER_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct prefer_free_default; + +template <typename T, typename Property, typename = void> +struct prefer_free; + +} // namespace traits +namespace detail { + +struct no_prefer_free +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct prefer_free_trait : no_prefer_free +{ +}; + +template <typename T, typename Property> +struct prefer_free_trait<T, Property, + void_t< + decltype(prefer(declval<T>(), declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + prefer(declval<T>(), declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(prefer(declval<T>(), declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct prefer_free_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_prefer_free, + traits::prefer_free< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct prefer_free_default : + detail::prefer_free_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct prefer_free : + prefer_free_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_PREFER_FREE_HPP diff --git a/3rdparty/asio/include/asio/traits/prefer_member.hpp b/3rdparty/asio/include/asio/traits/prefer_member.hpp new file mode 100644 index 00000000000..278c25c9964 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/prefer_member.hpp @@ -0,0 +1,104 @@ +// +// traits/prefer_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_PREFER_MEMBER_HPP +#define ASIO_TRAITS_PREFER_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct prefer_member_default; + +template <typename T, typename Property, typename = void> +struct prefer_member; + +} // namespace traits +namespace detail { + +struct no_prefer_member +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct prefer_member_trait : no_prefer_member +{ +}; + +template <typename T, typename Property> +struct prefer_member_trait<T, Property, + void_t< + decltype(declval<T>().prefer(declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + declval<T>().prefer(declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(declval<T>().prefer(declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct prefer_member_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_prefer_member, + traits::prefer_member< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct prefer_member_default : + detail::prefer_member_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct prefer_member : + prefer_member_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_PREFER_MEMBER_HPP diff --git a/3rdparty/asio/include/asio/traits/query_free.hpp b/3rdparty/asio/include/asio/traits/query_free.hpp new file mode 100644 index 00000000000..a54016adddc --- /dev/null +++ b/3rdparty/asio/include/asio/traits/query_free.hpp @@ -0,0 +1,104 @@ +// +// traits/query_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_QUERY_FREE_HPP +#define ASIO_TRAITS_QUERY_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct query_free_default; + +template <typename T, typename Property, typename = void> +struct query_free; + +} // namespace traits +namespace detail { + +struct no_query_free +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct query_free_trait : no_query_free +{ +}; + +template <typename T, typename Property> +struct query_free_trait<T, Property, + void_t< + decltype(query(declval<T>(), declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + query(declval<T>(), declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(query(declval<T>(), declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct query_free_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_query_free, + traits::query_free< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct query_free_default : + detail::query_free_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct query_free : + query_free_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_QUERY_FREE_HPP diff --git a/3rdparty/asio/include/asio/traits/query_member.hpp b/3rdparty/asio/include/asio/traits/query_member.hpp new file mode 100644 index 00000000000..2202c9dab4b --- /dev/null +++ b/3rdparty/asio/include/asio/traits/query_member.hpp @@ -0,0 +1,104 @@ +// +// traits/query_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_QUERY_MEMBER_HPP +#define ASIO_TRAITS_QUERY_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct query_member_default; + +template <typename T, typename Property, typename = void> +struct query_member; + +} // namespace traits +namespace detail { + +struct no_query_member +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct query_member_trait : no_query_member +{ +}; + +template <typename T, typename Property> +struct query_member_trait<T, Property, + void_t< + decltype(declval<T>().query(declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + declval<T>().query(declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(declval<T>().query(declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct query_member_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_query_member, + traits::query_member< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct query_member_default : + detail::query_member_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct query_member : + query_member_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_QUERY_MEMBER_HPP diff --git a/3rdparty/asio/include/asio/traits/query_static_constexpr_member.hpp b/3rdparty/asio/include/asio/traits/query_static_constexpr_member.hpp new file mode 100644 index 00000000000..95bdb7db376 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/query_static_constexpr_member.hpp @@ -0,0 +1,101 @@ +// +// traits/query_static_constexpr_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP +#define ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) \ + && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT 1 +#endif // defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct query_static_constexpr_member_default; + +template <typename T, typename Property, typename = void> +struct query_static_constexpr_member; + +} // namespace traits +namespace detail { + +struct no_query_static_constexpr_member +{ + static constexpr bool is_valid = false; +}; + +template <typename T, typename Property, typename = void> +struct query_static_constexpr_member_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_query_static_constexpr_member, + traits::query_static_constexpr_member< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template <typename T, typename Property> +struct query_static_constexpr_member_trait<T, Property, + enable_if_t< + (static_cast<void>(T::query(Property{})), true) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype(T::query(Property{})); + + static constexpr bool is_noexcept = noexcept(T::query(Property{})); + + static constexpr result_type value() noexcept(is_noexcept) + { + return T::query(Property{}); + } +}; + +#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct query_static_constexpr_member_default : + detail::query_static_constexpr_member_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct query_static_constexpr_member : + query_static_constexpr_member_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP diff --git a/3rdparty/asio/include/asio/traits/require_concept_free.hpp b/3rdparty/asio/include/asio/traits/require_concept_free.hpp new file mode 100644 index 00000000000..1ae2ad7801d --- /dev/null +++ b/3rdparty/asio/include/asio/traits/require_concept_free.hpp @@ -0,0 +1,104 @@ +// +// traits/require_concept_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_REQUIRE_CONCEPT_FREE_HPP +#define ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct require_concept_free_default; + +template <typename T, typename Property, typename = void> +struct require_concept_free; + +} // namespace traits +namespace detail { + +struct no_require_concept_free +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_concept_free_trait : no_require_concept_free +{ +}; + +template <typename T, typename Property> +struct require_concept_free_trait<T, Property, + void_t< + decltype(require_concept(declval<T>(), declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + require_concept(declval<T>(), declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(require_concept(declval<T>(), declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_concept_free_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_require_concept_free, + traits::require_concept_free< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct require_concept_free_default : + detail::require_concept_free_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct require_concept_free : + require_concept_free_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP diff --git a/3rdparty/asio/include/asio/traits/require_concept_member.hpp b/3rdparty/asio/include/asio/traits/require_concept_member.hpp new file mode 100644 index 00000000000..f6b6535e9bd --- /dev/null +++ b/3rdparty/asio/include/asio/traits/require_concept_member.hpp @@ -0,0 +1,104 @@ +// +// traits/require_concept_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP +#define ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct require_concept_member_default; + +template <typename T, typename Property, typename = void> +struct require_concept_member; + +} // namespace traits +namespace detail { + +struct no_require_concept_member +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_concept_member_trait : no_require_concept_member +{ +}; + +template <typename T, typename Property> +struct require_concept_member_trait<T, Property, + void_t< + decltype(declval<T>().require_concept(declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + declval<T>().require_concept(declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(declval<T>().require_concept(declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_concept_member_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_require_concept_member, + traits::require_concept_member< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct require_concept_member_default : + detail::require_concept_member_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct require_concept_member : + require_concept_member_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP diff --git a/3rdparty/asio/include/asio/traits/require_free.hpp b/3rdparty/asio/include/asio/traits/require_free.hpp new file mode 100644 index 00000000000..02b558676b1 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/require_free.hpp @@ -0,0 +1,104 @@ +// +// traits/require_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_REQUIRE_FREE_HPP +#define ASIO_TRAITS_REQUIRE_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct require_free_default; + +template <typename T, typename Property, typename = void> +struct require_free; + +} // namespace traits +namespace detail { + +struct no_require_free +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_free_trait : no_require_free +{ +}; + +template <typename T, typename Property> +struct require_free_trait<T, Property, + void_t< + decltype(require(declval<T>(), declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + require(declval<T>(), declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(require(declval<T>(), declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_free_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_require_free, + traits::require_free< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct require_free_default : + detail::require_free_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct require_free : + require_free_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_REQUIRE_FREE_HPP diff --git a/3rdparty/asio/include/asio/traits/require_member.hpp b/3rdparty/asio/include/asio/traits/require_member.hpp new file mode 100644 index 00000000000..af733e3b270 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/require_member.hpp @@ -0,0 +1,104 @@ +// +// traits/require_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_REQUIRE_MEMBER_HPP +#define ASIO_TRAITS_REQUIRE_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT 1 +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct require_member_default; + +template <typename T, typename Property, typename = void> +struct require_member; + +} // namespace traits +namespace detail { + +struct no_require_member +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +#if defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_member_trait : no_require_member +{ +}; + +template <typename T, typename Property> +struct require_member_trait<T, Property, + void_t< + decltype(declval<T>().require(declval<Property>())) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + declval<T>().require(declval<Property>())); + + static constexpr bool is_noexcept = + noexcept(declval<T>().require(declval<Property>())); +}; + +#else // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template <typename T, typename Property, typename = void> +struct require_member_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_require_member, + traits::require_member< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct require_member_default : + detail::require_member_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct require_member : + require_member_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_REQUIRE_MEMBER_HPP diff --git a/3rdparty/asio/include/asio/traits/static_query.hpp b/3rdparty/asio/include/asio/traits/static_query.hpp new file mode 100644 index 00000000000..b177a9d5304 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/static_query.hpp @@ -0,0 +1,102 @@ +// +// traits/static_query.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_STATIC_QUERY_HPP +#define ASIO_TRAITS_STATIC_QUERY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" + +#if defined(ASIO_HAS_VARIABLE_TEMPLATES) \ + && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT 1 +#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES) + // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct static_query_default; + +template <typename T, typename Property, typename = void> +struct static_query; + +} // namespace traits +namespace detail { + +struct no_static_query +{ + static constexpr bool is_valid = false; + static constexpr bool is_noexcept = false; +}; + +template <typename T, typename Property, typename = void> +struct static_query_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_static_query, + traits::static_query< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + +template <typename T, typename Property> +struct static_query_trait<T, Property, + void_t< + decltype(decay_t<Property>::template static_query_v<T>) + >> +{ + static constexpr bool is_valid = true; + + using result_type = decltype( + decay_t<Property>::template static_query_v<T>); + + static constexpr bool is_noexcept = + noexcept(decay_t<Property>::template static_query_v<T>); + + static constexpr result_type value() noexcept(is_noexcept) + { + return decay_t<Property>::template static_query_v<T>; + } +}; + +#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct static_query_default : detail::static_query_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct static_query : static_query_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_STATIC_QUERY_HPP diff --git a/3rdparty/asio/include/asio/traits/static_require.hpp b/3rdparty/asio/include/asio/traits/static_require.hpp new file mode 100644 index 00000000000..4ef4a617390 --- /dev/null +++ b/3rdparty/asio/include/asio/traits/static_require.hpp @@ -0,0 +1,115 @@ +// +// traits/static_require.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_STATIC_REQUIRE_HPP +#define ASIO_TRAITS_STATIC_REQUIRE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/traits/static_query.hpp" + +#define ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT 1 + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct static_require_default; + +template <typename T, typename Property, typename = void> +struct static_require; + +} // namespace traits +namespace detail { + +struct no_static_require +{ + static constexpr bool is_valid = false; +}; + +template <typename T, typename Property, typename = void> +struct static_require_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_static_require, + traits::static_require< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +template <typename T, typename Property> +struct static_require_trait<T, Property, + enable_if_t< + decay_t<Property>::value() == traits::static_query<T, Property>::value() + >> +{ + static constexpr bool is_valid = true; +}; + +#else // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +false_type static_require_test(...); + +template <typename T, typename Property> +true_type static_require_test(T*, Property*, + enable_if_t< + Property::value() == traits::static_query<T, Property>::value() + >* = 0); + +template <typename T, typename Property> +struct has_static_require +{ + static constexpr bool value = + decltype((static_require_test)( + static_cast<T*>(0), static_cast<Property*>(0)))::value; +}; + +template <typename T, typename Property> +struct static_require_trait<T, Property, + enable_if_t< + has_static_require<decay_t<T>, + decay_t<Property>>::value + >> +{ + static constexpr bool is_valid = true; +}; + +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct static_require_default : detail::static_require_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct static_require : static_require_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_STATIC_REQUIRE_HPP diff --git a/3rdparty/asio/include/asio/traits/static_require_concept.hpp b/3rdparty/asio/include/asio/traits/static_require_concept.hpp new file mode 100644 index 00000000000..6861f46aa0d --- /dev/null +++ b/3rdparty/asio/include/asio/traits/static_require_concept.hpp @@ -0,0 +1,116 @@ +// +// traits/static_require_concept.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_TRAITS_STATIC_REQUIRE_CONCEPT_HPP +#define ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/traits/static_query.hpp" + +#define ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT 1 + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace traits { + +template <typename T, typename Property, typename = void> +struct static_require_concept_default; + +template <typename T, typename Property, typename = void> +struct static_require_concept; + +} // namespace traits +namespace detail { + +struct no_static_require_concept +{ + static constexpr bool is_valid = false; +}; + +template <typename T, typename Property, typename = void> +struct static_require_concept_trait : + conditional_t< + is_same<T, decay_t<T>>::value + && is_same<Property, decay_t<Property>>::value, + no_static_require_concept, + traits::static_require_concept< + decay_t<T>, + decay_t<Property>> + > +{ +}; + +#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +template <typename T, typename Property> +struct static_require_concept_trait<T, Property, + enable_if_t< + decay_t<Property>::value() == traits::static_query<T, Property>::value() + >> +{ + static constexpr bool is_valid = true; +}; + +#else // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +false_type static_require_concept_test(...); + +template <typename T, typename Property> +true_type static_require_concept_test(T*, Property*, + enable_if_t< + Property::value() == traits::static_query<T, Property>::value() + >* = 0); + +template <typename T, typename Property> +struct has_static_require_concept +{ + static constexpr bool value = + decltype((static_require_concept_test)( + static_cast<T*>(0), static_cast<Property*>(0)))::value; +}; + +template <typename T, typename Property> +struct static_require_concept_trait<T, Property, + enable_if_t< + has_static_require_concept<decay_t<T>, + decay_t<Property>>::value + >> +{ + static constexpr bool is_valid = true; +}; + +#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +} // namespace detail +namespace traits { + +template <typename T, typename Property, typename> +struct static_require_concept_default : + detail::static_require_concept_trait<T, Property> +{ +}; + +template <typename T, typename Property, typename> +struct static_require_concept : static_require_concept_default<T, Property> +{ +}; + +} // namespace traits +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP diff --git a/3rdparty/asio/include/asio/ts/buffer.hpp b/3rdparty/asio/include/asio/ts/buffer.hpp index 257de209ce8..6c74a50ca66 100644 --- a/3rdparty/asio/include/asio/ts/buffer.hpp +++ b/3rdparty/asio/include/asio/ts/buffer.hpp @@ -2,7 +2,7 @@ // ts/buffer.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ts/executor.hpp b/3rdparty/asio/include/asio/ts/executor.hpp index d67c72e5201..df28bbf44bb 100644 --- a/3rdparty/asio/include/asio/ts/executor.hpp +++ b/3rdparty/asio/include/asio/ts/executor.hpp @@ -2,7 +2,7 @@ // ts/executor.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,7 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/handler_type.hpp" #include "asio/async_result.hpp" #include "asio/associated_allocator.hpp" #include "asio/execution_context.hpp" @@ -25,6 +24,7 @@ #include "asio/executor_work_guard.hpp" #include "asio/system_executor.hpp" #include "asio/executor.hpp" +#include "asio/any_io_executor.hpp" #include "asio/dispatch.hpp" #include "asio/post.hpp" #include "asio/defer.hpp" diff --git a/3rdparty/asio/include/asio/ts/internet.hpp b/3rdparty/asio/include/asio/ts/internet.hpp index 39e5b851935..eb2c35cd628 100644 --- a/3rdparty/asio/include/asio/ts/internet.hpp +++ b/3rdparty/asio/include/asio/ts/internet.hpp @@ -2,7 +2,7 @@ // ts/internet.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ts/io_context.hpp b/3rdparty/asio/include/asio/ts/io_context.hpp index fc7e8f82881..c688f160e7a 100644 --- a/3rdparty/asio/include/asio/ts/io_context.hpp +++ b/3rdparty/asio/include/asio/ts/io_context.hpp @@ -2,7 +2,7 @@ // ts/io_context.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ts/net.hpp b/3rdparty/asio/include/asio/ts/net.hpp index 5af4c6f8cd0..f82113b930a 100644 --- a/3rdparty/asio/include/asio/ts/net.hpp +++ b/3rdparty/asio/include/asio/ts/net.hpp @@ -2,7 +2,7 @@ // ts/net.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ts/netfwd.hpp b/3rdparty/asio/include/asio/ts/netfwd.hpp index 59029218e19..a575b6e497a 100644 --- a/3rdparty/asio/include/asio/ts/netfwd.hpp +++ b/3rdparty/asio/include/asio/ts/netfwd.hpp @@ -2,7 +2,7 @@ // ts/netfwd.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,15 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_HAS_CHRONO) -# include "asio/detail/chrono.hpp" -#endif // defined(ASIO_HAS_CHRONO) +#include "asio/detail/chrono.hpp" #if defined(ASIO_HAS_BOOST_DATE_TIME) # include "asio/detail/date_time_fwd.hpp" #endif // defined(ASIO_HAS_BOOST_DATE_TIME) +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +#include "asio/execution/blocking.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/execution/relationship.hpp" +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + #if !defined(GENERATING_DOCUMENTATION) #include "asio/detail/push_options.hpp" @@ -36,13 +39,47 @@ class execution_context; template <typename T, typename Executor> class executor_binder; -template <typename Executor> +#if !defined(ASIO_EXECUTOR_WORK_GUARD_DECL) +#define ASIO_EXECUTOR_WORK_GUARD_DECL + +template <typename Executor, typename = void, typename = void> class executor_work_guard; -class system_executor; +#endif // !defined(ASIO_EXECUTOR_WORK_GUARD_DECL) + +template <typename Blocking, typename Relationship, typename Allocator> +class basic_system_executor; + +#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) class executor; +typedef executor any_io_executor; + +#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +namespace execution { + +#if !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) +#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL + +template <typename... SupportableProperties> +class any_executor; + +#endif // !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) + +template <typename U> +struct context_as_t; + +template <typename Property> +struct prefer_only; + +} // namespace execution + +class any_io_executor; + +#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + template <typename Executor> class strand; @@ -58,32 +95,16 @@ struct time_traits; #endif // defined(ASIO_HAS_BOOST_DATE_TIME) -#if defined(ASIO_ENABLE_OLD_SERVICES) - -template <typename Clock, typename WaitTraits> -class waitable_timer_service; - -#if defined(ASIO_HAS_BOOST_DATE_TIME) - -template <typename TimeType, typename TimeTraits> -class deadline_timer_service; - -#endif // defined(ASIO_HAS_BOOST_DATE_TIME) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) #define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL template <typename Clock, - typename WaitTraits = asio::wait_traits<Clock> - ASIO_SVC_TPARAM_DEF2(= waitable_timer_service<Clock, WaitTraits>)> + typename WaitTraits = wait_traits<Clock>, + typename Executor = any_io_executor> class basic_waitable_timer; #endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) -#if defined(ASIO_HAS_CHRONO) - typedef basic_waitable_timer<chrono::system_clock> system_timer; typedef basic_waitable_timer<chrono::steady_clock> steady_timer; @@ -91,35 +112,51 @@ typedef basic_waitable_timer<chrono::steady_clock> steady_timer; typedef basic_waitable_timer<chrono::high_resolution_clock> high_resolution_timer; -#endif // defined(ASIO_HAS_CHRONO) +#if !defined(ASIO_BASIC_SOCKET_FWD_DECL) +#define ASIO_BASIC_SOCKET_FWD_DECL -template <class Protocol ASIO_SVC_TPARAM> +template <typename Protocol, typename Executor = any_io_executor> class basic_socket; -template <typename Protocol ASIO_SVC_TPARAM> +#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL) + +#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) +#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL + +template <typename Protocol, typename Executor = any_io_executor> class basic_datagram_socket; -template <typename Protocol ASIO_SVC_TPARAM> +#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) + +#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL) +#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> class basic_stream_socket; -template <typename Protocol ASIO_SVC_TPARAM> +#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL) + +#if !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) +#define ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL + +template <typename Protocol, typename Executor = any_io_executor> class basic_socket_acceptor; +#endif // !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) + #if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) #define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL // Forward declaration with defaulted arguments. -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), +template <typename Protocol, #if defined(ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) typename Clock = boost::posix_time::ptime, - typename WaitTraits = time_traits<Clock> - ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> + typename WaitTraits = time_traits<Clock>> #else typename Clock = chrono::steady_clock, - typename WaitTraits = wait_traits<Clock> - ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> + typename WaitTraits = wait_traits<Clock>> #endif class basic_socket_streambuf; @@ -129,17 +166,14 @@ class basic_socket_streambuf; #define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL // Forward declaration with defaulted arguments. -template <typename Protocol - ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), +template <typename Protocol, #if defined(ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) typename Clock = boost::posix_time::ptime, - typename WaitTraits = time_traits<Clock> - ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> + typename WaitTraits = time_traits<Clock>> #else typename Clock = chrono::steady_clock, - typename WaitTraits = wait_traits<Clock> - ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> + typename WaitTraits = wait_traits<Clock>> #endif class basic_socket_iostream; @@ -180,9 +214,14 @@ class basic_resolver_entry; template <typename InternetProtocol> class basic_resolver_results; -template <typename InternetProtocol ASIO_SVC_TPARAM> +#if !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL) +#define ASIO_IP_BASIC_RESOLVER_FWD_DECL + +template <typename InternetProtocol, typename Executor = any_io_executor> class basic_resolver; +#endif // !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL) + class tcp; class udp; diff --git a/3rdparty/asio/include/asio/ts/socket.hpp b/3rdparty/asio/include/asio/ts/socket.hpp index ecc4a2e3472..d54e0778264 100644 --- a/3rdparty/asio/include/asio/ts/socket.hpp +++ b/3rdparty/asio/include/asio/ts/socket.hpp @@ -2,7 +2,7 @@ // ts/socket.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/ts/timer.hpp b/3rdparty/asio/include/asio/ts/timer.hpp index a47d6565d53..3b3d6facf11 100644 --- a/3rdparty/asio/include/asio/ts/timer.hpp +++ b/3rdparty/asio/include/asio/ts/timer.hpp @@ -2,7 +2,7 @@ // ts/timer.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -15,7 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include <chrono> +#include "asio/detail/chrono.hpp" #include "asio/wait_traits.hpp" #include "asio/basic_waitable_timer.hpp" diff --git a/3rdparty/asio/include/asio/unyield.hpp b/3rdparty/asio/include/asio/unyield.hpp index ccbb043547e..f843d6137a2 100644 --- a/3rdparty/asio/include/asio/unyield.hpp +++ b/3rdparty/asio/include/asio/unyield.hpp @@ -2,7 +2,7 @@ // unyield.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/use_awaitable.hpp b/3rdparty/asio/include/asio/use_awaitable.hpp new file mode 100644 index 00000000000..6dd42f3d6e3 --- /dev/null +++ b/3rdparty/asio/include/asio/use_awaitable.hpp @@ -0,0 +1,161 @@ +// +// use_awaitable.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_USE_AWAITABLE_HPP +#define ASIO_USE_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#include "asio/awaitable.hpp" +#include "asio/detail/handler_tracking.hpp" + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) +# include "asio/detail/source_location.hpp" +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// A @ref completion_token that represents the currently executing coroutine. +/** + * The @c use_awaitable_t class, with its value @c use_awaitable, is used to + * represent the currently executing coroutine. This completion token may be + * passed as a handler to an asynchronous operation. For example: + * + * @code awaitable<void> my_coroutine() + * { + * std::size_t n = co_await my_socket.async_read_some(buffer, use_awaitable); + * ... + * } @endcode + * + * When used with co_await, the initiating function (@c async_read_some in the + * above example) suspends the current coroutine. The coroutine is resumed when + * the asynchronous operation completes, and the result of the operation is + * returned. + */ +template <typename Executor = any_io_executor> +struct use_awaitable_t +{ + /// Default constructor. + constexpr use_awaitable_t( +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + detail::source_location location = detail::source_location::current() +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + ) +#if defined(ASIO_ENABLE_HANDLER_TRACKING) +# if defined(ASIO_HAS_SOURCE_LOCATION) + : file_name_(location.file_name()), + line_(location.line()), + function_name_(location.function_name()) +# else // defined(ASIO_HAS_SOURCE_LOCATION) + : file_name_(0), + line_(0), + function_name_(0) +# endif // defined(ASIO_HAS_SOURCE_LOCATION) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + { + } + + /// Constructor used to specify file name, line, and function name. + constexpr use_awaitable_t(const char* file_name, + int line, const char* function_name) +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + : file_name_(file_name), + line_(line), + function_name_(function_name) +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) + { +#if !defined(ASIO_ENABLE_HANDLER_TRACKING) + (void)file_name; + (void)line; + (void)function_name; +#endif // !defined(ASIO_ENABLE_HANDLER_TRACKING) + } + + /// Adapts an executor to add the @c use_awaitable_t completion token as the + /// default. + template <typename InnerExecutor> + struct executor_with_default : InnerExecutor + { + /// Specify @c use_awaitable_t as the default completion token type. + typedef use_awaitable_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + template <typename InnerExecutor1> + executor_with_default(const InnerExecutor1& ex, + constraint_t< + conditional_t< + !is_same<InnerExecutor1, executor_with_default>::value, + is_convertible<InnerExecutor1, InnerExecutor>, + false_type + >::value + > = 0) noexcept + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c use_awaitable_t as its + /// default completion token type. + template <typename T> + using as_default_on_t = typename T::template rebind_executor< + executor_with_default<typename T::executor_type>>::other; + + /// Function helper to adapt an I/O object to use @c use_awaitable_t as its + /// default completion token type. + template <typename T> + static typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other + as_default_on(T&& object) + { + return typename decay_t<T>::template rebind_executor< + executor_with_default<typename decay_t<T>::executor_type> + >::other(static_cast<T&&>(object)); + } + +#if defined(ASIO_ENABLE_HANDLER_TRACKING) + const char* file_name_; + int line_; + const char* function_name_; +#endif // defined(ASIO_ENABLE_HANDLER_TRACKING) +}; + +/// A @ref completion_token object that represents the currently executing +/// coroutine. +/** + * See the documentation for asio::use_awaitable_t for a usage example. + */ +#if defined(GENERATING_DOCUMENTATION) +constexpr use_awaitable_t<> use_awaitable; +#else +constexpr use_awaitable_t<> use_awaitable(0, 0, 0); +#endif + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#include "asio/impl/use_awaitable.hpp" + +#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_USE_AWAITABLE_HPP diff --git a/3rdparty/asio/include/asio/use_future.hpp b/3rdparty/asio/include/asio/use_future.hpp index 2a0e24ff94d..26f5ae1fed0 100644 --- a/3rdparty/asio/include/asio/use_future.hpp +++ b/3rdparty/asio/include/asio/use_future.hpp @@ -2,7 +2,7 @@ // use_future.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,8 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" +#include "asio/detail/future.hpp" -#if defined(ASIO_HAS_STD_FUTURE) \ +#if defined(ASIO_HAS_STD_FUTURE_CLASS) \ || defined(GENERATING_DOCUMENTATION) #include <memory> @@ -36,12 +37,14 @@ class packaged_handler; } // namespace detail -/// Class used to specify that an asynchronous operation should return a future. +/// A @ref completion_token type that causes an asynchronous operation to return +/// a future. /** - * The use_future_t class is used to indicate that an asynchronous operation - * should return a std::future object. A use_future_t object may be passed as a - * handler to an asynchronous operation, typically using the special value @c - * asio::use_future. For example: + * The use_future_t class is a completion token type that is used to indicate + * that an asynchronous operation should return a std::future object. A + * use_future_t object may be passed as a completion token to an asynchronous + * operation, typically using the special value @c asio::use_future. For + * example: * * @code std::future<std::size_t> my_future * = my_socket.async_read_some(my_buffer, asio::use_future); @endcode @@ -51,7 +54,7 @@ class packaged_handler; * completes with an error_code indicating failure, it is converted into a * system_error and passed back to the caller via the future. */ -template <typename Allocator = std::allocator<void> > +template <typename Allocator = std::allocator<void>> class use_future_t { public: @@ -60,7 +63,7 @@ public: typedef Allocator allocator_type; /// Construct using default-constructed allocator. - ASIO_CONSTEXPR use_future_t() + constexpr use_future_t() { } @@ -113,23 +116,36 @@ public: #if defined(GENERATING_DOCUMENTATION) unspecified #else // defined(GENERATING_DOCUMENTATION) - detail::packaged_token<typename decay<Function>::type, Allocator> + detail::packaged_token<decay_t<Function>, Allocator> #endif // defined(GENERATING_DOCUMENTATION) - operator()(ASIO_MOVE_ARG(Function) f) const; + operator()(Function&& f) const; private: - Allocator allocator_; + // Helper type to ensure that use_future can be constexpr default-constructed + // even when std::allocator<void> can't be. + struct std_allocator_void + { + constexpr std_allocator_void() + { + } + + operator std::allocator<void>() const + { + return std::allocator<void>(); + } + }; + + conditional_t< + is_same<std::allocator<void>, Allocator>::value, + std_allocator_void, Allocator> allocator_; }; -/// A special value, similar to std::nothrow. +/// A @ref completion_token object that causes an asynchronous operation to +/// return a future. /** * See the documentation for asio::use_future_t for a usage example. */ -#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr use_future_t<> use_future; -#elif defined(ASIO_MSVC) -__declspec(selectany) use_future_t<> use_future; -#endif } // namespace asio @@ -137,7 +153,7 @@ __declspec(selectany) use_future_t<> use_future; #include "asio/impl/use_future.hpp" -#endif // defined(ASIO_HAS_STD_FUTURE) +#endif // defined(ASIO_HAS_STD_FUTURE_CLASS) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_USE_FUTURE_HPP diff --git a/3rdparty/asio/include/asio/uses_executor.hpp b/3rdparty/asio/include/asio/uses_executor.hpp index 53b727275fb..ff475cad4a1 100644 --- a/3rdparty/asio/include/asio/uses_executor.hpp +++ b/3rdparty/asio/include/asio/uses_executor.hpp @@ -2,7 +2,7 @@ // uses_executor.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -34,7 +34,7 @@ namespace asio { struct executor_arg_t { /// Constructor. - ASIO_CONSTEXPR executor_arg_t() ASIO_NOEXCEPT + constexpr executor_arg_t() noexcept { } }; @@ -45,11 +45,7 @@ struct executor_arg_t * See asio::executor_arg_t and asio::uses_executor * for more information. */ -#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr executor_arg_t executor_arg; -#elif defined(ASIO_MSVC) -__declspec(selectany) executor_arg_t executor_arg; -#endif /// The uses_executor trait detects whether a type T has an associated executor /// that is convertible from type Executor. diff --git a/3rdparty/asio/include/asio/version.hpp b/3rdparty/asio/include/asio/version.hpp index 40b4e9aae97..c52fdd45b58 100644 --- a/3rdparty/asio/include/asio/version.hpp +++ b/3rdparty/asio/include/asio/version.hpp @@ -2,7 +2,7 @@ // version.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,6 +18,6 @@ // ASIO_VERSION % 100 is the sub-minor version // ASIO_VERSION / 100 % 1000 is the minor version // ASIO_VERSION / 100000 is the major version -#define ASIO_VERSION 101100 // 1.11.0 +#define ASIO_VERSION 103002 // 1.30.2 #endif // ASIO_VERSION_HPP diff --git a/3rdparty/asio/include/asio/wait_traits.hpp b/3rdparty/asio/include/asio/wait_traits.hpp index 0cc60985242..5f5e876da66 100644 --- a/3rdparty/asio/include/asio/wait_traits.hpp +++ b/3rdparty/asio/include/asio/wait_traits.hpp @@ -2,7 +2,7 @@ // wait_traits.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) diff --git a/3rdparty/asio/include/asio/waitable_timer_service.hpp b/3rdparty/asio/include/asio/waitable_timer_service.hpp deleted file mode 100644 index bcb228d2ebc..00000000000 --- a/3rdparty/asio/include/asio/waitable_timer_service.hpp +++ /dev/null @@ -1,210 +0,0 @@ -// -// waitable_timer_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_WAITABLE_TIMER_SERVICE_HPP -#define ASIO_WAITABLE_TIMER_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/chrono_time_traits.hpp" -#include "asio/detail/deadline_timer_service.hpp" -#include "asio/io_context.hpp" -#include "asio/wait_traits.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { - -/// Default service implementation for a timer. -template <typename Clock, - typename WaitTraits = asio::wait_traits<Clock> > -class waitable_timer_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base< - waitable_timer_service<Clock, WaitTraits> > -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - - /// The clock type. - typedef Clock clock_type; - - /// The duration type of the clock. - typedef typename clock_type::duration duration; - - /// The time point type of the clock. - typedef typename clock_type::time_point time_point; - - /// The wait traits type. - typedef WaitTraits traits_type; - -private: - // The type of the platform-specific implementation. - typedef detail::deadline_timer_service< - detail::chrono_time_traits<Clock, WaitTraits> > service_impl_type; - -public: - /// The implementation type of the waitable timer. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef typename service_impl_type::implementation_type implementation_type; -#endif - - /// Construct a new timer service for the specified io_context. - explicit waitable_timer_service(asio::io_context& io_context) - : asio::detail::service_base< - waitable_timer_service<Clock, WaitTraits> >(io_context), - service_impl_(io_context) - { - } - - /// Construct a new timer implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - - /// Destroy a timer implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new timer implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another timer implementation. - void move_assign(implementation_type& impl, - waitable_timer_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Cancel any asynchronous wait operations associated with the timer. - std::size_t cancel(implementation_type& impl, asio::error_code& ec) - { - return service_impl_.cancel(impl, ec); - } - - /// Cancels one asynchronous wait operation associated with the timer. - std::size_t cancel_one(implementation_type& impl, - asio::error_code& ec) - { - return service_impl_.cancel_one(impl, ec); - } - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use expiry().) Get the expiry time for the timer as an - /// absolute time. - time_point expires_at(const implementation_type& impl) const - { - return service_impl_.expiry(impl); - } -#endif // !defined(ASIO_NO_DEPRECATED) - - /// Get the expiry time for the timer as an absolute time. - time_point expiry(const implementation_type& impl) const - { - return service_impl_.expiry(impl); - } - - /// Set the expiry time for the timer as an absolute time. - std::size_t expires_at(implementation_type& impl, - const time_point& expiry_time, asio::error_code& ec) - { - return service_impl_.expires_at(impl, expiry_time, ec); - } - - /// Set the expiry time for the timer relative to now. - std::size_t expires_after(implementation_type& impl, - const duration& expiry_time, asio::error_code& ec) - { - return service_impl_.expires_after(impl, expiry_time, ec); - } - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use expiry().) Get the expiry time for the timer relative to - /// now. - duration expires_from_now(const implementation_type& impl) const - { - typedef detail::chrono_time_traits<Clock, WaitTraits> traits; - return traits::subtract(service_impl_.expiry(impl), traits::now()); - } - - /// (Deprecated: Use expires_after().) Set the expiry time for the timer - /// relative to now. - std::size_t expires_from_now(implementation_type& impl, - const duration& expiry_time, asio::error_code& ec) - { - return service_impl_.expires_after(impl, expiry_time, ec); - } -#endif // !defined(ASIO_NO_DEPRECATED) - - // Perform a blocking wait on the timer. - void wait(implementation_type& impl, asio::error_code& ec) - { - service_impl_.wait(impl, ec); - } - - // Start an asynchronous wait on the timer. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, - ASIO_MOVE_ARG(WaitHandler) handler) - { - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_WAITABLE_TIMER_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/windows/basic_handle.hpp b/3rdparty/asio/include/asio/windows/basic_handle.hpp deleted file mode 100644 index 3b1ce2cc2db..00000000000 --- a/3rdparty/asio/include/asio/windows/basic_handle.hpp +++ /dev/null @@ -1,273 +0,0 @@ -// -// windows/basic_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_WINDOWS_BASIC_HANDLE_HPP -#define ASIO_WINDOWS_BASIC_HANDLE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ - || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ - || defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) - -#include "asio/basic_io_object.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/error.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace windows { - -/// Provides Windows handle functionality. -/** - * The windows::basic_handle class template provides the ability to wrap a - * Windows handle. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - */ -template <typename HandleService> -class basic_handle - : public basic_io_object<HandleService> -{ -public: - /// The native representation of a handle. - typedef typename HandleService::native_handle_type native_handle_type; - - /// A basic_handle is always the lowest layer. - typedef basic_handle<HandleService> lowest_layer_type; - - /// Construct a basic_handle without opening it. - /** - * This constructor creates a handle without opening it. - * - * @param io_context The io_context object that the handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - */ - explicit basic_handle(asio::io_context& io_context) - : basic_io_object<HandleService>(io_context) - { - } - - /// Construct a basic_handle on an existing native handle. - /** - * This constructor creates a handle object to hold an existing native handle. - * - * @param io_context The io_context object that the handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - * - * @param handle A native handle. - * - * @throws asio::system_error Thrown on failure. - */ - basic_handle(asio::io_context& io_context, - const native_handle_type& handle) - : basic_io_object<HandleService>(io_context) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), handle, ec); - asio::detail::throw_error(ec, "assign"); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a basic_handle from another. - /** - * This constructor moves a handle from one object to another. - * - * @param other The other basic_handle object from which the move will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_handle(io_context&) constructor. - */ - basic_handle(basic_handle&& other) - : basic_io_object<HandleService>( - ASIO_MOVE_CAST(basic_handle)(other)) - { - } - - /// Move-assign a basic_handle from another. - /** - * This assignment operator moves a handle from one object to another. - * - * @param other The other basic_handle object from which the move will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_handle(io_context&) constructor. - */ - basic_handle& operator=(basic_handle&& other) - { - basic_io_object<HandleService>::operator=( - ASIO_MOVE_CAST(basic_handle)(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Get a reference to the lowest layer. - /** - * This function returns a reference to the lowest layer in a stack of - * layers. Since a basic_handle cannot contain any further layers, it simply - * returns a reference to itself. - * - * @return A reference to the lowest layer in the stack of layers. Ownership - * is not transferred to the caller. - */ - lowest_layer_type& lowest_layer() - { - return *this; - } - - /// Get a const reference to the lowest layer. - /** - * This function returns a const reference to the lowest layer in a stack of - * layers. Since a basic_handle cannot contain any further layers, it simply - * returns a reference to itself. - * - * @return A const reference to the lowest layer in the stack of layers. - * Ownership is not transferred to the caller. - */ - const lowest_layer_type& lowest_layer() const - { - return *this; - } - - /// Assign an existing native handle to the handle. - /* - * This function opens the handle to hold an existing native handle. - * - * @param handle A native handle. - * - * @throws asio::system_error Thrown on failure. - */ - void assign(const native_handle_type& handle) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), handle, ec); - asio::detail::throw_error(ec, "assign"); - } - - /// Assign an existing native handle to the handle. - /* - * This function opens the handle to hold an existing native handle. - * - * @param handle A native handle. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, - asio::error_code& ec) - { - this->get_service().assign(this->get_implementation(), handle, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the handle is open. - bool is_open() const - { - return this->get_service().is_open(this->get_implementation()); - } - - /// Close the handle. - /** - * This function is used to close the handle. Any asynchronous read or write - * operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void close() - { - asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); - asio::detail::throw_error(ec, "close"); - } - - /// Close the handle. - /** - * This function is used to close the handle. Any asynchronous read or write - * operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID close(asio::error_code& ec) - { - this->get_service().close(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native handle representation. - /** - * This function may be used to obtain the underlying representation of the - * handle. This is intended to allow access to native handle functionality - * that is not otherwise provided. - */ - native_handle_type native_handle() - { - return this->get_service().native_handle(this->get_implementation()); - } - - /// Cancel all asynchronous operations associated with the handle. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void cancel() - { - asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); - asio::detail::throw_error(ec, "cancel"); - } - - /// Cancel all asynchronous operations associated with the handle. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) - { - this->get_service().cancel(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - -protected: - /// Protected destructor to prevent deletion through this type. - ~basic_handle() - { - } -}; - -} // namespace windows -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) - // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) - // || defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) - // || defined(GENERATING_DOCUMENTATION) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_WINDOWS_BASIC_HANDLE_HPP diff --git a/3rdparty/asio/include/asio/windows/basic_object_handle.hpp b/3rdparty/asio/include/asio/windows/basic_object_handle.hpp index d134dbfb1db..bb10efc2a0a 100644 --- a/3rdparty/asio/include/asio/windows/basic_object_handle.hpp +++ b/3rdparty/asio/include/asio/windows/basic_object_handle.hpp @@ -2,7 +2,7 @@ // windows/basic_object_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2011 Boris Schaeling (boris@highscore.de) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -18,15 +18,17 @@ #include "asio/detail/config.hpp" -#if defined(ASIO_ENABLE_OLD_SERVICES) - #if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/io_object_impl.hpp" #include "asio/detail/throw_error.hpp" +#include "asio/detail/win_object_handle_service.hpp" #include "asio/error.hpp" -#include "asio/windows/basic_handle.hpp" -#include "asio/windows/object_handle_service.hpp" +#include "asio/execution_context.hpp" #include "asio/detail/push_options.hpp" @@ -35,85 +37,338 @@ namespace windows { /// Provides object-oriented handle functionality. /** - * The windows::basic_object_handle class template provides asynchronous and - * blocking object-oriented handle functionality. + * The windows::basic_object_handle class provides asynchronous and blocking + * object-oriented handle functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename ObjectHandleService = object_handle_service> +template <typename Executor = any_io_executor> class basic_object_handle - : public basic_handle<ObjectHandleService> { +private: + class initiate_async_wait; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the handle type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_object_handle<Executor1> other; + }; + /// The native representation of a handle. - typedef typename ObjectHandleService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef asio::detail::win_object_handle_service::native_handle_type + native_handle_type; +#endif - /// Construct a basic_object_handle without opening it. + /// An object handle is always the lowest layer. + typedef basic_object_handle lowest_layer_type; + + /// Construct an object handle without opening it. /** * This constructor creates an object handle without opening it. * - * @param io_context The io_context object that the object handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. + * @param ex The I/O executor that the object handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * object handle. */ - explicit basic_object_handle(asio::io_context& io_context) - : basic_handle<ObjectHandleService>(io_context) + explicit basic_object_handle(const executor_type& ex) + : impl_(0, ex) { } - /// Construct a basic_object_handle on an existing native handle. + /// Construct an object handle without opening it. + /** + * This constructor creates an object handle without opening it. + * + * @param context An execution context which provides the I/O executor that + * the object handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the object handle. + */ + template <typename ExecutionContext> + explicit basic_object_handle(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct an object handle on an existing native handle. /** * This constructor creates an object handle object to hold an existing native * handle. * - * @param io_context The io_context object that the object handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. + * @param ex The I/O executor that the object handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * object handle. * * @param native_handle The new underlying handle implementation. * * @throws asio::system_error Thrown on failure. */ - basic_object_handle(asio::io_context& io_context, + basic_object_handle(const executor_type& ex, const native_handle_type& native_handle) - : basic_handle<ObjectHandleService>(io_context, native_handle) + : impl_(0, ex) { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + asio::detail::throw_error(ec, "assign"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a basic_object_handle from another. + /// Construct an object handle on an existing native handle. + /** + * This constructor creates an object handle object to hold an existing native + * handle. + * + * @param context An execution context which provides the I/O executor that + * the object handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the object handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_object_handle(ExecutionContext& context, + const native_handle_type& native_handle, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Move-construct an object handle from another. /** * This constructor moves an object handle from one object to another. * - * @param other The other basic_object_handle object from which the move will + * @param other The other object handle object from which the move will * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_object_handle(io_context&) constructor. + * constructed using the @c basic_object_handle(const executor_type&) + * constructor. */ basic_object_handle(basic_object_handle&& other) - : basic_handle<ObjectHandleService>( - ASIO_MOVE_CAST(basic_object_handle)(other)) + : impl_(std::move(other.impl_)) { } - /// Move-assign a basic_object_handle from another. + /// Move-assign an object handle from another. /** * This assignment operator moves an object handle from one object to another. * - * @param other The other basic_object_handle object from which the move will + * @param other The other object handle object from which the move will * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_object_handle(io_context&) constructor. + * constructed using the @c basic_object_handle(const executor_type&) + * constructor. */ basic_object_handle& operator=(basic_object_handle&& other) { - basic_handle<ObjectHandleService>::operator=( - ASIO_MOVE_CAST(basic_object_handle)(other)); + impl_ = std::move(other.impl_); + return *this; + } + + // All handles have access to each other's implementations. + template <typename Executor1> + friend class basic_object_handle; + + /// Move-construct an object handle from a handle of another executor type. + /** + * This constructor moves an object handle from one object to another. + * + * @param other The other object handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_object_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + basic_object_handle(basic_object_handle<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign an object handle from a handle of another executor type. + /** + * This assignment operator moves an object handle from one object to another. + * + * @param other The other object handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_object_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_object_handle& + > operator=(basic_object_handle<Executor1>&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since an object handle cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since an object handle cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const native_handle_type& handle) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, + asio::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the handle is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native handle representation. + /** + * This function may be used to obtain the underlying representation of the + * handle. This is intended to allow access to native handle functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } /// Perform a blocking wait on the object handle. /** @@ -126,7 +381,7 @@ public: void wait() { asio::error_code ec; - this->get_service().wait(this->get_implementation(), ec); + impl_.get_service().wait(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "wait"); } @@ -140,33 +395,83 @@ public: */ void wait(asio::error_code& ec) { - this->get_service().wait(this->get_implementation(), ec); + impl_.get_service().wait(impl_.get_implementation(), ec); } /// Start an asynchronous wait on the object handle. /** * This function is be used to initiate an asynchronous wait against the - * object handle. It always returns immediately. + * object handle. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * - * @param handler The handler to be called when the object handle is set to - * the signalled state. Copies will be made of the handler as required. The - * function signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the wait completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(ASIO_MOVE_ARG(WaitHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitToken = default_completion_token_t<executor_type>> + auto async_wait( + WaitToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WaitToken, void (asio::error_code)>( + declval<initiate_async_wait>(), token)) { - return this->get_service().async_wait(this->get_implementation(), - ASIO_MOVE_CAST(WaitHandler)(handler)); + return async_initiate<WaitToken, void (asio::error_code)>( + initiate_async_wait(this), token); } + +private: + // Disallow copying and assignment. + basic_object_handle(const basic_object_handle&) = delete; + basic_object_handle& operator=(const basic_object_handle&) = delete; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_object_handle* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue<WaitHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_object_handle* self_; + }; + + asio::detail::io_object_impl< + asio::detail::win_object_handle_service, Executor> impl_; }; } // namespace windows @@ -177,6 +482,4 @@ public: #endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP diff --git a/3rdparty/asio/include/asio/windows/basic_overlapped_handle.hpp b/3rdparty/asio/include/asio/windows/basic_overlapped_handle.hpp new file mode 100644 index 00000000000..8b8475b0006 --- /dev/null +++ b/3rdparty/asio/include/asio/windows/basic_overlapped_handle.hpp @@ -0,0 +1,455 @@ +// +// windows/basic_overlapped_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP +#define ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <cstddef> +#include <utility> +#include "asio/any_io_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/win_iocp_handle_service.hpp" +#include "asio/error.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace windows { + +/// Provides Windows handle functionality for objects that support +/// overlapped I/O. +/** + * The windows::overlapped_handle class provides the ability to wrap a Windows + * handle. The underlying object referred to by the handle must support + * overlapped I/O. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <typename Executor = any_io_executor> +class basic_overlapped_handle +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the handle type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_overlapped_handle<Executor1> other; + }; + + /// The native representation of a handle. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef asio::detail::win_iocp_handle_service::native_handle_type + native_handle_type; +#endif + + /// An overlapped_handle is always the lowest layer. + typedef basic_overlapped_handle lowest_layer_type; + + /// Construct an overlapped handle without opening it. + /** + * This constructor creates an overlapped handle without opening it. + * + * @param ex The I/O executor that the overlapped handle will use, by default, + * to dispatch handlers for any asynchronous operations performed on the + * overlapped handle. + */ + explicit basic_overlapped_handle(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct an overlapped handle without opening it. + /** + * This constructor creates an overlapped handle without opening it. + * + * @param context An execution context which provides the I/O executor that + * the overlapped handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the overlapped handle. + */ + template <typename ExecutionContext> + explicit basic_overlapped_handle(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) + { + } + + /// Construct an overlapped handle on an existing native handle. + /** + * This constructor creates an overlapped handle object to hold an existing + * native handle. + * + * @param ex The I/O executor that the overlapped handle will use, by default, + * to dispatch handlers for any asynchronous operations performed on the + * overlapped handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_overlapped_handle(const executor_type& ex, + const native_handle_type& native_handle) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct an overlapped handle on an existing native handle. + /** + * This constructor creates an overlapped handle object to hold an existing + * native handle. + * + * @param context An execution context which provides the I/O executor that + * the overlapped handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the overlapped handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_overlapped_handle(ExecutionContext& context, + const native_handle_type& native_handle, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Move-construct an overlapped handle from another. + /** + * This constructor moves a handle from one object to another. + * + * @param other The other overlapped handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(const executor_type&) + * constructor. + */ + basic_overlapped_handle(basic_overlapped_handle&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign an overlapped handle from another. + /** + * This assignment operator moves a handle from one object to another. + * + * @param other The other overlapped handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(const executor_type&) + * constructor. + */ + basic_overlapped_handle& operator=(basic_overlapped_handle&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All overlapped handles have access to each other's implementations. + template <typename Executor1> + friend class basic_overlapped_handle; + + /// Move-construct an overlapped handle from a handle of another executor + /// type. + /** + * This constructor moves a handle from one object to another. + * + * @param other The other overlapped handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + basic_overlapped_handle(basic_overlapped_handle<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign an overlapped handle from a handle of another executor type. + /** + * This assignment operator moves a handle from one object to another. + * + * @param other The other overlapped handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_overlapped_handle& + > operator=(basic_overlapped_handle<Executor1>&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + /// Get the executor associated with the object. + const executor_type& get_executor() noexcept + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since an overlapped_handle cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since an overlapped_handle cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const native_handle_type& handle) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, + asio::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the handle is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID close(asio::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native handle. + /** + * This function causes all outstanding asynchronous operations to finish + * immediately, and the handlers for cancelled operations will be passed the + * asio::error::operation_aborted error. Ownership of the native handle + * is then transferred to the caller. + * + * @throws asio::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + asio::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native handle. + /** + * This function causes all outstanding asynchronous operations to finish + * immediately, and the handlers for cancelled operations will be passed the + * asio::error::operation_aborted error. Ownership of the native handle + * is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with asio::error::operation_not_supported on + * these platforms. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(asio::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native handle representation. + /** + * This function may be used to obtain the underlying representation of the + * handle. This is intended to allow access to native handle functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + ASIO_SYNC_OP_VOID_RETURN(ec); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the handle, cancelling any outstanding asynchronous + * wait operations associated with the handle as if by calling @c cancel. + */ + ~basic_overlapped_handle() + { + } + + asio::detail::io_object_impl< + asio::detail::win_iocp_handle_service, Executor> impl_; + +private: + // Disallow copying and assignment. + basic_overlapped_handle(const basic_overlapped_handle&) = delete; + basic_overlapped_handle& operator=( + const basic_overlapped_handle&) = delete; +}; + +} // namespace windows +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP diff --git a/3rdparty/asio/include/asio/windows/basic_random_access_handle.hpp b/3rdparty/asio/include/asio/windows/basic_random_access_handle.hpp index 4e9ebe5b7dc..e66e943c6b5 100644 --- a/3rdparty/asio/include/asio/windows/basic_random_access_handle.hpp +++ b/3rdparty/asio/include/asio/windows/basic_random_access_handle.hpp @@ -2,7 +2,7 @@ // windows/basic_random_access_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,19 +16,11 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) +#include "asio/windows/basic_overlapped_handle.hpp" #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#include <cstddef> -#include "asio/detail/handler_type_requirements.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/error.hpp" -#include "asio/windows/basic_handle.hpp" -#include "asio/windows/random_access_handle_service.hpp" - #include "asio/detail/push_options.hpp" namespace asio { @@ -36,92 +28,194 @@ namespace windows { /// Provides random-access handle functionality. /** - * The windows::basic_random_access_handle class template provides asynchronous - * and blocking random-access handle functionality. + * The windows::basic_random_access_handle class provides asynchronous and + * blocking random-access handle functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename RandomAccessHandleService = random_access_handle_service> +template <typename Executor = any_io_executor> class basic_random_access_handle - : public basic_handle<RandomAccessHandleService> + : public basic_overlapped_handle<Executor> { +private: + class initiate_async_write_some_at; + class initiate_async_read_some_at; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the handle type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_random_access_handle<Executor1> other; + }; + /// The native representation of a handle. - typedef typename RandomAccessHandleService::native_handle_type +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef asio::detail::win_iocp_handle_service::native_handle_type native_handle_type; +#endif - /// Construct a basic_random_access_handle without opening it. + /// Construct a random-access handle without opening it. + /** + * This constructor creates a random-access handle without opening it. + * + * @param ex The I/O executor that the random-access handle will use, by + * default, to dispatch handlers for any asynchronous operations performed on + * the random-access handle. + */ + explicit basic_random_access_handle(const executor_type& ex) + : basic_overlapped_handle<Executor>(ex) + { + } + + /// Construct a random-access handle without opening it. /** * This constructor creates a random-access handle without opening it. The - * handle needs to be opened before data can be written to or read from it. + * handle needs to be opened or assigned before data can be written to or read + * from it. * - * @param io_context The io_context object that the random-access handle will - * use to dispatch handlers for any asynchronous operations performed on the - * handle. + * @param context An execution context which provides the I/O executor that + * the random-access handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the random-access handle. */ - explicit basic_random_access_handle(asio::io_context& io_context) - : basic_handle<RandomAccessHandleService>(io_context) + template <typename ExecutionContext> + explicit basic_random_access_handle(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_overlapped_handle<Executor>(context) { } - /// Construct a basic_random_access_handle on an existing native handle. + /// Construct a random-access handle on an existing native handle. /** * This constructor creates a random-access handle object to hold an existing * native handle. * - * @param io_context The io_context object that the random-access handle will - * use to dispatch handlers for any asynchronous operations performed on the - * handle. + * @param ex The I/O executor that the random-access handle will use, by + * default, to dispatch handlers for any asynchronous operations performed on + * the random-access handle. * * @param handle The new underlying handle implementation. * * @throws asio::system_error Thrown on failure. */ - basic_random_access_handle(asio::io_context& io_context, + basic_random_access_handle(const executor_type& ex, const native_handle_type& handle) - : basic_handle<RandomAccessHandleService>(io_context, handle) + : basic_overlapped_handle<Executor>(ex, handle) + { + } + + /// Construct a random-access handle on an existing native handle. + /** + * This constructor creates a random-access handle object to hold an existing + * native handle. + * + * @param context An execution context which provides the I/O executor that + * the random-access handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the random-access handle. + * + * @param handle The new underlying handle implementation. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_random_access_handle(ExecutionContext& context, + const native_handle_type& handle, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_overlapped_handle<Executor>(context, handle) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a basic_random_access_handle from another. + /// Move-construct a random-access handle from another. /** * This constructor moves a random-access handle from one object to another. * - * @param other The other basic_random_access_handle object from which the + * @param other The other random-access handle object from which the * move will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_random_access_handle(io_context&) + * constructed using the @c basic_random_access_handle(const executor_type&) * constructor. */ basic_random_access_handle(basic_random_access_handle&& other) - : basic_handle<RandomAccessHandleService>( - ASIO_MOVE_CAST(basic_random_access_handle)(other)) + : basic_overlapped_handle<Executor>(std::move(other)) { } - /// Move-assign a basic_random_access_handle from another. + /// Move-assign a random-access handle from another. /** * This assignment operator moves a random-access handle from one object to * another. * - * @param other The other basic_random_access_handle object from which the + * @param other The other random-access handle object from which the * move will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_random_access_handle(io_context&) + * constructed using the @c basic_random_access_handle(const executor_type&) * constructor. */ basic_random_access_handle& operator=(basic_random_access_handle&& other) { - basic_handle<RandomAccessHandleService>::operator=( - ASIO_MOVE_CAST(basic_random_access_handle)(other)); + basic_overlapped_handle<Executor>::operator=(std::move(other)); + return *this; + } + + /// Move-construct a random-access handle from a handle of another executor + /// type. + /** + * This constructor moves a random-access handle from one object to another. + * + * @param other The other random-access handle object from which the + * move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + basic_random_access_handle(basic_random_access_handle<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_overlapped_handle<Executor>(std::move(other)) + { + } + + /// Move-assign a random-access handle from a handle of another executor + /// type. + /** + * This assignment operator moves a random-access handle from one object to + * another. + * + * @param other The other random-access handle object from which the + * move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_random_access_handle& + > operator=(basic_random_access_handle<Executor1>&& other) + { + basic_overlapped_handle<Executor>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Write some data to the handle at the specified offset. /** @@ -157,8 +251,8 @@ public: const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().write_some_at( - this->get_implementation(), offset, buffers, ec); + std::size_t s = this->impl_.get_service().write_some_at( + this->impl_.get_implementation(), offset, buffers, ec); asio::detail::throw_error(ec, "write_some_at"); return s; } @@ -185,33 +279,39 @@ public: std::size_t write_some_at(uint64_t offset, const ConstBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().write_some_at( - this->get_implementation(), offset, buffers, ec); + return this->impl_.get_service().write_some_at( + this->impl_.get_implementation(), offset, buffers, ec); } /// Start an asynchronous write at the specified offset. /** * This function is used to asynchronously write data to the random-access - * handle. The function call always returns immediately. + * handle. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param offset The offset at which the data will be written. * * @param buffers One or more data buffers to be written to the handle. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write_at function if you need to ensure that @@ -225,20 +325,30 @@ public: * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some_at(uint64_t offset, - const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_write_some_at>(), token, offset, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - return this->get_service().async_write_some_at(this->get_implementation(), - offset, buffers, ASIO_MOVE_CAST(WriteHandler)(handler)); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some_at(this), token, offset, buffers); } /// Read some data from the handle at the specified offset. @@ -276,8 +386,8 @@ public: const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().read_some_at( - this->get_implementation(), offset, buffers, ec); + std::size_t s = this->impl_.get_service().read_some_at( + this->impl_.get_implementation(), offset, buffers, ec); asio::detail::throw_error(ec, "read_some_at"); return s; } @@ -305,33 +415,39 @@ public: std::size_t read_some_at(uint64_t offset, const MutableBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().read_some_at( - this->get_implementation(), offset, buffers, ec); + return this->impl_.get_service().read_some_at( + this->impl_.get_implementation(), offset, buffers, ec); } /// Start an asynchronous read at the specified offset. /** * This function is used to asynchronously read data from the random-access - * handle. The function call always returns immediately. + * handle. It is an initiating function for an @ref asynchronous_operation, + * and always returns immediately. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read_at function if you need to ensure that @@ -346,21 +462,98 @@ public: * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some_at(uint64_t offset, - const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some_at>(), token, offset, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - return this->get_service().async_read_some_at(this->get_implementation(), - offset, buffers, ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some_at(this), token, offset, buffers); } + +private: + class initiate_async_write_some_at + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some_at(basic_random_access_handle* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + uint64_t offset, const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_write_some_at( + self_->impl_.get_implementation(), offset, buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_random_access_handle* self_; + }; + + class initiate_async_read_some_at + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some_at(basic_random_access_handle* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + uint64_t offset, const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_read_some_at( + self_->impl_.get_implementation(), offset, buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_random_access_handle* self_; + }; }; } // namespace windows @@ -371,6 +564,4 @@ public: #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP diff --git a/3rdparty/asio/include/asio/windows/basic_stream_handle.hpp b/3rdparty/asio/include/asio/windows/basic_stream_handle.hpp index c0a11fcf1af..0331d9dfa03 100644 --- a/3rdparty/asio/include/asio/windows/basic_stream_handle.hpp +++ b/3rdparty/asio/include/asio/windows/basic_stream_handle.hpp @@ -2,7 +2,7 @@ // windows/basic_stream_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,19 +16,11 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) +#include "asio/windows/basic_overlapped_handle.hpp" #if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#include <cstddef> -#include "asio/detail/handler_type_requirements.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/error.hpp" -#include "asio/windows/basic_handle.hpp" -#include "asio/windows/stream_handle_service.hpp" - #include "asio/detail/push_options.hpp" namespace asio { @@ -36,8 +28,8 @@ namespace windows { /// Provides stream-oriented handle functionality. /** - * The windows::basic_stream_handle class template provides asynchronous and - * blocking stream-oriented handle functionality. + * The windows::basic_stream_handle class provides asynchronous and blocking + * stream-oriented handle functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n @@ -46,81 +38,182 @@ namespace windows { * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ -template <typename StreamHandleService = stream_handle_service> +template <typename Executor = any_io_executor> class basic_stream_handle - : public basic_handle<StreamHandleService> + : public basic_overlapped_handle<Executor> { +private: + class initiate_async_write_some; + class initiate_async_read_some; + public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the handle type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_stream_handle<Executor1> other; + }; + /// The native representation of a handle. - typedef typename StreamHandleService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef asio::detail::win_iocp_handle_service::native_handle_type + native_handle_type; +#endif - /// Construct a basic_stream_handle without opening it. + /// Construct a stream handle without opening it. + /** + * This constructor creates a stream handle without opening it. + * + * @param ex The I/O executor that the stream handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the stream + * handle. + */ + explicit basic_stream_handle(const executor_type& ex) + : basic_overlapped_handle<Executor>(ex) + { + } + + /// Construct a stream handle without opening it. /** * This constructor creates a stream handle without opening it. The handle - * needs to be opened and then connected or accepted before data can be sent - * or received on it. + * needs to be opened or assigned before data can be written to or read from + * it. + * + * @param context An execution context which provides the I/O executor that + * the stream handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the stream handle. + */ + template <typename ExecutionContext> + explicit basic_stream_handle(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_overlapped_handle<Executor>(context) + { + } + + /// Construct a stream handle on an existing native handle. + /** + * This constructor creates a stream handle object to hold an existing native + * handle. + * + * @param ex The I/O executor that the stream handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the stream + * handle. + * + * @param handle The new underlying handle implementation. * - * @param io_context The io_context object that the stream handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. + * @throws asio::system_error Thrown on failure. */ - explicit basic_stream_handle(asio::io_context& io_context) - : basic_handle<StreamHandleService>(io_context) + basic_stream_handle(const executor_type& ex, const native_handle_type& handle) + : basic_overlapped_handle<Executor>(ex, handle) { } - /// Construct a basic_stream_handle on an existing native handle. + /// Construct a stream handle on an existing native handle. /** * This constructor creates a stream handle object to hold an existing native * handle. * - * @param io_context The io_context object that the stream handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. + * @param context An execution context which provides the I/O executor that + * the stream handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the stream handle. * * @param handle The new underlying handle implementation. * * @throws asio::system_error Thrown on failure. */ - basic_stream_handle(asio::io_context& io_context, - const native_handle_type& handle) - : basic_handle<StreamHandleService>(io_context, handle) + template <typename ExecutionContext> + basic_stream_handle(ExecutionContext& context, + const native_handle_type& handle, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : basic_overlapped_handle<Executor>(context, handle) { } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a basic_stream_handle from another. + /// Move-construct a stream handle from another. /** * This constructor moves a stream handle from one object to another. * - * @param other The other basic_stream_handle object from which the move + * @param other The other stream handle object from which the move * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_handle(io_context&) constructor. + * constructed using the @c basic_stream_handle(const executor_type&) + * constructor. */ basic_stream_handle(basic_stream_handle&& other) - : basic_handle<StreamHandleService>( - ASIO_MOVE_CAST(basic_stream_handle)(other)) + : basic_overlapped_handle<Executor>(std::move(other)) { } - /// Move-assign a basic_stream_handle from another. + /// Move-assign a stream handle from another. /** * This assignment operator moves a stream handle from one object to * another. * - * @param other The other basic_stream_handle object from which the move - * will occur. + * @param other The other stream handle object from which the move will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_handle(io_context&) constructor. + * constructed using the @c basic_stream_handle(const executor_type&) + * constructor. */ basic_stream_handle& operator=(basic_stream_handle&& other) { - basic_handle<StreamHandleService>::operator=( - ASIO_MOVE_CAST(basic_stream_handle)(other)); + basic_overlapped_handle<Executor>::operator=(std::move(other)); + return *this; + } + + /// Move-construct a stream handle from a handle of another executor type. + /** + * This constructor moves a stream handle from one object to another. + * + * @param other The other stream handle object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + basic_stream_handle(basic_stream_handle<Executor1>&& other, + constraint_t< + is_convertible<Executor1, Executor>::value, + defaulted_constraint + > = defaulted_constraint()) + : basic_overlapped_handle<Executor>(std::move(other)) + { + } + + /// Move-assign a stream handle from a handle of another executor type. + /** + * This assignment operator moves a stream handle from one object to + * another. + * + * @param other The other stream handle object from which the move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_handle(const executor_type&) + * constructor. + */ + template<typename Executor1> + constraint_t< + is_convertible<Executor1, Executor>::value, + basic_stream_handle& + > operator=(basic_stream_handle<Executor1>&& other) + { + basic_overlapped_handle<Executor>::operator=(std::move(other)); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Write some data to the handle. /** @@ -153,8 +246,8 @@ public: std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().write_some( - this->get_implementation(), buffers, ec); + std::size_t s = this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); asio::detail::throw_error(ec, "write_some"); return s; } @@ -179,31 +272,37 @@ public: std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().write_some( - this->get_implementation(), buffers, ec); + return this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the stream handle. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more data buffers to be written to the handle. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -217,19 +316,30 @@ public: * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) + template <typename ConstBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t<executor_type>> + auto async_write_some(const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_write_some>(), token, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - return this->get_service().async_write_some(this->get_implementation(), - buffers, ASIO_MOVE_CAST(WriteHandler)(handler)); + return async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + initiate_async_write_some(this), token, buffers); } /// Read some data from the handle. @@ -264,8 +374,8 @@ public: std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; - std::size_t s = this->get_service().read_some( - this->get_implementation(), buffers, ec); + std::size_t s = this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); asio::detail::throw_error(ec, "read_some"); return s; } @@ -291,31 +401,37 @@ public: std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { - return this->get_service().read_some( - this->get_implementation(), buffers, ec); + return this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the stream handle. - * The function call always returns immediately. + * It is an initiating function for an @ref asynchronous_operation, and always + * returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the read completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -330,20 +446,98 @@ public: * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template <typename MutableBufferSequence, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) ReadToken = default_completion_token_t<executor_type>> + auto async_read_some(const MutableBufferSequence& buffers, + ReadToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + declval<initiate_async_read_some>(), token, buffers)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - return this->get_service().async_read_some(this->get_implementation(), - buffers, ASIO_MOVE_CAST(ReadHandler)(handler)); + return async_initiate<ReadToken, + void (asio::error_code, std::size_t)>( + initiate_async_read_some(this), token, buffers); } + +private: + class initiate_async_write_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_stream_handle* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WriteHandler, typename ConstBufferSequence> + void operator()(WriteHandler&& handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue<WriteHandler> handler2(handler); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_handle* self_; + }; + + class initiate_async_read_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_stream_handle* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ReadHandler, typename MutableBufferSequence> + void operator()(ReadHandler&& handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue<ReadHandler> handler2(handler); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_stream_handle* self_; + }; }; } // namespace windows @@ -354,6 +548,4 @@ public: #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP diff --git a/3rdparty/asio/include/asio/windows/object_handle.hpp b/3rdparty/asio/include/asio/windows/object_handle.hpp index 6b5ad598b11..243d9455ce2 100644 --- a/3rdparty/asio/include/asio/windows/object_handle.hpp +++ b/3rdparty/asio/include/asio/windows/object_handle.hpp @@ -2,7 +2,7 @@ // windows/object_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2011 Boris Schaeling (boris@highscore.de) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -21,360 +21,17 @@ #if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/detail/win_object_handle_service.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/windows/basic_object_handle.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#define ASIO_SVC_T asio::detail::win_object_handle_service - -#include "asio/detail/push_options.hpp" +#include "asio/windows/basic_object_handle.hpp" namespace asio { namespace windows { -#if defined(ASIO_ENABLE_OLD_SERVICES) -// Typedef for the typical usage of an object handle. +/// Typedef for the typical usage of an object handle. typedef basic_object_handle<> object_handle; -#else // defined(ASIO_ENABLE_OLD_SERVICES) -/// Provides object-oriented handle functionality. -/** - * The windows::object_handle class provides asynchronous and blocking - * object-oriented handle functionality. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - */ -class object_handle - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T> -{ -public: - /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; - - /// The native representation of a handle. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef ASIO_SVC_T::native_handle_type native_handle_type; -#endif - - /// An object_handle is always the lowest layer. - typedef object_handle lowest_layer_type; - - /// Construct an object_handle without opening it. - /** - * This constructor creates an object handle without opening it. - * - * @param io_context The io_context object that the object handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - */ - explicit object_handle(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) - { - } - - /// Construct an object_handle on an existing native handle. - /** - * This constructor creates an object handle object to hold an existing native - * handle. - * - * @param io_context The io_context object that the object handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - * - * @param native_handle The new underlying handle implementation. - * - * @throws asio::system_error Thrown on failure. - */ - object_handle(asio::io_context& io_context, - const native_handle_type& native_handle) - : basic_io_object<ASIO_SVC_T>(io_context) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), native_handle, ec); - asio::detail::throw_error(ec, "assign"); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct an object_handle from another. - /** - * This constructor moves an object handle from one object to another. - * - * @param other The other object_handle object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c object_handle(io_context&) constructor. - */ - object_handle(object_handle&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) - { - } - - /// Move-assign an object_handle from another. - /** - * This assignment operator moves an object handle from one object to another. - * - * @param other The other object_handle object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c object_handle(io_context&) constructor. - */ - object_handle& operator=(object_handle&& other) - { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - - /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT - { - return basic_io_object<ASIO_SVC_T>::get_executor(); - } - - /// Get a reference to the lowest layer. - /** - * This function returns a reference to the lowest layer in a stack of - * layers. Since an object_handle cannot contain any further layers, it simply - * returns a reference to itself. - * - * @return A reference to the lowest layer in the stack of layers. Ownership - * is not transferred to the caller. - */ - lowest_layer_type& lowest_layer() - { - return *this; - } - - /// Get a const reference to the lowest layer. - /** - * This function returns a const reference to the lowest layer in a stack of - * layers. Since an object_handle cannot contain any further layers, it simply - * returns a reference to itself. - * - * @return A const reference to the lowest layer in the stack of layers. - * Ownership is not transferred to the caller. - */ - const lowest_layer_type& lowest_layer() const - { - return *this; - } - - /// Assign an existing native handle to the handle. - /* - * This function opens the handle to hold an existing native handle. - * - * @param handle A native handle. - * - * @throws asio::system_error Thrown on failure. - */ - void assign(const native_handle_type& handle) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), handle, ec); - asio::detail::throw_error(ec, "assign"); - } - - /// Assign an existing native handle to the handle. - /* - * This function opens the handle to hold an existing native handle. - * - * @param handle A native handle. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, - asio::error_code& ec) - { - this->get_service().assign(this->get_implementation(), handle, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the handle is open. - bool is_open() const - { - return this->get_service().is_open(this->get_implementation()); - } - - /// Close the handle. - /** - * This function is used to close the handle. Any asynchronous read or write - * operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void close() - { - asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); - asio::detail::throw_error(ec, "close"); - } - - /// Close the handle. - /** - * This function is used to close the handle. Any asynchronous read or write - * operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID close(asio::error_code& ec) - { - this->get_service().close(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native handle representation. - /** - * This function may be used to obtain the underlying representation of the - * handle. This is intended to allow access to native handle functionality - * that is not otherwise provided. - */ - native_handle_type native_handle() - { - return this->get_service().native_handle(this->get_implementation()); - } - - /// Cancel all asynchronous operations associated with the handle. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void cancel() - { - asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); - asio::detail::throw_error(ec, "cancel"); - } - - /// Cancel all asynchronous operations associated with the handle. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) - { - this->get_service().cancel(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Perform a blocking wait on the object handle. - /** - * This function is used to wait for the object handle to be set to the - * signalled state. This function blocks and does not return until the object - * handle has been set to the signalled state. - * - * @throws asio::system_error Thrown on failure. - */ - void wait() - { - asio::error_code ec; - this->get_service().wait(this->get_implementation(), ec); - asio::detail::throw_error(ec, "wait"); - } - - /// Perform a blocking wait on the object handle. - /** - * This function is used to wait for the object handle to be set to the - * signalled state. This function blocks and does not return until the object - * handle has been set to the signalled state. - * - * @param ec Set to indicate what error occurred, if any. - */ - void wait(asio::error_code& ec) - { - this->get_service().wait(this->get_implementation(), ec); - } - - /// Start an asynchronous wait on the object handle. - /** - * This function is be used to initiate an asynchronous wait against the - * object handle. It always returns immediately. - * - * @param handler The handler to be called when the object handle is set to - * the signalled state. Copies will be made of the handler as required. The - * function signature of the handler must be: - * @code void handler( - * const asio::error_code& error // Result of operation. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(ASIO_MOVE_ARG(WaitHandler) handler) - { - asio::async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_wait(this->get_implementation(), - init.completion_handler); - - return init.result.get(); - } -}; -#endif // defined(ASIO_ENABLE_OLD_SERVICES) } // namespace windows } // namespace asio -#include "asio/detail/pop_options.hpp" - -#undef ASIO_SVC_T - #endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) // || defined(GENERATING_DOCUMENTATION) diff --git a/3rdparty/asio/include/asio/windows/object_handle_service.hpp b/3rdparty/asio/include/asio/windows/object_handle_service.hpp deleted file mode 100644 index 524a9f89003..00000000000 --- a/3rdparty/asio/include/asio/windows/object_handle_service.hpp +++ /dev/null @@ -1,183 +0,0 @@ -// -// windows/object_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) -// -// 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_WINDOWS_OBJECT_HANDLE_SERVICE_HPP -#define ASIO_WINDOWS_OBJECT_HANDLE_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) - -#include "asio/async_result.hpp" -#include "asio/detail/win_object_handle_service.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace windows { - -/// Default service implementation for an object handle. -class object_handle_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<object_handle_service> -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - -private: - // The type of the platform-specific implementation. - typedef detail::win_object_handle_service service_impl_type; - -public: - /// The type of an object handle implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef service_impl_type::implementation_type implementation_type; -#endif - - /// The native handle type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new object handle service for the specified io_context. - explicit object_handle_service(asio::io_context& io_context) - : asio::detail::service_base<object_handle_service>(io_context), - service_impl_(io_context) - { - } - - /// Construct a new object handle implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new object handle implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another object handle implementation. - void move_assign(implementation_type& impl, - object_handle_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy an object handle implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Assign an existing native handle to an object handle. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const native_handle_type& handle, asio::error_code& ec) - { - service_impl_.assign(impl, handle, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the handle is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close an object handle implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native handle implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the handle. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - // Wait for a signaled state. - void wait(implementation_type& impl, asio::error_code& ec) - { - service_impl_.wait(impl, ec); - } - - /// Start an asynchronous wait. - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(implementation_type& impl, - ASIO_MOVE_ARG(WaitHandler) handler) - { - asio::async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - service_impl_.async_wait(impl, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace windows -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) - // || defined(GENERATING_DOCUMENTATION) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_WINDOWS_OBJECT_HANDLE_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/windows/overlapped_handle.hpp b/3rdparty/asio/include/asio/windows/overlapped_handle.hpp index 3db0f1dac3c..fc12865b48c 100644 --- a/3rdparty/asio/include/asio/windows/overlapped_handle.hpp +++ b/3rdparty/asio/include/asio/windows/overlapped_handle.hpp @@ -2,7 +2,7 @@ // windows/overlapped_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -17,315 +17,23 @@ #include "asio/detail/config.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) - #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" -#include "asio/detail/throw_error.hpp" -#include "asio/detail/win_iocp_handle_service.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#define ASIO_SVC_T asio::detail::win_iocp_handle_service - -#include "asio/detail/push_options.hpp" +#include "asio/windows/basic_overlapped_handle.hpp" namespace asio { namespace windows { -/// Provides Windows handle functionality for objects that support -/// overlapped I/O. -/** - * The windows::overlapped_handle class provides the ability to wrap a Windows - * handle. The underlying object referred to by the handle must support - * overlapped I/O. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - */ -class overlapped_handle - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T> -{ -public: - /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; - - /// The native representation of a handle. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef ASIO_SVC_T::native_handle_type native_handle_type; -#endif - - /// An overlapped_handle is always the lowest layer. - typedef overlapped_handle lowest_layer_type; - - /// Construct an overlapped_handle without opening it. - /** - * This constructor creates a handle without opening it. - * - * @param io_context The io_context object that the handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - */ - explicit overlapped_handle(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) - { - } - - /// Construct an overlapped_handle on an existing native handle. - /** - * This constructor creates a handle object to hold an existing native handle. - * - * @param io_context The io_context object that the handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - * - * @param handle A native handle. - * - * @throws asio::system_error Thrown on failure. - */ - overlapped_handle(asio::io_context& io_context, - const native_handle_type& handle) - : basic_io_object<ASIO_SVC_T>(io_context) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), handle, ec); - asio::detail::throw_error(ec, "assign"); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct an overlapped_handle from another. - /** - * This constructor moves a handle from one object to another. - * - * @param other The other overlapped_handle object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c overlapped_handle(io_context&) constructor. - */ - overlapped_handle(overlapped_handle&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) - { - } - - /// Move-assign an overlapped_handle from another. - /** - * This assignment operator moves a handle from one object to another. - * - * @param other The other overlapped_handle object from which the move will - * occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c overlapped_handle(io_context&) constructor. - */ - overlapped_handle& operator=(overlapped_handle&& other) - { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) - - /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT - { - return basic_io_object<ASIO_SVC_T>::get_executor(); - } - - /// Get a reference to the lowest layer. - /** - * This function returns a reference to the lowest layer in a stack of - * layers. Since an overlapped_handle cannot contain any further layers, it - * simply returns a reference to itself. - * - * @return A reference to the lowest layer in the stack of layers. Ownership - * is not transferred to the caller. - */ - lowest_layer_type& lowest_layer() - { - return *this; - } - - /// Get a const reference to the lowest layer. - /** - * This function returns a const reference to the lowest layer in a stack of - * layers. Since an overlapped_handle cannot contain any further layers, it - * simply returns a reference to itself. - * - * @return A const reference to the lowest layer in the stack of layers. - * Ownership is not transferred to the caller. - */ - const lowest_layer_type& lowest_layer() const - { - return *this; - } - - /// Assign an existing native handle to the handle. - /* - * This function opens the handle to hold an existing native handle. - * - * @param handle A native handle. - * - * @throws asio::system_error Thrown on failure. - */ - void assign(const native_handle_type& handle) - { - asio::error_code ec; - this->get_service().assign(this->get_implementation(), handle, ec); - asio::detail::throw_error(ec, "assign"); - } - - /// Assign an existing native handle to the handle. - /* - * This function opens the handle to hold an existing native handle. - * - * @param handle A native handle. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, - asio::error_code& ec) - { - this->get_service().assign(this->get_implementation(), handle, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the handle is open. - bool is_open() const - { - return this->get_service().is_open(this->get_implementation()); - } - - /// Close the handle. - /** - * This function is used to close the handle. Any asynchronous read or write - * operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void close() - { - asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); - asio::detail::throw_error(ec, "close"); - } - - /// Close the handle. - /** - * This function is used to close the handle. Any asynchronous read or write - * operations will be cancelled immediately, and will complete with the - * asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID close(asio::error_code& ec) - { - this->get_service().close(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native handle representation. - /** - * This function may be used to obtain the underlying representation of the - * handle. This is intended to allow access to native handle functionality - * that is not otherwise provided. - */ - native_handle_type native_handle() - { - return this->get_service().native_handle(this->get_implementation()); - } - - /// Cancel all asynchronous operations associated with the handle. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @throws asio::system_error Thrown on failure. - */ - void cancel() - { - asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); - asio::detail::throw_error(ec, "cancel"); - } - - /// Cancel all asynchronous operations associated with the handle. - /** - * This function causes all outstanding asynchronous read or write operations - * to finish immediately, and the handlers for cancelled operations will be - * passed the asio::error::operation_aborted error. - * - * @param ec Set to indicate what error occurred, if any. - */ - ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) - { - this->get_service().cancel(this->get_implementation(), ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - -protected: - /// Protected destructor to prevent deletion through this type. - /** - * This function destroys the handle, cancelling any outstanding asynchronous - * wait operations associated with the handle as if by calling @c cancel. - */ - ~overlapped_handle() - { - } -}; +/// Typedef for the typical usage of an overlapped handle. +typedef basic_overlapped_handle<> overlapped_handle; } // namespace windows } // namespace asio -#include "asio/detail/pop_options.hpp" - -#undef ASIO_SVC_T - #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP diff --git a/3rdparty/asio/include/asio/windows/overlapped_ptr.hpp b/3rdparty/asio/include/asio/windows/overlapped_ptr.hpp index 00f3baaaacc..e1e6f8c841f 100644 --- a/3rdparty/asio/include/asio/windows/overlapped_ptr.hpp +++ b/3rdparty/asio/include/asio/windows/overlapped_ptr.hpp @@ -2,7 +2,7 @@ // windows/overlapped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -49,10 +49,25 @@ public: } /// Construct an overlapped_ptr to contain the specified handler. - template <typename Handler> - explicit overlapped_ptr(asio::io_context& io_context, - ASIO_MOVE_ARG(Handler) handler) - : impl_(io_context, ASIO_MOVE_CAST(Handler)(handler)) + template <typename ExecutionContext, typename Handler> + explicit overlapped_ptr(ExecutionContext& context, + Handler&& handler, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(context.get_executor(), static_cast<Handler&&>(handler)) + { + } + + /// Construct an overlapped_ptr to contain the specified handler. + template <typename Executor, typename Handler> + explicit overlapped_ptr(const Executor& ex, + Handler&& handler, + constraint_t< + execution::is_executor<Executor>::value + || is_executor<Executor>::value + > = 0) + : impl_(ex, static_cast<Handler&&>(handler)) { } @@ -69,11 +84,25 @@ public: /// Reset to contain the specified handler, freeing any current OVERLAPPED /// object. - template <typename Handler> - void reset(asio::io_context& io_context, - ASIO_MOVE_ARG(Handler) handler) + template <typename ExecutionContext, typename Handler> + void reset(ExecutionContext& context, Handler&& handler, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + { + impl_.reset(context.get_executor(), static_cast<Handler&&>(handler)); + } + + /// Reset to contain the specified handler, freeing any current OVERLAPPED + /// object. + template <typename Executor, typename Handler> + void reset(const Executor& ex, Handler&& handler, + constraint_t< + execution::is_executor<Executor>::value + || is_executor<Executor>::value + > = 0) { - impl_.reset(io_context, ASIO_MOVE_CAST(Handler)(handler)); + impl_.reset(ex, static_cast<Handler&&>(handler)); } /// Get the contained OVERLAPPED object. diff --git a/3rdparty/asio/include/asio/windows/random_access_handle.hpp b/3rdparty/asio/include/asio/windows/random_access_handle.hpp index cc3ea5c22dd..88dfa36ecdd 100644 --- a/3rdparty/asio/include/asio/windows/random_access_handle.hpp +++ b/3rdparty/asio/include/asio/windows/random_access_handle.hpp @@ -2,7 +2,7 @@ // windows/random_access_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,362 +16,21 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/windows/overlapped_handle.hpp" #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/windows/basic_random_access_handle.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#include "asio/detail/push_options.hpp" +#include "asio/windows/basic_random_access_handle.hpp" namespace asio { namespace windows { -#if defined(ASIO_ENABLE_OLD_SERVICES) -// Typedef for the typical usage of a random-access handle. +/// Typedef for the typical usage of a random-access handle. typedef basic_random_access_handle<> random_access_handle; -#else // defined(ASIO_ENABLE_OLD_SERVICES) -/// Provides random-access handle functionality. -/** - * The windows::random_access_handle class provides asynchronous and - * blocking random-access handle functionality. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - */ -class random_access_handle - : public overlapped_handle -{ -public: - /// Construct a random_access_handle without opening it. - /** - * This constructor creates a random-access handle without opening it. The - * handle needs to be opened before data can be written to or read from it. - * - * @param io_context The io_context object that the random-access handle will - * use to dispatch handlers for any asynchronous operations performed on the - * handle. - */ - explicit random_access_handle(asio::io_context& io_context) - : overlapped_handle(io_context) - { - } - - /// Construct a random_access_handle on an existing native handle. - /** - * This constructor creates a random-access handle object to hold an existing - * native handle. - * - * @param io_context The io_context object that the random-access handle will - * use to dispatch handlers for any asynchronous operations performed on the - * handle. - * - * @param handle The new underlying handle implementation. - * - * @throws asio::system_error Thrown on failure. - */ - random_access_handle(asio::io_context& io_context, - const native_handle_type& handle) - : overlapped_handle(io_context, handle) - { - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a random_access_handle from another. - /** - * This constructor moves a random-access handle from one object to another. - * - * @param other The other random_access_handle object from which the - * move will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c random_access_handle(io_context&) - * constructor. - */ - random_access_handle(random_access_handle&& other) - : overlapped_handle(std::move(other)) - { - } - - /// Move-assign a random_access_handle from another. - /** - * This assignment operator moves a random-access handle from one object to - * another. - * - * @param other The other random_access_handle object from which the - * move will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c random_access_handle(io_context&) - * constructor. - */ - random_access_handle& operator=(random_access_handle&& other) - { - overlapped_handle::operator=(std::move(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Write some data to the handle at the specified offset. - /** - * This function is used to write data to the random-access handle. The - * function call will block until one or more bytes of the data has been - * written successfully, or until an error occurs. - * - * @param offset The offset at which the data will be written. - * - * @param buffers One or more data buffers to be written to the handle. - * - * @returns The number of bytes written. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The write_some_at operation may not write all of the data. Consider - * using the @ref write_at function if you need to ensure that all data is - * written before the blocking operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * handle.write_some_at(42, asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence> - std::size_t write_some_at(uint64_t offset, - const ConstBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().write_some_at( - this->get_implementation(), offset, buffers, ec); - asio::detail::throw_error(ec, "write_some_at"); - return s; - } - - /// Write some data to the handle at the specified offset. - /** - * This function is used to write data to the random-access handle. The - * function call will block until one or more bytes of the data has been - * written successfully, or until an error occurs. - * - * @param offset The offset at which the data will be written. - * - * @param buffers One or more data buffers to be written to the handle. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes written. Returns 0 if an error occurred. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write_at function if you need to ensure that - * all data is written before the blocking operation completes. - */ - template <typename ConstBufferSequence> - std::size_t write_some_at(uint64_t offset, - const ConstBufferSequence& buffers, asio::error_code& ec) - { - return this->get_service().write_some_at( - this->get_implementation(), offset, buffers, ec); - } - - /// Start an asynchronous write at the specified offset. - /** - * This function is used to asynchronously write data to the random-access - * handle. The function call always returns immediately. - * - * @param offset The offset at which the data will be written. - * - * @param buffers One or more data buffers to be written to the handle. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The write operation may not transmit all of the data to the peer. - * Consider using the @ref async_write_at function if you need to ensure that - * all data is written before the asynchronous operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * handle.async_write_some_at(42, asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some_at(uint64_t offset, - const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - asio::async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_write_some_at(this->get_implementation(), - offset, buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the handle at the specified offset. - /** - * This function is used to read data from the random-access handle. The - * function call will block until one or more bytes of data has been read - * successfully, or until an error occurs. - * - * @param offset The offset at which the data will be read. - * - * @param buffers One or more buffers into which the data will be read. - * - * @returns The number of bytes read. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read_at function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * handle.read_some_at(42, asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence> - std::size_t read_some_at(uint64_t offset, - const MutableBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().read_some_at( - this->get_implementation(), offset, buffers, ec); - asio::detail::throw_error(ec, "read_some_at"); - return s; - } - - /// Read some data from the handle at the specified offset. - /** - * This function is used to read data from the random-access handle. The - * function call will block until one or more bytes of data has been read - * successfully, or until an error occurs. - * - * @param offset The offset at which the data will be read. - * - * @param buffers One or more buffers into which the data will be read. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes read. Returns 0 if an error occurred. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read_at function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - */ - template <typename MutableBufferSequence> - std::size_t read_some_at(uint64_t offset, - const MutableBufferSequence& buffers, asio::error_code& ec) - { - return this->get_service().read_some_at( - this->get_implementation(), offset, buffers, ec); - } - - /// Start an asynchronous read at the specified offset. - /** - * This function is used to asynchronously read data from the random-access - * handle. The function call always returns immediately. - * - * @param offset The offset at which the data will be read. - * - * @param buffers One or more buffers into which the data will be read. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The read operation may not read all of the requested number of bytes. - * Consider using the @ref async_read_at function if you need to ensure that - * the requested amount of data is read before the asynchronous operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * handle.async_read_some_at(42, asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some_at(uint64_t offset, - const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - asio::async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_read_some_at(this->get_implementation(), - offset, buffers, init.completion_handler); - - return init.result.get(); - } -}; -#endif // defined(ASIO_ENABLE_OLD_SERVICES) } // namespace windows } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) diff --git a/3rdparty/asio/include/asio/windows/random_access_handle_service.hpp b/3rdparty/asio/include/asio/windows/random_access_handle_service.hpp deleted file mode 100644 index b3df24abaf4..00000000000 --- a/3rdparty/asio/include/asio/windows/random_access_handle_service.hpp +++ /dev/null @@ -1,214 +0,0 @@ -// -// windows/random_access_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP -#define ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/cstdint.hpp" -#include "asio/detail/win_iocp_handle_service.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace windows { - -/// Default service implementation for a random-access handle. -class random_access_handle_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<random_access_handle_service> -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - -private: - // The type of the platform-specific implementation. - typedef detail::win_iocp_handle_service service_impl_type; - -public: - /// The type of a random-access handle implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef service_impl_type::implementation_type implementation_type; -#endif - - /// The native handle type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new random-access handle service for the specified io_context. - explicit random_access_handle_service(asio::io_context& io_context) - : asio::detail::service_base< - random_access_handle_service>(io_context), - service_impl_(io_context) - { - } - - /// Construct a new random-access handle implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new random-access handle implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another random-access handle implementation. - void move_assign(implementation_type& impl, - random_access_handle_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a random-access handle implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Assign an existing native handle to a random-access handle. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const native_handle_type& handle, asio::error_code& ec) - { - service_impl_.assign(impl, handle, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the handle is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a random-access handle implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native handle implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the handle. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Write the given data at the specified offset. - template <typename ConstBufferSequence> - std::size_t write_some_at(implementation_type& impl, uint64_t offset, - const ConstBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.write_some_at(impl, offset, buffers, ec); - } - - /// Start an asynchronous write at the specified offset. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some_at(implementation_type& impl, - uint64_t offset, const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - asio::async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_write_some_at(impl, - offset, buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the specified offset. - template <typename MutableBufferSequence> - std::size_t read_some_at(implementation_type& impl, uint64_t offset, - const MutableBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.read_some_at(impl, offset, buffers, ec); - } - - /// Start an asynchronous read at the specified offset. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some_at(implementation_type& impl, - uint64_t offset, const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - asio::async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_read_some_at(impl, - offset, buffers, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace windows -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) - // || defined(GENERATING_DOCUMENTATION) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/windows/stream_handle.hpp b/3rdparty/asio/include/asio/windows/stream_handle.hpp index 583637af956..4b88b8cb699 100644 --- a/3rdparty/asio/include/asio/windows/stream_handle.hpp +++ b/3rdparty/asio/include/asio/windows/stream_handle.hpp @@ -2,7 +2,7 @@ // windows/stream_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -16,346 +16,21 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" -#include "asio/windows/overlapped_handle.hpp" #if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#if defined(ASIO_ENABLE_OLD_SERVICES) -# include "asio/windows/basic_stream_handle.hpp" -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#include "asio/detail/push_options.hpp" +#include "asio/windows/basic_stream_handle.hpp" namespace asio { namespace windows { -#if defined(ASIO_ENABLE_OLD_SERVICES) -// Typedef for the typical usage of a stream-oriented handle. +/// Typedef for the typical usage of a stream-oriented handle. typedef basic_stream_handle<> stream_handle; -#else // defined(ASIO_ENABLE_OLD_SERVICES) -/// Provides stream-oriented handle functionality. -/** - * The windows::stream_handle class provides asynchronous and blocking - * stream-oriented handle functionality. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - * - * @par Concepts: - * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. - */ -class stream_handle - : public overlapped_handle -{ -public: - /// Construct a stream_handle without opening it. - /** - * This constructor creates a stream handle without opening it. The handle - * needs to be opened and then connected or accepted before data can be sent - * or received on it. - * - * @param io_context The io_context object that the stream handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - */ - explicit stream_handle(asio::io_context& io_context) - : overlapped_handle(io_context) - { - } - - /// Construct a stream_handle on an existing native handle. - /** - * This constructor creates a stream handle object to hold an existing native - * handle. - * - * @param io_context The io_context object that the stream handle will use to - * dispatch handlers for any asynchronous operations performed on the handle. - * - * @param handle The new underlying handle implementation. - * - * @throws asio::system_error Thrown on failure. - */ - stream_handle(asio::io_context& io_context, - const native_handle_type& handle) - : overlapped_handle(io_context, handle) - { - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a stream_handle from another. - /** - * This constructor moves a stream handle from one object to another. - * - * @param other The other stream_handle object from which the move - * will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c stream_handle(io_context&) constructor. - */ - stream_handle(stream_handle&& other) - : overlapped_handle(std::move(other)) - { - } - - /// Move-assign a stream_handle from another. - /** - * This assignment operator moves a stream handle from one object to - * another. - * - * @param other The other stream_handle object from which the move - * will occur. - * - * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c stream_handle(io_context&) constructor. - */ - stream_handle& operator=(stream_handle&& other) - { - overlapped_handle::operator=(std::move(other)); - return *this; - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Write some data to the handle. - /** - * This function is used to write data to the stream handle. The function call - * will block until one or more bytes of the data has been written - * successfully, or until an error occurs. - * - * @param buffers One or more data buffers to be written to the handle. - * - * @returns The number of bytes written. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that - * all data is written before the blocking operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * handle.write_some(asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().write_some( - this->get_implementation(), buffers, ec); - asio::detail::throw_error(ec, "write_some"); - return s; - } - - /// Write some data to the handle. - /** - * This function is used to write data to the stream handle. The function call - * will block until one or more bytes of the data has been written - * successfully, or until an error occurs. - * - * @param buffers One or more data buffers to be written to the handle. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes written. Returns 0 if an error occurred. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that - * all data is written before the blocking operation completes. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers, - asio::error_code& ec) - { - return this->get_service().write_some( - this->get_implementation(), buffers, ec); - } - - /// Start an asynchronous write. - /** - * This function is used to asynchronously write data to the stream handle. - * The function call always returns immediately. - * - * @param buffers One or more data buffers to be written to the handle. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The write operation may not transmit all of the data to the peer. - * Consider using the @ref async_write function if you need to ensure that all - * data is written before the asynchronous operation completes. - * - * @par Example - * To write a single data buffer use the @ref buffer function as follows: - * @code - * handle.async_write_some(asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on writing multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - asio::async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_write_some( - this->get_implementation(), buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the handle. - /** - * This function is used to read data from the stream handle. The function - * call will block until one or more bytes of data has been read successfully, - * or until an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @returns The number of bytes read. - * - * @throws asio::system_error Thrown on failure. An error code of - * asio::error::eof indicates that the connection was closed by the - * peer. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * handle.read_some(asio::buffer(data, size)); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers) - { - asio::error_code ec; - std::size_t s = this->get_service().read_some( - this->get_implementation(), buffers, ec); - asio::detail::throw_error(ec, "read_some"); - return s; - } - - /// Read some data from the handle. - /** - * This function is used to read data from the stream handle. The function - * call will block until one or more bytes of data has been read successfully, - * or until an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes read. Returns 0 if an error occurred. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that - * the requested amount of data is read before the blocking operation - * completes. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers, - asio::error_code& ec) - { - return this->get_service().read_some( - this->get_implementation(), buffers, ec); - } - - /// Start an asynchronous read. - /** - * This function is used to asynchronously read data from the stream handle. - * The function call always returns immediately. - * - * @param buffers One or more buffers into which the data will be read. - * Although the buffers object may be copied as necessary, ownership of the - * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. - * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: - * @code void handler( - * const asio::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. - * ); @endcode - * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). - * - * @note The read operation may not read all of the requested number of bytes. - * Consider using the @ref async_read function if you need to ensure that the - * requested amount of data is read before the asynchronous operation - * completes. - * - * @par Example - * To read into a single data buffer use the @ref buffer function as follows: - * @code - * handle.async_read_some(asio::buffer(data, size), handler); - * @endcode - * See the @ref buffer documentation for information on reading into multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - asio::async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - this->get_service().async_read_some( - this->get_implementation(), buffers, init.completion_handler); - - return init.result.get(); - } -}; -#endif // defined(ASIO_ENABLE_OLD_SERVICES) } // namespace windows } // namespace asio -#include "asio/detail/pop_options.hpp" - #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) diff --git a/3rdparty/asio/include/asio/windows/stream_handle_service.hpp b/3rdparty/asio/include/asio/windows/stream_handle_service.hpp deleted file mode 100644 index 5da3dd7fc9f..00000000000 --- a/3rdparty/asio/include/asio/windows/stream_handle_service.hpp +++ /dev/null @@ -1,210 +0,0 @@ -// -// windows/stream_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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_WINDOWS_STREAM_HANDLE_SERVICE_HPP -#define ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/detail/config.hpp" - -#if defined(ASIO_ENABLE_OLD_SERVICES) - -#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) - -#include <cstddef> -#include "asio/async_result.hpp" -#include "asio/detail/win_iocp_handle_service.hpp" -#include "asio/error.hpp" -#include "asio/io_context.hpp" - -#include "asio/detail/push_options.hpp" - -namespace asio { -namespace windows { - -/// Default service implementation for a stream handle. -class stream_handle_service -#if defined(GENERATING_DOCUMENTATION) - : public asio::io_context::service -#else - : public asio::detail::service_base<stream_handle_service> -#endif -{ -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static asio::io_context::id id; -#endif - -private: - // The type of the platform-specific implementation. - typedef detail::win_iocp_handle_service service_impl_type; - -public: - /// The type of a stream handle implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined implementation_type; -#else - typedef service_impl_type::implementation_type implementation_type; -#endif - - /// The native handle type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_handle_type; -#else - typedef service_impl_type::native_handle_type native_handle_type; -#endif - - /// Construct a new stream handle service for the specified io_context. - explicit stream_handle_service(asio::io_context& io_context) - : asio::detail::service_base<stream_handle_service>(io_context), - service_impl_(io_context) - { - } - - /// Construct a new stream handle implementation. - void construct(implementation_type& impl) - { - service_impl_.construct(impl); - } - -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Move-construct a new stream handle implementation. - void move_construct(implementation_type& impl, - implementation_type& other_impl) - { - service_impl_.move_construct(impl, other_impl); - } - - /// Move-assign from another stream handle implementation. - void move_assign(implementation_type& impl, - stream_handle_service& other_service, - implementation_type& other_impl) - { - service_impl_.move_assign(impl, other_service.service_impl_, other_impl); - } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - - /// Destroy a stream handle implementation. - void destroy(implementation_type& impl) - { - service_impl_.destroy(impl); - } - - /// Assign an existing native handle to a stream handle. - ASIO_SYNC_OP_VOID assign(implementation_type& impl, - const native_handle_type& handle, asio::error_code& ec) - { - service_impl_.assign(impl, handle, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Determine whether the handle is open. - bool is_open(const implementation_type& impl) const - { - return service_impl_.is_open(impl); - } - - /// Close a stream handle implementation. - ASIO_SYNC_OP_VOID close(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.close(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Get the native handle implementation. - native_handle_type native_handle(implementation_type& impl) - { - return service_impl_.native_handle(impl); - } - - /// Cancel all asynchronous operations associated with the handle. - ASIO_SYNC_OP_VOID cancel(implementation_type& impl, - asio::error_code& ec) - { - service_impl_.cancel(impl, ec); - ASIO_SYNC_OP_VOID_RETURN(ec); - } - - /// Write the given data to the stream. - template <typename ConstBufferSequence> - std::size_t write_some(implementation_type& impl, - const ConstBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.write_some(impl, buffers, ec); - } - - /// Start an asynchronous write. - template <typename ConstBufferSequence, typename WriteHandler> - ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) - async_write_some(implementation_type& impl, - const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler) - { - asio::async_completion<WriteHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_write_some(impl, buffers, init.completion_handler); - - return init.result.get(); - } - - /// Read some data from the stream. - template <typename MutableBufferSequence> - std::size_t read_some(implementation_type& impl, - const MutableBufferSequence& buffers, asio::error_code& ec) - { - return service_impl_.read_some(impl, buffers, ec); - } - - /// Start an asynchronous read. - template <typename MutableBufferSequence, typename ReadHandler> - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (asio::error_code, std::size_t)) - async_read_some(implementation_type& impl, - const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) - { - asio::async_completion<ReadHandler, - void (asio::error_code, std::size_t)> init(handler); - - service_impl_.async_read_some(impl, buffers, init.completion_handler); - - return init.result.get(); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown() - { - service_impl_.shutdown(); - } - - // The platform-specific implementation. - service_impl_type service_impl_; -}; - -} // namespace windows -} // namespace asio - -#include "asio/detail/pop_options.hpp" - -#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) - // || defined(GENERATING_DOCUMENTATION) - -#endif // defined(ASIO_ENABLE_OLD_SERVICES) - -#endif // ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP diff --git a/3rdparty/asio/include/asio/writable_pipe.hpp b/3rdparty/asio/include/asio/writable_pipe.hpp new file mode 100644 index 00000000000..27f408a4956 --- /dev/null +++ b/3rdparty/asio/include/asio/writable_pipe.hpp @@ -0,0 +1,35 @@ +// +// writable_pipe.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// 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_WRITABLE_PIPE_HPP +#define ASIO_WRITABLE_PIPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_PIPE) \ + || defined(GENERATING_DOCUMENTATION) + +#include "asio/basic_writable_pipe.hpp" + +namespace asio { + +/// Typedef for the typical usage of a writable pipe. +typedef basic_writable_pipe<> writable_pipe; + +} // namespace asio + +#endif // defined(ASIO_HAS_PIPE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_WRITABLE_PIPE_HPP diff --git a/3rdparty/asio/include/asio/write.hpp b/3rdparty/asio/include/asio/write.hpp index 001086202a7..ca3f002c025 100644 --- a/3rdparty/asio/include/asio/write.hpp +++ b/3rdparty/asio/include/asio/write.hpp @@ -2,7 +2,7 @@ // write.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -19,6 +19,7 @@ #include <cstddef> #include "asio/async_result.hpp" #include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" #include "asio/error.hpp" #if !defined(ASIO_NO_EXTENSIONS) @@ -28,11 +29,21 @@ #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + +template <typename> class initiate_async_write; +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +template <typename> class initiate_async_write_dynbuf_v1; +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) +template <typename> class initiate_async_write_dynbuf_v2; + +} // namespace detail /** * @defgroup write asio::write * - * @brief Write a certain amount of data to a stream before returning. + * @brief The @c write function is a composed operation that writes a certain + * amount of data to a stream before returning. */ /*@{*/ @@ -74,9 +85,9 @@ namespace asio { */ template <typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type* = 0); + > = 0); /// Write all of the supplied data to a stream before returning. /** @@ -117,9 +128,9 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, template <typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, asio::error_code& ec, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type* = 0); + > = 0); /// Write a certain amount of data to a stream before returning. /** @@ -171,9 +182,9 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type* = 0); + > = 0); /// Write a certain amount of data to a stream before returning. /** @@ -218,9 +229,11 @@ template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type* = 0); + > = 0); + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) /// Write all of the supplied data to a stream before returning. /** @@ -249,12 +262,15 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, * s, buffers, * asio::transfer_all()); @endcode */ -template <typename SyncWriteStream, typename DynamicBuffer> +template <typename SyncWriteStream, typename DynamicBuffer_v1> std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + DynamicBuffer_v1&& buffers, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Write all of the supplied data to a stream before returning. /** @@ -283,13 +299,16 @@ std::size_t write(SyncWriteStream& s, * s, buffers, * asio::transfer_all(), ec); @endcode */ -template <typename SyncWriteStream, typename DynamicBuffer> +template <typename SyncWriteStream, typename DynamicBuffer_v1> std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Write a certain amount of data to a stream before returning. /** @@ -327,14 +346,17 @@ std::size_t write(SyncWriteStream& s, * * @throws asio::system_error Thrown on failure. */ -template <typename SyncWriteStream, typename DynamicBuffer, +template <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); /// Write a certain amount of data to a stream before returning. /** @@ -373,14 +395,17 @@ std::size_t write(SyncWriteStream& s, * @returns The number of bytes written. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ -template <typename SyncWriteStream, typename DynamicBuffer, +template <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t write(SyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, + DynamicBuffer_v1&& buffers, CompletionCondition completion_condition, asio::error_code& ec, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0); #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) @@ -527,13 +552,170 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b, #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code asio::write( + * s, buffers, + * asio::transfer_all()); @endcode + */ +template <typename SyncWriteStream, typename DynamicBuffer_v2> +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code asio::write( + * s, buffers, + * asio::transfer_all(), ec); @endcode + */ +template <typename SyncWriteStream, typename DynamicBuffer_v2> +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @returns The number of bytes transferred. + * + * @throws asio::system_error Thrown on failure. + */ +template <typename SyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template <typename SyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, asio::error_code& ec, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0); /*@}*/ /** * @defgroup async_write asio::async_write * - * @brief Start an asynchronous operation to write a certain amount of data to a - * stream. + * @brief The @c async_write function is a composed asynchronous operation that + * writes a certain amount of data to a stream before completion. */ /*@{*/ @@ -541,9 +723,9 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b, /// stream. /** * This function is used to asynchronously write a certain number of bytes of - * data to a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. @@ -562,23 +744,28 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b, * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes written from the - * // buffers. If an error occurred, - * // this will be less than the sum - * // of the buffer sizes. + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -588,24 +775,41 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b, * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. */ template <typename AsyncWriteStream, typename ConstBufferSequence, - typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken + = default_completion_token_t<typename AsyncWriteStream::executor_type>> +auto async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + WriteToken&& token + = default_completion_token_t<typename AsyncWriteStream::executor_type>(), + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type* = 0); + > = 0) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write<AsyncWriteStream>>(), + token, buffers, transfer_all())); /// Start an asynchronous operation to write a certain amount of data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of - * data to a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. @@ -624,7 +828,7 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object @@ -640,21 +844,26 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's async_write_some function. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes written from the - * // buffers. If an error occurred, - * // this will be less than the sum - * // of the buffer sizes. + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -665,25 +874,44 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. */ -template <typename AsyncWriteStream, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, +template <typename AsyncWriteStream, + typename ConstBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +auto async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< + WriteToken&& token, + constraint_t< is_const_buffer_sequence<ConstBufferSequence>::value - >::type* = 0); + > = 0) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write<AsyncWriteStream>>(), + token, buffers, + static_cast<CompletionCondition&&>(completion_condition))); + +#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1) /// Start an asynchronous operation to write all of the supplied data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of - * data to a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li All of the data in the supplied dynamic buffer sequence has been written. * @@ -701,43 +929,68 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * @param buffers The dynamic buffer sequence from which data will be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. Successfully written - * data is automatically consumed from the buffers. - * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * that they remain valid until the completion handler is called. Successfully + * written data is automatically consumed from the buffers. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes written from the - * // buffers. If an error occurred, - * // this will be less than the sum - * // of the buffer sizes. + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. */ -template <typename AsyncWriteStream, - typename DynamicBuffer, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); +template <typename AsyncWriteStream, typename DynamicBuffer_v1, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken + = default_completion_token_t<typename AsyncWriteStream::executor_type>> +auto async_write(AsyncWriteStream& s, DynamicBuffer_v1&& buffers, + WriteToken&& token + = default_completion_token_t<typename AsyncWriteStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + transfer_all())); /// Start an asynchronous operation to write a certain amount of data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of - * data to a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li All of the data in the supplied dynamic buffer sequence has been written. * @@ -755,8 +1008,8 @@ async_write(AsyncWriteStream& s, * @param buffers The dynamic buffer sequence from which data will be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. Successfully written - * data is automatically consumed from the buffers. + * that they remain valid until the completion handler is called. Successfully + * written data is automatically consumed from the buffers. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object @@ -772,33 +1025,56 @@ async_write(AsyncWriteStream& s, * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's async_write_some function. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes written from the - * // buffers. If an error occurred, - * // this will be less than the sum - * // of the buffer sizes. + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. */ -template <typename AsyncWriteStream, typename DynamicBuffer, - typename CompletionCondition, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, - ASIO_MOVE_ARG(DynamicBuffer) buffers, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler, - typename enable_if< - is_dynamic_buffer<DynamicBuffer>::value - >::type* = 0); +template <typename AsyncWriteStream, + typename DynamicBuffer_v1, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +auto async_write(AsyncWriteStream& s, DynamicBuffer_v1&& buffers, + CompletionCondition completion_condition, WriteToken&& token, + constraint_t< + is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value + > = 0, + constraint_t< + !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value + > = 0) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v1&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))); #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) @@ -807,9 +1083,9 @@ async_write(AsyncWriteStream& s, /// stream. /** * This function is used to asynchronously write a certain number of bytes of - * data to a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * @@ -826,37 +1102,60 @@ async_write(AsyncWriteStream& s, * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes written from the - * // buffers. If an error occurred, - * // this will be less than the sum - * // of the buffer sizes. + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. */ -template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, - ASIO_MOVE_ARG(WriteHandler) handler); +template <typename AsyncWriteStream, typename Allocator, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken + = default_completion_token_t<typename AsyncWriteStream::executor_type>> +auto async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, + WriteToken&& token + = default_completion_token_t<typename AsyncWriteStream::executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, basic_streambuf_ref<Allocator>(b), transfer_all())); /// Start an asynchronous operation to write a certain amount of data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of - * data to a stream. The function call always returns immediately. The - * asynchronous operation will continue until one of the following conditions - * is true: + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * @@ -873,7 +1172,7 @@ async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object @@ -889,32 +1188,220 @@ async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's async_write_some function. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error, // Result of operation. + * // Result of operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes written from the - * // buffers. If an error occurred, - * // this will be less than the sum - * // of the buffer sizes. + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. */ -template <typename AsyncWriteStream, typename Allocator, - typename CompletionCondition, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler); +template <typename AsyncWriteStream, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +auto async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, WriteToken&& token) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), + token, basic_streambuf_ref<Allocator>(b), + static_cast<CompletionCondition&&>(completion_condition))); #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) +#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to write all of the supplied data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. Successfully + * written data is automatically consumed from the buffers. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. + */ +template <typename AsyncWriteStream, typename DynamicBuffer_v2, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken + = default_completion_token_t<typename AsyncWriteStream::executor_type>> +auto async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + WriteToken&& token + = default_completion_token_t<typename AsyncWriteStream::executor_type>(), + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + transfer_all())); + +/// Start an asynchronous operation to write a certain amount of data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. The asynchronous + * operation will continue until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the completion handler is called. Successfully + * written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const asio::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. + * + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: + * @code void handler( + * // Result of operation. + * const asio::error_code& error, + * + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncWriteStream type's + * @c async_write_some operation. + */ +template <typename AsyncWriteStream, + typename DynamicBuffer_v2, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken> +auto async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + WriteToken&& token, + constraint_t< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + > = 0) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>>(), + token, static_cast<DynamicBuffer_v2&&>(buffers), + static_cast<CompletionCondition&&>(completion_condition))); /*@}*/ diff --git a/3rdparty/asio/include/asio/write_at.hpp b/3rdparty/asio/include/asio/write_at.hpp index 17227748964..a33514e61a0 100644 --- a/3rdparty/asio/include/asio/write_at.hpp +++ b/3rdparty/asio/include/asio/write_at.hpp @@ -2,7 +2,7 @@ // write_at.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) @@ -18,6 +18,7 @@ #include "asio/detail/config.hpp" #include <cstddef> #include "asio/async_result.hpp" +#include "asio/completion_condition.hpp" #include "asio/detail/cstdint.hpp" #include "asio/error.hpp" @@ -28,11 +29,20 @@ #include "asio/detail/push_options.hpp" namespace asio { +namespace detail { + +template <typename> class initiate_async_write_at; +#if !defined(ASIO_NO_IOSTREAM) +template <typename> class initiate_async_write_at_streambuf; +#endif // !defined(ASIO_NO_IOSTREAM) + +} // namespace detail /** * @defgroup write_at asio::write_at * - * @brief Write a certain amount of data at a specified offset before returning. + * @brief The @c write_at function is a composed operation that writes a + * certain amount of data at a specified offset before returning. */ /*@{*/ @@ -392,8 +402,9 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, /** * @defgroup async_write_at asio::async_write_at * - * @brief Start an asynchronous operation to write a certain amount of data at - * the specified offset. + * @brief The @c async_write_at function is a composed asynchronous operation + * that writes a certain amount of data at the specified offset before + * completion. */ /*@{*/ @@ -401,9 +412,10 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of - * data to a random access device at a specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data to a random access device at a specified offset. It is an initiating + * function for an @ref asynchronous_operation, and always returns immediately. + * The asynchronous operation will continue until one of the following + * conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. @@ -426,11 +438,13 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -440,9 +454,12 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -452,22 +469,41 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessWriteDevice type's + * async_write_some_at operation. */ template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, - typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, - const ConstBufferSequence& buffers, - ASIO_MOVE_ARG(WriteHandler) handler); + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>> +auto async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + WriteToken&& token = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at< + AsyncRandomAccessWriteDevice>>(), + token, offset, buffers, transfer_all())); /// Start an asynchronous operation to write a certain amount of data at the /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of - * data to a random access device at a specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data to a random access device at a specified offset. It is an initiating + * function for an @ref asynchronous_operation, and always returns immediately. + * The asynchronous operation will continue until one of the following + * conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. @@ -490,7 +526,7 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee - * that they remain valid until the handler is called. + * that they remain valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object @@ -506,9 +542,11 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's async_write_some_at function. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -518,9 +556,12 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -531,15 +572,35 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessWriteDevice type's + * async_write_some_at operation. */ -template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, +template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>> +auto async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler); + WriteToken&& token = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at< + AsyncRandomAccessWriteDevice>>(), + token, offset, buffers, + static_cast<CompletionCondition&&>(completion_condition))); #if !defined(ASIO_NO_EXTENSIONS) #if !defined(ASIO_NO_IOSTREAM) @@ -548,9 +609,10 @@ async_write_at(AsyncRandomAccessWriteDevice& d, /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of - * data to a random access device at a specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data to a random access device at a specified offset. It is an initiating + * function for an @ref asynchronous_operation, and always returns immediately. + * The asynchronous operation will continue until one of the following + * conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * @@ -571,11 +633,13 @@ async_write_at(AsyncRandomAccessWriteDevice& d, * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -585,24 +649,47 @@ async_write_at(AsyncRandomAccessWriteDevice& d, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessWriteDevice type's + * async_write_some_at operation. */ template <typename AsyncRandomAccessWriteDevice, typename Allocator, - typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, - basic_streambuf<Allocator>& b, ASIO_MOVE_ARG(WriteHandler) handler); + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>> +auto async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, basic_streambuf<Allocator>& b, + WriteToken&& token = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>>(), + token, offset, &b, transfer_all())); /// Start an asynchronous operation to write a certain amount of data at the /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of - * data to a random access device at a specified offset. The function call - * always returns immediately. The asynchronous operation will continue until - * one of the following conditions is true: + * data to a random access device at a specified offset. It is an initiating + * function for an @ref asynchronous_operation, and always returns immediately. + * The asynchronous operation will continue until one of the following + * conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * @@ -623,7 +710,7 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it - * remains valid until the handler is called. + * remains valid until the completion handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object @@ -639,9 +726,11 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's async_write_some_at function. * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The function signature of the - * handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the write completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, @@ -651,17 +740,40 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation of - * the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code, std::size_t) @endcode + * + * @par Per-Operation Cancellation + * This asynchronous operation supports cancellation for the following + * asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * if they are also supported by the @c AsyncRandomAccessWriteDevice type's + * async_write_some_at operation. */ -template <typename AsyncRandomAccessWriteDevice, typename Allocator, - typename CompletionCondition, typename WriteHandler> -ASIO_INITFN_RESULT_TYPE(WriteHandler, - void (asio::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, +template <typename AsyncRandomAccessWriteDevice, + typename Allocator, typename CompletionCondition, + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, + std::size_t)) WriteToken = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>> +auto async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, - ASIO_MOVE_ARG(WriteHandler) handler); + WriteToken&& token = default_completion_token_t< + typename AsyncRandomAccessWriteDevice::executor_type>()) + -> decltype( + async_initiate<WriteToken, + void (asio::error_code, std::size_t)>( + declval<detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>>(), + token, offset, &b, + static_cast<CompletionCondition&&>(completion_condition))); #endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_EXTENSIONS) diff --git a/3rdparty/asio/include/asio/yield.hpp b/3rdparty/asio/include/asio/yield.hpp index fa178172e5b..c180503dda9 100644 --- a/3rdparty/asio/include/asio/yield.hpp +++ b/3rdparty/asio/include/asio/yield.hpp @@ -2,7 +2,7 @@ // yield.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) |