Initial Commit

This commit is contained in:
2025-11-06 15:51:56 +01:00
commit 0f7191ad54
648 changed files with 170981 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
//
// impl/any_completion_executor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,134 @@
//
// impl/any_io_executor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,169 @@
//
// impl/append.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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/initiation_base.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 : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
std::tuple<Values...> values, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
detail::append_handler<decay_t<Handler>, Values...>(
static_cast<Handler&&>(handler),
static_cast<std::tuple<Values...>&&>(values)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
std::tuple<Values...> values, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
detail::append_handler<decay_t<Handler>, Values...>(
static_cast<Handler&&>(handler),
static_cast<std::tuple<Values...>&&>(values)),
static_cast<Args&&>(args)...);
}
};
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

View File

@@ -0,0 +1,276 @@
//
// impl/as_tuple.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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/associated_executor.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_cont_helpers.hpp"
#include "asio/detail/initiation_base.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 : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
detail::as_tuple_handler<decay_t<Handler>>(
static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
detail::as_tuple_handler<decay_t<Handler>>(
static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
};
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 : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
detail::as_tuple_handler<decay_t<Handler>>(
static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
detail::as_tuple_handler<decay_t<Handler>>(
static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
};
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);
}
};
template <typename... Signatures>
struct async_result<partial_as_tuple, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&&, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
as_tuple_t<
default_completion_token_t<associated_executor_t<Initiation>>>{},
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
as_tuple_t<
default_completion_token_t<associated_executor_t<Initiation>>>{},
static_cast<Args&&>(args)...);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_AS_TUPLE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
//
// impl/awaitable.ipp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_IPP
#define ASIO_IMPL_AWAITABLE_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_CO_AWAIT)
#include "asio/awaitable.hpp"
#include "asio/detail/call_stack.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
void awaitable_launch_context::launch(void (*pump_fn)(void*), void* arg)
{
call_stack<awaitable_launch_context>::context ctx(this);
pump_fn(arg);
}
bool awaitable_launch_context::is_launching()
{
return !!call_stack<awaitable_launch_context>::contains(this);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_CO_AWAIT)
#endif // ASIO_IMPL_AWAITABLE_IPP

View File

@@ -0,0 +1,404 @@
//
// impl/buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_BUFFERED_READ_STREAM_HPP
#define ASIO_IMPL_BUFFERED_READ_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/associator.hpp"
#include "asio/detail/handler_cont_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"
namespace asio {
template <typename Stream>
std::size_t buffered_read_stream<Stream>::fill()
{
detail::buffer_resize_guard<detail::buffered_stream_storage>
resize_guard(storage_);
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
storage_.resize(previous_size + next_layer_.read_some(buffer(
storage_.data() + previous_size,
storage_.size() - previous_size)));
resize_guard.commit();
return storage_.size() - previous_size;
}
template <typename Stream>
std::size_t buffered_read_stream<Stream>::fill(asio::error_code& ec)
{
detail::buffer_resize_guard<detail::buffered_stream_storage>
resize_guard(storage_);
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
storage_.resize(previous_size + next_layer_.read_some(buffer(
storage_.data() + previous_size,
storage_.size() - previous_size),
ec));
resize_guard.commit();
return storage_.size() - previous_size;
}
namespace detail
{
template <typename ReadHandler>
class buffered_fill_handler
{
public:
buffered_fill_handler(detail::buffered_stream_storage& storage,
std::size_t previous_size, ReadHandler& handler)
: storage_(storage),
previous_size_(previous_size),
handler_(static_cast<ReadHandler&&>(handler))
{
}
buffered_fill_handler(const buffered_fill_handler& other)
: storage_(other.storage_),
previous_size_(other.previous_size_),
handler_(other.handler_)
{
}
buffered_fill_handler(buffered_fill_handler&& other)
: storage_(other.storage_),
previous_size_(other.previous_size_),
handler_(static_cast<ReadHandler&&>(other.handler_))
{
}
void operator()(const asio::error_code& ec,
const std::size_t bytes_transferred)
{
storage_.resize(previous_size_ + bytes_transferred);
static_cast<ReadHandler&&>(handler_)(ec, bytes_transferred);
}
//private:
detail::buffered_stream_storage& storage_;
std::size_t previous_size_;
ReadHandler handler_;
};
template <typename ReadHandler>
inline bool asio_handler_is_continuation(
buffered_fill_handler<ReadHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Stream>
class initiate_async_buffered_fill
{
public:
typedef typename remove_reference_t<
Stream>::lowest_layer_type::executor_type executor_type;
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 <template <typename, typename> class Associator,
typename ReadHandler, typename DefaultCandidate>
struct associator<Associator,
detail::buffered_fill_handler<ReadHandler>,
DefaultCandidate>
: Associator<ReadHandler, DefaultCandidate>
{
static typename Associator<ReadHandler, DefaultCandidate>::type get(
const detail::buffered_fill_handler<ReadHandler>& h) noexcept
{
return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::buffered_fill_handler<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 Stream>
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*>()))
{
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
detail::initiate_async_buffered_fill<Stream>(next_layer_),
handler, &storage_);
}
template <typename Stream>
template <typename MutableBufferSequence>
std::size_t buffered_read_stream<Stream>::read_some(
const MutableBufferSequence& buffers)
{
using asio::buffer_size;
if (buffer_size(buffers) == 0)
return 0;
if (storage_.empty())
this->fill();
return this->copy(buffers);
}
template <typename Stream>
template <typename MutableBufferSequence>
std::size_t buffered_read_stream<Stream>::read_some(
const MutableBufferSequence& buffers, asio::error_code& ec)
{
ec = asio::error_code();
using asio::buffer_size;
if (buffer_size(buffers) == 0)
return 0;
if (storage_.empty() && !this->fill(ec))
return 0;
return this->copy(buffers);
}
namespace detail
{
template <typename MutableBufferSequence, typename ReadHandler>
class buffered_read_some_handler
{
public:
buffered_read_some_handler(detail::buffered_stream_storage& storage,
const MutableBufferSequence& buffers, ReadHandler& handler)
: storage_(storage),
buffers_(buffers),
handler_(static_cast<ReadHandler&&>(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_(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;
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);
static_cast<ReadHandler&&>(handler_)(ec, bytes_copied);
}
}
//private:
detail::buffered_stream_storage& storage_;
MutableBufferSequence buffers_;
ReadHandler handler_;
};
template <typename MutableBufferSequence, typename ReadHandler>
inline bool asio_handler_is_continuation(
buffered_read_some_handler<
MutableBufferSequence, ReadHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Stream>
class initiate_async_buffered_read_some
{
public:
typedef typename remove_reference_t<
Stream>::lowest_layer_type::executor_type executor_type;
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(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 <template <typename, typename> class Associator,
typename MutableBufferSequence, typename ReadHandler,
typename DefaultCandidate>
struct associator<Associator,
detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,
DefaultCandidate>
: Associator<ReadHandler, DefaultCandidate>
{
static typename Associator<ReadHandler, DefaultCandidate>::type get(
const detail::buffered_read_some_handler<
MutableBufferSequence, ReadHandler>& h) noexcept
{
return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::buffered_read_some_handler<
MutableBufferSequence, 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 Stream>
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))
{
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>
template <typename MutableBufferSequence>
std::size_t buffered_read_stream<Stream>::peek(
const MutableBufferSequence& buffers)
{
if (storage_.empty())
this->fill();
return this->peek_copy(buffers);
}
template <typename Stream>
template <typename MutableBufferSequence>
std::size_t buffered_read_stream<Stream>::peek(
const MutableBufferSequence& buffers, asio::error_code& ec)
{
ec = asio::error_code();
if (storage_.empty() && !this->fill(ec))
return 0;
return this->peek_copy(buffers);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_BUFFERED_READ_STREAM_HPP

View File

@@ -0,0 +1,384 @@
//
// impl/buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_BUFFERED_WRITE_STREAM_HPP
#define ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/associator.hpp"
#include "asio/detail/handler_cont_helpers.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
std::size_t buffered_write_stream<Stream>::flush()
{
std::size_t bytes_written = write(next_layer_,
buffer(storage_.data(), storage_.size()));
storage_.consume(bytes_written);
return bytes_written;
}
template <typename Stream>
std::size_t buffered_write_stream<Stream>::flush(asio::error_code& ec)
{
std::size_t bytes_written = write(next_layer_,
buffer(storage_.data(), storage_.size()),
transfer_all(), ec);
storage_.consume(bytes_written);
return bytes_written;
}
namespace detail
{
template <typename WriteHandler>
class buffered_flush_handler
{
public:
buffered_flush_handler(detail::buffered_stream_storage& storage,
WriteHandler& handler)
: storage_(storage),
handler_(static_cast<WriteHandler&&>(handler))
{
}
buffered_flush_handler(const buffered_flush_handler& other)
: storage_(other.storage_),
handler_(other.handler_)
{
}
buffered_flush_handler(buffered_flush_handler&& other)
: storage_(other.storage_),
handler_(static_cast<WriteHandler&&>(other.handler_))
{
}
void operator()(const asio::error_code& ec,
const std::size_t bytes_written)
{
storage_.consume(bytes_written);
static_cast<WriteHandler&&>(handler_)(ec, bytes_written);
}
//private:
detail::buffered_stream_storage& storage_;
WriteHandler handler_;
};
template <typename WriteHandler>
inline bool asio_handler_is_continuation(
buffered_flush_handler<WriteHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Stream>
class initiate_async_buffered_flush
{
public:
typedef typename remove_reference_t<
Stream>::lowest_layer_type::executor_type executor_type;
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 <template <typename, typename> class Associator,
typename WriteHandler, typename DefaultCandidate>
struct associator<Associator,
detail::buffered_flush_handler<WriteHandler>,
DefaultCandidate>
: Associator<WriteHandler, DefaultCandidate>
{
static typename Associator<WriteHandler, DefaultCandidate>::type get(
const detail::buffered_flush_handler<WriteHandler>& h) noexcept
{
return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::buffered_flush_handler<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 Stream>
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*>()))
{
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
detail::initiate_async_buffered_flush<Stream>(next_layer_),
handler, &storage_);
}
template <typename Stream>
template <typename ConstBufferSequence>
std::size_t buffered_write_stream<Stream>::write_some(
const ConstBufferSequence& buffers)
{
using asio::buffer_size;
if (buffer_size(buffers) == 0)
return 0;
if (storage_.size() == storage_.capacity())
this->flush();
return this->copy(buffers);
}
template <typename Stream>
template <typename ConstBufferSequence>
std::size_t buffered_write_stream<Stream>::write_some(
const ConstBufferSequence& buffers, asio::error_code& ec)
{
ec = asio::error_code();
using asio::buffer_size;
if (buffer_size(buffers) == 0)
return 0;
if (storage_.size() == storage_.capacity() && !flush(ec))
return 0;
return this->copy(buffers);
}
namespace detail
{
template <typename ConstBufferSequence, typename WriteHandler>
class buffered_write_some_handler
{
public:
buffered_write_some_handler(detail::buffered_stream_storage& storage,
const ConstBufferSequence& buffers, WriteHandler& handler)
: storage_(storage),
buffers_(buffers),
handler_(static_cast<WriteHandler&&>(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_(static_cast<WriteHandler&&>(other.handler_))
{
}
void operator()(const asio::error_code& ec, std::size_t)
{
if (ec)
{
const std::size_t length = 0;
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 = 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);
static_cast<WriteHandler&&>(handler_)(ec, bytes_copied);
}
}
//private:
detail::buffered_stream_storage& storage_;
ConstBufferSequence buffers_;
WriteHandler handler_;
};
template <typename ConstBufferSequence, typename WriteHandler>
inline bool asio_handler_is_continuation(
buffered_write_some_handler<
ConstBufferSequence, WriteHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Stream>
class initiate_async_buffered_write_some
{
public:
typedef typename remove_reference_t<
Stream>::lowest_layer_type::executor_type executor_type;
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(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 <template <typename, typename> class Associator,
typename ConstBufferSequence, typename WriteHandler,
typename DefaultCandidate>
struct associator<Associator,
detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
DefaultCandidate>
: Associator<WriteHandler, DefaultCandidate>
{
static typename Associator<WriteHandler, DefaultCandidate>::type get(
const detail::buffered_write_some_handler<
ConstBufferSequence, WriteHandler>& h) noexcept
{
return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::buffered_write_some_handler<
ConstBufferSequence, 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 Stream>
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))
{
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>
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 = buffer_size(buffers);
std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
storage_.resize(orig_size + length);
return asio::buffer_copy(
storage_.data() + orig_size, buffers, length);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP

View File

@@ -0,0 +1,268 @@
//
// impl/cancel_after.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_CANCEL_AFTER_HPP
#define ASIO_IMPL_CANCEL_AFTER_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/initiation_base.hpp"
#include "asio/detail/timed_cancel_op.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Initiation, typename Clock,
typename WaitTraits, typename... Signatures>
struct initiate_cancel_after : initiation_base<Initiation>
{
using initiation_base<Initiation>::initiation_base;
template <typename Handler, typename Rep, typename Period, typename... Args>
void operator()(Handler&& handler,
const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type, Args&&... args) &&
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits>, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
p.p = new (p.v) op(handler2.value,
basic_waitable_timer<Clock, WaitTraits,
typename Initiation::executor_type>(this->get_executor(), timeout),
cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<Initiation&&>(*this), static_cast<Args&&>(args)...);
}
template <typename Handler, typename Rep, typename Period, typename... Args>
void operator()(Handler&& handler,
const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type, Args&&... args) const &
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits>, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
p.p = new (p.v) op(handler2.value,
basic_waitable_timer<Clock, WaitTraits,
typename Initiation::executor_type>(this->get_executor(), timeout),
cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<const Initiation&>(*this),
static_cast<Args&&>(args)...);
}
};
template <typename Initiation, typename Clock,
typename WaitTraits, typename Executor, typename... Signatures>
struct initiate_cancel_after_timer : initiation_base<Initiation>
{
using initiation_base<Initiation>::initiation_base;
template <typename Handler, typename Rep, typename Period, typename... Args>
void operator()(Handler&& handler,
basic_waitable_timer<Clock, WaitTraits, Executor>* timer,
const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type, Args&&... args) &&
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits, Executor>&, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
timer->expires_after(timeout);
p.p = new (p.v) op(handler2.value, *timer, cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<Initiation&&>(*this), static_cast<Args&&>(args)...);
}
template <typename Handler, typename Rep, typename Period, typename... Args>
void operator()(Handler&& handler,
basic_waitable_timer<Clock, WaitTraits, Executor>* timer,
const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type, Args&&... args) const &
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits, Executor>&, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
timer->expires_after(timeout);
p.p = new (p.v) op(handler2.value, *timer, cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<const Initiation&>(*this),
static_cast<Args&&>(args)...);
}
};
} // namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken, typename Clock,
typename WaitTraits, typename... Signatures>
struct async_result<
cancel_after_t<CompletionToken, Clock, WaitTraits>, Signatures...>
: async_result<CompletionToken, Signatures...>
{
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>,
Signatures...>(
declval<detail::initiate_cancel_after<
decay_t<Initiation>, Clock, WaitTraits, Signatures...>>(),
token.token_, token.timeout_, token.cancel_type_,
static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value,
const CompletionToken, CompletionToken>,
Signatures...>(
detail::initiate_cancel_after<
decay_t<Initiation>, Clock, WaitTraits, Signatures...>(
static_cast<Initiation&&>(initiation)),
token.token_, token.timeout_, token.cancel_type_,
static_cast<Args&&>(args)...);
}
};
template <typename CompletionToken, typename Clock,
typename WaitTraits, typename Executor, typename... Signatures>
struct async_result<
cancel_after_timer<CompletionToken, Clock, WaitTraits, Executor>,
Signatures...>
: async_result<CompletionToken, Signatures...>
{
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>,
Signatures...>(
declval<detail::initiate_cancel_after_timer<
decay_t<Initiation>, Clock, WaitTraits, Executor, Signatures...>>(),
token.token_, &token.timer_, token.timeout_,
token.cancel_type_, static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value,
const CompletionToken, CompletionToken>,
Signatures...>(
detail::initiate_cancel_after_timer<
decay_t<Initiation>, Clock, WaitTraits, Executor, Signatures...>(
static_cast<Initiation&&>(initiation)),
token.token_, &token.timer_, token.timeout_,
token.cancel_type_, static_cast<Args&&>(args)...);
}
};
template <typename Clock, typename WaitTraits, typename... Signatures>
struct async_result<partial_cancel_after<Clock, WaitTraits>, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<
const cancel_after_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>&,
Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_after_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.timeout_, token.cancel_type_),
static_cast<Args&&>(args)...))
{
return async_initiate<
const cancel_after_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>&,
Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_after_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.timeout_, token.cancel_type_),
static_cast<Args&&>(args)...);
}
};
template <typename Clock, typename WaitTraits,
typename Executor, typename... Signatures>
struct async_result<
partial_cancel_after_timer<Clock, WaitTraits, Executor>, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_after_timer<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits, Executor>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.timer_, token.timeout_, token.cancel_type_),
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_after_timer<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits, Executor>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.timer_, token.timeout_, token.cancel_type_),
static_cast<Args&&>(args)...);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_CANCEL_AFTER_HPP

View File

@@ -0,0 +1,268 @@
//
// impl/cancel_at.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_CANCEL_AT_HPP
#define ASIO_IMPL_CANCEL_AT_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/initiation_base.hpp"
#include "asio/detail/timed_cancel_op.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Initiation, typename Clock,
typename WaitTraits, typename... Signatures>
struct initiate_cancel_at : initiation_base<Initiation>
{
using initiation_base<Initiation>::initiation_base;
template <typename Handler, typename Duration, typename... Args>
void operator()(Handler&& handler,
const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type, Args&&... args) &&
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits>, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
p.p = new (p.v) op(handler2.value,
basic_waitable_timer<Clock, WaitTraits,
typename Initiation::executor_type>(this->get_executor(), expiry),
cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<Initiation&&>(*this), static_cast<Args&&>(args)...);
}
template <typename Handler, typename Duration, typename... Args>
void operator()(Handler&& handler,
const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type, Args&&... args) const &
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits>, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
p.p = new (p.v) op(handler2.value,
basic_waitable_timer<Clock, WaitTraits,
typename Initiation::executor_type>(this->get_executor(), expiry),
cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<const Initiation&>(*this),
static_cast<Args&&>(args)...);
}
};
template <typename Initiation, typename Clock,
typename WaitTraits, typename Executor, typename... Signatures>
struct initiate_cancel_at_timer : initiation_base<Initiation>
{
using initiation_base<Initiation>::initiation_base;
template <typename Handler, typename Duration, typename... Args>
void operator()(Handler&& handler,
basic_waitable_timer<Clock, WaitTraits, Executor>* timer,
const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type, Args&&... args) &&
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits, Executor>&, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
timer->expires_at(expiry);
p.p = new (p.v) op(handler2.value, *timer, cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<Initiation&&>(*this), static_cast<Args&&>(args)...);
}
template <typename Handler, typename Duration, typename... Args>
void operator()(Handler&& handler,
basic_waitable_timer<Clock, WaitTraits, Executor>* timer,
const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type, Args&&... args) const &
{
using op = detail::timed_cancel_op<decay_t<Handler>,
basic_waitable_timer<Clock, WaitTraits, Executor>&, Signatures...>;
non_const_lvalue<Handler> handler2(handler);
typename op::ptr p = { asio::detail::addressof(handler2.value),
op::ptr::allocate(handler2.value), 0 };
timer->expires_at(expiry);
p.p = new (p.v) op(handler2.value, *timer, cancel_type);
op* o = p.p;
p.v = p.p = 0;
o->start(static_cast<const Initiation&>(*this),
static_cast<Args&&>(args)...);
}
};
} // namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken, typename Clock,
typename WaitTraits, typename... Signatures>
struct async_result<
cancel_at_t<CompletionToken, Clock, WaitTraits>, Signatures...>
: async_result<CompletionToken, Signatures...>
{
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>,
Signatures...>(
declval<detail::initiate_cancel_at<
decay_t<Initiation>, Clock, WaitTraits, Signatures...>>(),
token.token_, token.expiry_, token.cancel_type_,
static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value,
const CompletionToken, CompletionToken>,
Signatures...>(
detail::initiate_cancel_at<
decay_t<Initiation>, Clock, WaitTraits, Signatures...>(
static_cast<Initiation&&>(initiation)),
token.token_, token.expiry_, token.cancel_type_,
static_cast<Args&&>(args)...);
}
};
template <typename CompletionToken, typename Clock,
typename WaitTraits, typename Executor, typename... Signatures>
struct async_result<
cancel_at_timer<CompletionToken, Clock, WaitTraits, Executor>,
Signatures...>
: async_result<CompletionToken, Signatures...>
{
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>,
Signatures...>(
declval<detail::initiate_cancel_at_timer<
decay_t<Initiation>, Clock, WaitTraits, Executor, Signatures...>>(),
token.token_, &token.timer_, token.expiry_, token.cancel_type_,
static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value,
const CompletionToken, CompletionToken>,
Signatures...>(
detail::initiate_cancel_at_timer<
decay_t<Initiation>, Clock, WaitTraits, Executor, Signatures...>(
static_cast<Initiation&&>(initiation)),
token.token_, &token.timer_, token.expiry_, token.cancel_type_,
static_cast<Args&&>(args)...);
}
};
template <typename Clock, typename WaitTraits, typename... Signatures>
struct async_result<partial_cancel_at<Clock, WaitTraits>, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<
const cancel_at_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>&,
Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_at_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.expiry_, token.cancel_type_),
static_cast<Args&&>(args)...))
{
return async_initiate<
const cancel_at_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>&,
Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_at_t<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.expiry_, token.cancel_type_),
static_cast<Args&&>(args)...);
}
};
template <typename Clock, typename WaitTraits,
typename Executor, typename... Signatures>
struct async_result<
partial_cancel_at_timer<Clock, WaitTraits, Executor>, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_at_timer<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits, Executor>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.timer_, token.expiry_, token.cancel_type_),
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
cancel_at_timer<
default_completion_token_t<associated_executor_t<Initiation>>,
Clock, WaitTraits, Executor>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.timer_, token.expiry_, token.cancel_type_),
static_cast<Args&&>(args)...);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_CANCEL_AT_HPP

View File

@@ -0,0 +1,96 @@
//
// impl/cancellation_signal.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,455 @@
//
// impl/co_spawn.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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{};
std::exception_ptr e = nullptr;
bool done = false;
#if !defined(ASIO_NO_EXCEPTIONS)
try
#endif // !defined(ASIO_NO_EXCEPTIONS)
{
T t = co_await s.function();
done = true;
bool is_launching = (co_await awaitable_thread_is_launching{});
if (is_launching)
{
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;
}
#if !defined(ASIO_NO_EXCEPTIONS)
catch (...)
{
if (done)
throw;
e = std::current_exception();
}
#endif // !defined(ASIO_NO_EXCEPTIONS)
bool is_launching = (co_await awaitable_thread_is_launching{});
if (is_launching)
{
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{};
std::exception_ptr e = nullptr;
#if !defined(ASIO_NO_EXCEPTIONS)
try
#endif // !defined(ASIO_NO_EXCEPTIONS)
{
co_await s.function();
}
#if !defined(ASIO_NO_EXCEPTIONS)
catch (...)
{
e = std::current_exception();
}
#endif // !defined(ASIO_NO_EXCEPTIONS)
bool is_launching = (co_await awaitable_thread_is_launching{});
if (is_launching)
{
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

View File

@@ -0,0 +1,102 @@
//
// impl/config.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_CONFIG_HPP
#define ASIO_IMPL_CONFIG_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cerrno>
#include <cstdlib>
#include <limits>
#include <stdexcept>
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename T>
T config_get(const config_service& service, const char* section,
const char* key_name, T default_value, false_type /*is_bool*/)
{
if (is_unsigned<T>::value)
{
char buf[std::numeric_limits<unsigned long long>::digits10
+ 1 /* sign */ + 1 /* partial digit */ + 1 /* NUL */];
if (const char* str = service.get_value(
section, key_name, buf, sizeof(buf)))
{
char* end = nullptr;
errno = 0;
unsigned long long result = std::strtoull(str, &end, 0);
if (errno == ERANGE
|| result > static_cast<unsigned long long>(
(std::numeric_limits<T>::max)()))
detail::throw_exception(std::out_of_range("config out of range"));
return static_cast<T>(result);
}
}
else
{
char buf[std::numeric_limits<unsigned long long>::digits10
+ 1 /* sign */ + 1 /* partial digit */ + 1 /* NUL */];
if (const char* str = service.get_value(
section, key_name, buf, sizeof(buf)))
{
char* end = nullptr;
errno = 0;
long long result = std::strtoll(str, &end, 0);
if (errno == ERANGE || result < (std::numeric_limits<T>::min)()
|| result > (std::numeric_limits<T>::max)())
detail::throw_exception(std::out_of_range("config out of range"));
return static_cast<T>(result);
}
}
return default_value;
}
template <typename T>
T config_get(const config_service& service, const char* section,
const char* key_name, T default_value, true_type /*is_bool*/)
{
char buf[std::numeric_limits<unsigned long long>::digits10
+ 1 /* sign */ + 1 /* partial digit */ + 1 /* NUL */];
if (const char* str = service.get_value(
section, key_name, buf, sizeof(buf)))
{
char* end = nullptr;
errno = 0;
unsigned long long result = std::strtoll(str, &end, 0);
if (errno == ERANGE || (result != 0 && result != 1))
detail::throw_exception(std::out_of_range("config out of range"));
return static_cast<T>(result != 0);
}
return default_value;
}
} // namespace detail
template <typename T>
constraint_t<is_integral<T>::value, T>
config::get(const char* section, const char* key_name, T default_value) const
{
return detail::config_get(service_, section,
key_name, default_value, is_same<T, bool>());
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_CONFIG_HPP

View File

@@ -0,0 +1,345 @@
//
// impl/config.ipp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_CONFIG_IPP
#define ASIO_IMPL_CONFIG_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/config.hpp"
#include "asio/detail/concurrency_hint.hpp"
#include <cctype>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <utility>
#include "asio/detail/push_options.hpp"
namespace asio {
config_service::config_service(execution_context& ctx)
: detail::execution_context_service_base<config_service>(ctx)
{
}
void config_service::shutdown()
{
}
const char* config_service::get_value(const char* /*section*/,
const char* /*key_name*/, char* /*value*/, std::size_t /*value_len*/) const
{
return nullptr;
}
namespace detail {
class config_from_concurrency_hint_service : public config_service
{
public:
explicit config_from_concurrency_hint_service(
execution_context& ctx, int concurrency_hint)
: config_service(ctx),
concurrency_hint_(concurrency_hint)
{
}
const char* get_value(const char* section, const char* key_name,
char* value, std::size_t value_len) const override
{
if (std::strcmp(section, "scheduler") == 0)
{
if (std::strcmp(key_name, "concurrency_hint") == 0)
{
if (ASIO_CONCURRENCY_HINT_IS_SPECIAL(concurrency_hint_))
{
return
!ASIO_CONCURRENCY_HINT_IS_LOCKING(
SCHEDULER, concurrency_hint_) ||
!ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, concurrency_hint_) ? "1" : "-1";
}
else
{
std::snprintf(value, value_len, "%d", concurrency_hint_);
return value;
}
}
else if (std::strcmp(key_name, "locking") == 0)
{
return ASIO_CONCURRENCY_HINT_IS_LOCKING(
SCHEDULER, concurrency_hint_) ? "1" : "0";
}
}
else if (std::strcmp(section, "reactor") == 0)
{
if (std::strcmp(key_name, "io_locking") == 0)
{
return ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, concurrency_hint_) ? "1" : "0";
}
else if (std::strcmp(key_name, "registration_locking") == 0)
{
return ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_REGISTRATION, concurrency_hint_) ? "1" : "0";
}
}
return nullptr;
}
private:
int concurrency_hint_;
};
} // namespace detail
config_from_concurrency_hint::config_from_concurrency_hint()
: concurrency_hint_(ASIO_CONCURRENCY_HINT_DEFAULT)
{
}
void config_from_concurrency_hint::make(execution_context& ctx) const
{
(void)make_service<detail::config_from_concurrency_hint_service>(ctx,
concurrency_hint_ == 1
? ASIO_CONCURRENCY_HINT_1 : concurrency_hint_);
}
namespace detail {
class config_from_string_service : public config_service
{
public:
config_from_string_service(execution_context& ctx,
std::string s, std::string prefix)
: config_service(ctx),
string_(static_cast<std::string&&>(s)),
prefix_(static_cast<std::string&&>(prefix))
{
enum
{
expecting_key_name,
key_name,
expecting_equals,
expecting_value,
value,
expecting_eol
} state = expecting_key_name;
std::pair<const char*, const char*> entry{};
for (char& c : string_)
{
switch (state)
{
case expecting_key_name:
switch (c)
{
case ' ': case '\t': case '\n':
break;
case '#':
state = expecting_eol;
break;
default:
entry.first = &c;
state = key_name;
break;
}
break;
case key_name:
switch (c)
{
case ' ': case '\t':
c = 0;
state = expecting_equals;
break;
case '=':
c = 0;
state = expecting_value;
break;
case '\n':
entry.first = nullptr;
state = expecting_key_name;
break;
case '#':
entry.first = nullptr;
state = expecting_eol;
break;
default:
break;
}
break;
case expecting_equals:
switch (c)
{
case ' ': case '\t':
break;
case '=':
state = expecting_value;
break;
case '\n':
entry.first = nullptr;
state = expecting_key_name;
break;
default:
entry.first = nullptr;
state = expecting_eol;
break;
}
break;
case expecting_value:
switch (c)
{
case ' ': case '\t':
break;
case '\n':
entry.first = nullptr;
state = expecting_key_name;
break;
case '#':
entry.first = nullptr;
state = expecting_eol;
break;
default:
entry.second = &c;
state = value;
break;
}
break;
case value:
switch (c)
{
case '\n':
c = 0;
entries_.push_back(entry);
entry.first = entry.second = nullptr;
state = expecting_key_name;
break;
case '#':
c = 0;
entries_.push_back(entry);
entry.first = entry.second = nullptr;
state = expecting_eol;
break;
default:
break;
}
break;
case expecting_eol:
switch (c)
{
case '\n':
state = expecting_key_name;
break;
default:
break;
}
break;
}
}
if (entry.first && entry.second)
entries_.push_back(entry);
}
const char* get_value(const char* section, const char* key_name,
char* /*value*/, std::size_t /*value_len*/) const override
{
std::string entry_key;
entry_key.reserve(prefix_.length() + 1
+ std::strlen(section) + 1
+ std::strlen(key_name) + 1);
entry_key.append(prefix_);
if (!entry_key.empty())
entry_key.append(".");
entry_key.append(section);
entry_key.append(".");
entry_key.append(key_name);
for (const std::pair<const char*, const char*>& entry : entries_)
if (entry_key == entry.first)
return entry.second;
return nullptr;
}
private:
std::string string_;
std::string prefix_;
std::vector<std::pair<const char*, const char*>> entries_;
};
} // namespace detail
void config_from_string::make(execution_context& ctx) const
{
(void)make_service<detail::config_from_string_service>(ctx, string_, prefix_);
}
namespace detail {
#if defined(ASIO_MSVC)
# pragma warning (push)
# pragma warning (disable:4996) // suppress unsafe warning for std::getenv
#endif // defined(ASIO_MSVC)
class config_from_env_service : public config_service
{
public:
explicit config_from_env_service(
execution_context& ctx, std::string prefix)
: config_service(ctx),
prefix_(static_cast<std::string&&>(prefix))
{
}
const char* get_value(const char* section, const char* key_name,
char* /*value*/, std::size_t /*value_len*/) const override
{
std::string env_var;
env_var.reserve(prefix_.length() + 1
+ std::strlen(section) + 1
+ std::strlen(key_name) + 1);
env_var.append(prefix_);
if (!env_var.empty())
env_var.append("_");
env_var.append(section);
env_var.append("_");
env_var.append(key_name);
for (char& c : env_var)
c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
return std::getenv(env_var.c_str());
}
private:
std::string prefix_;
};
#if defined(ASIO_MSVC)
# pragma warning (pop)
#endif // defined(ASIO_MSVC)
} // namespace detail
config_from_env::config_from_env()
: prefix_("asio")
{
}
void config_from_env::make(execution_context& ctx) const
{
(void)make_service<detail::config_from_env_service>(ctx, prefix_);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_CONFIG_IPP

View File

@@ -0,0 +1,645 @@
//
// impl/connect.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_HPP
#define ASIO_IMPL_CONNECT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <algorithm>
#include "asio/associator.hpp"
#include "asio/detail/base_from_cancellation_state.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/handler_cont_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"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail
{
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 ConnectCondition, typename Iterator>
inline Iterator call_connect_condition(ConnectCondition& connect_condition,
const asio::error_code& ec, Iterator next, Iterator end,
constraint_t<
is_same<
result_of_t<ConnectCondition(asio::error_code, Iterator)>,
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,
constraint_t<
is_same<
result_of_t<ConnectCondition(asio::error_code,
decltype(*declval<Iterator>()))>,
bool
>::value
> = 0)
{
for (;next != end; ++next)
if (connect_condition(ec, *next))
return next;
return end;
}
} // namespace detail
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints,
constraint_t<
is_endpoint_sequence<EndpointSequence>::value
>)
{
asio::error_code ec;
typename Protocol::endpoint result = connect(s, endpoints, ec);
asio::detail::throw_error(ec, "connect");
return result;
}
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, asio::error_code& ec,
constraint_t<
is_endpoint_sequence<EndpointSequence>::value
>)
{
return detail::deref_connect_result<Protocol>(
connect(s, endpoints.begin(), endpoints.end(),
detail::default_connect_condition(), ec), ec);
}
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end)
{
asio::error_code ec;
Iterator result = connect(s, begin, end, ec);
asio::detail::throw_error(ec, "connect");
return result;
}
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, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
constraint_t<
is_endpoint_sequence<EndpointSequence>::value
>,
constraint_t<
is_connect_condition<ConnectCondition,
decltype(declval<const EndpointSequence&>().begin())>::value
>)
{
asio::error_code ec;
typename Protocol::endpoint result = connect(
s, endpoints, connect_condition, ec);
asio::detail::throw_error(ec, "connect");
return result;
}
template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
asio::error_code& ec,
constraint_t<
is_endpoint_sequence<EndpointSequence>::value
>,
constraint_t<
is_connect_condition<ConnectCondition,
decltype(declval<const EndpointSequence&>().begin())>::value
>)
{
return detail::deref_connect_result<Protocol>(
connect(s, endpoints.begin(), endpoints.end(),
connect_condition, ec), ec);
}
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition,
constraint_t<
is_connect_condition<ConnectCondition, Iterator>::value
>)
{
asio::error_code ec;
Iterator result = connect(s, begin, end, connect_condition, ec);
asio::detail::throw_error(ec, "connect");
return result;
}
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition,
asio::error_code& ec,
constraint_t<
is_connect_condition<ConnectCondition, Iterator>::value
>)
{
ec = asio::error_code();
for (Iterator iter = begin; iter != end; ++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)
ec = asio::error::not_found;
return end;
}
namespace detail
{
// Enable the empty base class optimisation for the connect condition.
template <typename ConnectCondition>
class base_from_connect_condition
{
protected:
explicit base_from_connect_condition(
const ConnectCondition& connect_condition)
: connect_condition_(connect_condition)
{
}
template <typename Iterator>
void check_condition(const asio::error_code& ec,
Iterator& iter, Iterator& end)
{
iter = detail::call_connect_condition(connect_condition_, ec, iter, end);
}
private:
ConnectCondition connect_condition_;
};
// The default_connect_condition implementation is essentially a no-op. This
// template specialisation lets us eliminate all costs associated with it.
template <>
class base_from_connect_condition<default_connect_condition>
{
protected:
explicit base_from_connect_condition(const default_connect_condition&)
{
}
template <typename Iterator>
void check_condition(const asio::error_code&, Iterator&, Iterator&)
{
}
};
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, Executor>& sock,
const EndpointSequence& endpoints,
const ConnectCondition& connect_condition,
RangeConnectHandler& handler)
: 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_(static_cast<RangeConnectHandler&&>(handler))
{
}
range_connect_op(const range_connect_op& other)
: 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_(other.handler_)
{
}
range_connect_op(range_connect_op&& 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_(static_cast<RangeConnectHandler&&>(other.handler_))
{
}
void operator()(asio::error_code ec, int start = 0)
{
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_);
switch (start_ = start)
{
case 1:
for (;;)
{
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,
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(
static_cast<range_connect_op&&>(*this), ec));
return;
}
/* fall-through */ default:
if (iter == end)
break;
if (!socket_.is_open())
{
ec = asio::error::operation_aborted;
break;
}
if (!ec)
break;
if (this->cancelled() != cancellation_type::none)
{
ec = asio::error::operation_aborted;
break;
}
++iter;
++index_;
}
static_cast<RangeConnectHandler&&>(handler_)(
static_cast<const asio::error_code&>(ec),
static_cast<const typename Protocol::endpoint&>(
ec || iter == end ? typename Protocol::endpoint() : *iter));
}
}
basic_socket<Protocol, Executor>& socket_;
EndpointSequence endpoints_;
std::size_t index_;
int start_;
RangeConnectHandler handler_;
};
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
inline bool asio_handler_is_continuation(
range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Protocol, typename Executor>
class initiate_async_range_connect
{
public:
typedef Executor executor_type;
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, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
class iterator_connect_op
: public base_from_cancellation_state<IteratorConnectHandler>,
base_from_connect_condition<ConnectCondition>
{
public:
iterator_connect_op(basic_socket<Protocol, Executor>& sock,
const Iterator& begin, const Iterator& end,
const ConnectCondition& connect_condition,
IteratorConnectHandler& handler)
: 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_(static_cast<IteratorConnectHandler&&>(handler))
{
}
iterator_connect_op(const iterator_connect_op& other)
: 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_(other.handler_)
{
}
iterator_connect_op(iterator_connect_op&& 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_(static_cast<IteratorConnectHandler&&>(other.handler_))
{
}
void operator()(asio::error_code ec, int start = 0)
{
switch (start_ = start)
{
case 1:
for (;;)
{
this->check_condition(ec, iter_, end_);
if (iter_ != end_)
{
socket_.close(ec);
ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));
socket_.async_connect(*iter_,
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(
static_cast<iterator_connect_op&&>(*this), ec));
return;
}
/* fall-through */ default:
if (iter_ == end_)
break;
if (!socket_.is_open())
{
ec = asio::error::operation_aborted;
break;
}
if (!ec)
break;
if (this->cancelled() != cancellation_type::none)
{
ec = asio::error::operation_aborted;
break;
}
++iter_;
}
static_cast<IteratorConnectHandler&&>(handler_)(
static_cast<const asio::error_code&>(ec),
static_cast<const Iterator&>(iter_));
}
}
//private:
basic_socket<Protocol, Executor>& socket_;
Iterator iter_;
Iterator end_;
int start_;
IteratorConnectHandler handler_;
};
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
inline bool asio_handler_is_continuation(
iterator_connect_op<Protocol, Executor, Iterator,
ConnectCondition, IteratorConnectHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Protocol, typename Executor>
class initiate_async_iterator_connect
{
public:
typedef Executor executor_type;
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 <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>,
DefaultCandidate>
: Associator<RangeConnectHandler, DefaultCandidate>
{
static typename Associator<RangeConnectHandler, DefaultCandidate>::type get(
const detail::range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>& h) noexcept
{
return Associator<RangeConnectHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::range_connect_op<Protocol, Executor,
EndpointSequence, ConnectCondition, RangeConnectHandler>& h,
const DefaultCandidate& c) noexcept
-> decltype(
Associator<RangeConnectHandler, DefaultCandidate>::get(
h.handler_, c))
{
return Associator<RangeConnectHandler, DefaultCandidate>::get(
h.handler_, c);
}
};
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>
{
static typename Associator<IteratorConnectHandler, DefaultCandidate>::type
get(const detail::iterator_connect_op<Protocol, Executor, Iterator,
ConnectCondition, IteratorConnectHandler>& h) noexcept
{
return Associator<IteratorConnectHandler, DefaultCandidate>::get(
h.handler_);
}
static auto get(
const detail::iterator_connect_op<Protocol, Executor,
Iterator, ConnectCondition, IteratorConnectHandler>& h,
const DefaultCandidate& c) noexcept
-> decltype(
Associator<IteratorConnectHandler, DefaultCandidate>::get(
h.handler_, c))
{
return Associator<IteratorConnectHandler, DefaultCandidate>::get(
h.handler_, c);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_CONNECT_HPP

View File

@@ -0,0 +1,73 @@
//
// impl/connect_pipe.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,150 @@
//
// impl/connect_pipe.ipp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 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,
// Include address of static to discriminate asio instances in DLLs.
L"\\\\.\\pipe\\asio-A0812896-741A-484D-AF23-BE51BF620E22-%u-%p-%ld-%ld",
static_cast<unsigned int>(::GetCurrentProcessId()), &counter1, 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

View File

@@ -0,0 +1,144 @@
//
// impl/consign.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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/initiation_base.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 : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
std::tuple<Values...> values, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
detail::consign_handler<decay_t<Handler>, Values...>(
static_cast<Handler&&>(handler),
static_cast<std::tuple<Values...>&&>(values)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
std::tuple<Values...> values, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
detail::consign_handler<decay_t<Handler>, Values...>(
static_cast<Handler&&>(handler),
static_cast<std::tuple<Values...>&&>(values)),
static_cast<Args&&>(args)...);
}
};
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

View File

@@ -0,0 +1,147 @@
//
// impl/deferred.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,77 @@
//
// impl/detached.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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... Signatures>
struct async_result<detached_t, Signatures...>
{
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

128
include/asio/impl/error.ipp Normal file
View File

@@ -0,0 +1,128 @@
//
// impl/error.ipp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_ERROR_IPP
#define ASIO_IMPL_ERROR_IPP
#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/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace error {
#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
namespace detail {
class netdb_category : public asio::error_category
{
public:
const char* name() const noexcept
{
return "asio.netdb";
}
std::string message(int value) const
{
if (value == error::host_not_found)
return "Host not found (authoritative)";
if (value == error::host_not_found_try_again)
return "Host not found (non-authoritative), try again later";
if (value == error::no_data)
return "The query is valid, but it does not have associated data";
if (value == error::no_recovery)
return "A non-recoverable error occurred during database lookup";
return "asio.netdb error";
}
};
} // namespace detail
const asio::error_category& get_netdb_category()
{
static detail::netdb_category instance;
return instance;
}
namespace detail {
class addrinfo_category : public asio::error_category
{
public:
const char* name() const noexcept
{
return "asio.addrinfo";
}
std::string message(int value) const
{
if (value == error::service_not_found)
return "Service not found";
if (value == error::socket_type_not_supported)
return "Socket type not supported";
return "asio.addrinfo error";
}
};
} // namespace detail
const asio::error_category& get_addrinfo_category()
{
static detail::addrinfo_category instance;
return instance;
}
#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
namespace detail {
class misc_category : public asio::error_category
{
public:
const char* name() const noexcept
{
return "asio.misc";
}
std::string message(int value) const
{
if (value == error::already_open)
return "Already open";
if (value == error::eof)
return "End of file";
if (value == error::not_found)
return "Element not found";
if (value == error::fd_set_failure)
return "The descriptor does not fit into the select call's fd_set";
return "asio.misc error";
}
};
} // namespace detail
const asio::error_category& get_misc_category()
{
static detail::misc_category instance;
return instance;
}
} // namespace error
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_ERROR_IPP

View File

@@ -0,0 +1,207 @@
//
// impl/error_code.ipp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_ERROR_CODE_IPP
#define ASIO_IMPL_ERROR_CODE_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_WINDOWS) || defined(__CYGWIN__)
# include <winerror.h>
#elif defined(ASIO_WINDOWS_RUNTIME)
# include <windows.h>
#else
# include <cerrno>
# include <cstring>
# include <string>
#endif
#include "asio/detail/local_free_on_block_exit.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/error_code.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class system_category : public error_category
{
public:
const char* name() const noexcept
{
return "asio.system";
}
std::string message(int value) const
{
#if defined(ASIO_WINDOWS_RUNTIME) || defined(ASIO_WINDOWS_APP)
std::wstring wmsg(128, wchar_t());
for (;;)
{
DWORD wlength = ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
&wmsg[0], static_cast<DWORD>(wmsg.size()), 0);
if (wlength == 0 && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
wmsg.resize(wmsg.size() + wmsg.size() / 2);
continue;
}
if (wlength && wmsg[wlength - 1] == '\n')
--wlength;
if (wlength && wmsg[wlength - 1] == '\r')
--wlength;
if (wlength)
{
std::string msg(wlength * 2, char());
int length = ::WideCharToMultiByte(CP_ACP, 0,
wmsg.c_str(), static_cast<int>(wlength),
&msg[0], static_cast<int>(wlength * 2), 0, 0);
if (length <= 0)
return "asio.system error";
msg.resize(static_cast<std::size_t>(length));
return msg;
}
else
return "asio.system error";
}
#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
char* msg = 0;
DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);
detail::local_free_on_block_exit local_free_obj(msg);
if (length && msg[length - 1] == '\n')
msg[--length] = '\0';
if (length && msg[length - 1] == '\r')
msg[--length] = '\0';
if (length)
return msg;
else
return "asio.system error";
#else // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)
#if !defined(__sun)
if (value == ECANCELED)
return "Operation aborted.";
#endif // !defined(__sun)
#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__)
using namespace std;
return strerror(value);
#else
char buf[256] = "";
using namespace std;
return strerror_result(strerror_r(value, buf, sizeof(buf)), buf);
#endif
#endif // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)
}
#if defined(ASIO_HAS_STD_ERROR_CODE)
std::error_condition default_error_condition(
int ev) const noexcept
{
switch (ev)
{
case access_denied:
return std::errc::permission_denied;
case address_family_not_supported:
return std::errc::address_family_not_supported;
case address_in_use:
return std::errc::address_in_use;
case already_connected:
return std::errc::already_connected;
case already_started:
return std::errc::connection_already_in_progress;
case broken_pipe:
return std::errc::broken_pipe;
case connection_aborted:
return std::errc::connection_aborted;
case connection_refused:
return std::errc::connection_refused;
case connection_reset:
return std::errc::connection_reset;
case bad_descriptor:
return std::errc::bad_file_descriptor;
case fault:
return std::errc::bad_address;
case host_unreachable:
return std::errc::host_unreachable;
case in_progress:
return std::errc::operation_in_progress;
case interrupted:
return std::errc::interrupted;
case invalid_argument:
return std::errc::invalid_argument;
case message_size:
return std::errc::message_size;
case name_too_long:
return std::errc::filename_too_long;
case network_down:
return std::errc::network_down;
case network_reset:
return std::errc::network_reset;
case network_unreachable:
return std::errc::network_unreachable;
case no_descriptors:
return std::errc::too_many_files_open;
case no_buffer_space:
return std::errc::no_buffer_space;
case no_memory:
return std::errc::not_enough_memory;
case no_permission:
return std::errc::operation_not_permitted;
case no_protocol_option:
return std::errc::no_protocol_option;
case no_such_device:
return std::errc::no_such_device;
case not_connected:
return std::errc::not_connected;
case not_socket:
return std::errc::not_a_socket;
case operation_aborted:
return std::errc::operation_canceled;
case operation_not_supported:
return std::errc::operation_not_supported;
case shut_down:
return std::make_error_condition(ev, *this);
case timed_out:
return std::errc::timed_out;
case try_again:
return std::errc::resource_unavailable_try_again;
case would_block:
return std::errc::operation_would_block;
default:
return std::make_error_condition(ev, *this);
}
}
#endif // defined(ASIO_HAS_STD_ERROR_CODE)
private:
// Helper function to adapt the result from glibc's variant of strerror_r.
static const char* strerror_result(int, const char* s) { return s; }
static const char* strerror_result(const char* s, const char*) { return s; }
};
} // namespace detail
const error_category& system_category()
{
static detail::system_category instance;
return instance;
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_ERROR_CODE_IPP

View File

@@ -0,0 +1,145 @@
//
// impl/execution_context.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_EXECUTION_CONTEXT_HPP
#define ASIO_IMPL_EXECUTION_CONTEXT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <cstring>
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/service_registry.hpp"
#include "asio/detail/throw_exception.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Allocator>
execution_context::execution_context(allocator_arg_t, const Allocator& a)
: execution_context(detail::allocate_object<allocator_impl<Allocator>>(a, a))
{
}
template <typename Allocator>
execution_context::execution_context(allocator_arg_t, const Allocator& a,
const service_maker& initial_services)
: execution_context(detail::allocate_object<allocator_impl<Allocator>>(a, a),
initial_services)
{
}
inline execution_context::auto_allocator_ptr::~auto_allocator_ptr()
{
ptr_->destroy();
}
template <typename Allocator>
void execution_context::allocator_impl<Allocator>::destroy()
{
detail::deallocate_object(allocator_, this);
}
template <typename Allocator>
void* execution_context::allocator_impl<Allocator>::allocate(
std::size_t size, std::size_t align)
{
typename std::allocator_traits<Allocator>::template
rebind_alloc<unsigned char> alloc(allocator_);
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 0;
}
template <typename Allocator>
void execution_context::allocator_impl<Allocator>::deallocate(
void* ptr, std::size_t size, std::size_t align)
{
if (ptr)
{
typename std::allocator_traits<Allocator>::template
rebind_alloc<unsigned char> alloc(allocator_);
std::ptrdiff_t off;
std::memcpy(&off, static_cast<unsigned char*>(ptr) + size, sizeof(off));
unsigned char* base = static_cast<unsigned char*>(ptr) - off;
std::allocator_traits<decltype(alloc)>::deallocate(
alloc, base, size + align - 1 + sizeof(std::ptrdiff_t));
}
}
#if !defined(GENERATING_DOCUMENTATION)
template <typename Service>
inline Service& use_service(execution_context& e)
{
// Check that Service meets the necessary type requirements.
(void)static_cast<execution_context::service*>(static_cast<Service*>(0));
return e.service_registry_->template use_service<Service>();
}
template <typename Service, typename... Args>
Service& make_service(execution_context& e, Args&&... args)
{
// Check that Service meets the necessary type requirements.
(void)static_cast<execution_context::service*>(static_cast<Service*>(0));
return e.service_registry_->template make_service<Service>(
static_cast<Args&&>(args)...);
}
template <typename Service>
inline void add_service(execution_context& e, Service* svc)
{
// Check that Service meets the necessary type requirements.
(void)static_cast<execution_context::service*>(static_cast<Service*>(0));
e.service_registry_->template add_service<Service>(svc);
}
template <typename Service>
inline bool has_service(execution_context& e)
{
// Check that Service meets the necessary type requirements.
(void)static_cast<execution_context::service*>(static_cast<Service*>(0));
return e.service_registry_->template has_service<Service>();
}
#endif // !defined(GENERATING_DOCUMENTATION)
inline execution_context& execution_context::service::context()
{
return owner_;
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_EXECUTION_CONTEXT_HPP

View File

@@ -0,0 +1,120 @@
//
// impl/execution_context.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_EXECUTION_CONTEXT_IPP
#define ASIO_IMPL_EXECUTION_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/execution_context.hpp"
#include "asio/detail/service_registry.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
execution_context::execution_context()
: execution_context(
detail::allocate_object<allocator_impl<std::allocator<void>>>(
std::allocator<void>(), std::allocator<void>()))
{
}
execution_context::execution_context(allocator_impl_base* alloc)
: allocator_{alloc},
service_registry_(
detail::allocate_object<detail::service_registry>(
allocator<void>(*this), *this))
{
}
execution_context::execution_context(
const execution_context::service_maker& initial_services)
: execution_context(
detail::allocate_object<allocator_impl<std::allocator<void>>>(
std::allocator<void>(), std::allocator<void>()),
initial_services)
{
}
execution_context::execution_context(allocator_impl_base* alloc,
const execution_context::service_maker& initial_services)
: allocator_{alloc},
service_registry_(
detail::allocate_object<detail::service_registry>(
allocator<void>(*this), *this))
{
initial_services.make(*this);
}
execution_context::~execution_context()
{
shutdown();
destroy();
detail::deallocate_object(allocator<void>(*this), service_registry_);
}
void execution_context::shutdown()
{
service_registry_->shutdown_services();
}
void execution_context::destroy()
{
service_registry_->destroy_services();
}
void execution_context::notify_fork(
asio::execution_context::fork_event event)
{
service_registry_->notify_fork(event);
}
execution_context::allocator_impl_base::~allocator_impl_base()
{
}
execution_context::service::service(execution_context& owner)
: owner_(owner),
next_(0),
destroy_(0)
{
}
execution_context::service::~service()
{
}
void execution_context::service::notify_fork(execution_context::fork_event)
{
}
execution_context::service_maker::~service_maker()
{
}
service_already_exists::service_already_exists()
: std::logic_error("Service already exists.")
{
}
invalid_service_owner::invalid_service_owner()
: std::logic_error("Invalid service owner.")
{
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_EXECUTION_CONTEXT_IPP

View File

@@ -0,0 +1,317 @@
//
// impl/executor.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_EXECUTOR_HPP
#define ASIO_IMPL_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_NO_TS_EXECUTORS)
#include <new>
#include "asio/detail/atomic_count.hpp"
#include "asio/detail/global.hpp"
#include "asio/detail/memory.hpp"
#include "asio/executor.hpp"
#include "asio/system_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(GENERATING_DOCUMENTATION)
// Default polymorphic executor implementation.
template <typename Executor, typename Allocator>
class executor::impl
: public executor::impl_base
{
public:
typedef ASIO_REBIND_ALLOC(Allocator, impl) allocator_type;
static impl_base* create(const Executor& e, Allocator a = Allocator())
{
raw_mem mem(a);
impl* p = new (mem.ptr_) impl(e, a);
mem.ptr_ = 0;
return p;
}
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),
allocator_(a)
{
}
impl_base* clone() const noexcept
{
detail::ref_count_up(ref_count_);
return const_cast<impl_base*>(static_cast<const impl_base*>(this));
}
void destroy() noexcept
{
if (detail::ref_count_down(ref_count_))
{
allocator_type alloc(allocator_);
impl* p = this;
p->~impl();
alloc.deallocate(p, 1);
}
}
void on_work_started() noexcept
{
executor_.on_work_started();
}
void on_work_finished() noexcept
{
executor_.on_work_finished();
}
execution_context& context() noexcept
{
return executor_.context();
}
void dispatch(function&& f)
{
executor_.dispatch(static_cast<function&&>(f), allocator_);
}
void post(function&& f)
{
executor_.post(static_cast<function&&>(f), allocator_);
}
void defer(function&& f)
{
executor_.defer(static_cast<function&&>(f), allocator_);
}
type_id_result_type target_type() const noexcept
{
return type_id<Executor>();
}
void* target() noexcept
{
return &executor_;
}
const void* target() const noexcept
{
return &executor_;
}
bool equals(const impl_base* e) const noexcept
{
if (this == e)
return true;
if (target_type() != e->target_type())
return false;
return executor_ == *static_cast<const Executor*>(e->target());
}
private:
mutable detail::atomic_count ref_count_;
Executor executor_;
Allocator allocator_;
struct raw_mem
{
allocator_type allocator_;
impl* ptr_;
explicit raw_mem(const Allocator& a)
: allocator_(a),
ptr_(allocator_.allocate(1))
{
}
~raw_mem()
{
if (ptr_)
allocator_.deallocate(ptr_, 1);
}
private:
// Disallow copying and assignment.
raw_mem(const raw_mem&);
raw_mem operator=(const raw_mem&);
};
};
// Polymorphic executor specialisation for system_executor.
template <typename Allocator>
class executor::impl<system_executor, Allocator>
: public executor::impl_base
{
public:
static impl_base* create(const system_executor&,
const Allocator& = Allocator())
{
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()
: impl_base(true)
{
}
impl_base* clone() const noexcept
{
return const_cast<impl_base*>(static_cast<const impl_base*>(this));
}
void destroy() noexcept
{
}
void on_work_started() noexcept
{
executor_.on_work_started();
}
void on_work_finished() noexcept
{
executor_.on_work_finished();
}
execution_context& context() noexcept
{
return executor_.context();
}
void dispatch(function&& f)
{
executor_.dispatch(static_cast<function&&>(f),
std::allocator<void>());
}
void post(function&& f)
{
executor_.post(static_cast<function&&>(f),
std::allocator<void>());
}
void defer(function&& f)
{
executor_.defer(static_cast<function&&>(f),
std::allocator<void>());
}
type_id_result_type target_type() const noexcept
{
return type_id<system_executor>();
}
void* target() noexcept
{
return &executor_;
}
const void* target() const noexcept
{
return &executor_;
}
bool equals(const impl_base* e) const noexcept
{
return this == e;
}
private:
system_executor executor_;
};
template <typename Executor>
executor::executor(Executor 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))
{
}
template <typename Executor, typename Allocator>
executor::executor(allocator_arg_t, const Allocator& a, Executor e)
: impl_(impl<Executor, Allocator>::create(e, a))
{
}
template <typename Function, typename Allocator>
void executor::dispatch(Function&& f,
const Allocator& a) const
{
impl_base* i = get_impl();
if (i->fast_dispatch_)
system_executor().dispatch(static_cast<Function&&>(f), a);
else
i->dispatch(function(static_cast<Function&&>(f), a));
}
template <typename Function, typename Allocator>
void executor::post(Function&& f,
const Allocator& a) const
{
get_impl()->post(function(static_cast<Function&&>(f), a));
}
template <typename Function, typename Allocator>
void executor::defer(Function&& f,
const Allocator& a) const
{
get_impl()->defer(function(static_cast<Function&&>(f), a));
}
template <typename Executor>
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 noexcept
{
return impl_ && impl_->target_type() == type_id<Executor>()
? static_cast<Executor*>(impl_->target()) : 0;
}
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(ASIO_NO_TS_EXECUTORS)
#endif // ASIO_IMPL_EXECUTOR_HPP

View File

@@ -0,0 +1,43 @@
//
// impl/executor.ipp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_EXECUTOR_IPP
#define ASIO_IMPL_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_NO_TS_EXECUTORS)
#include "asio/executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
bad_executor::bad_executor() noexcept
{
}
const char* bad_executor::what() const noexcept
{
return "bad executor";
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(ASIO_NO_TS_EXECUTORS)
#endif // ASIO_IMPL_EXECUTOR_IPP

View File

@@ -0,0 +1,343 @@
//
// impl/io_context.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_IO_CONTEXT_HPP
#define ASIO_IMPL_IO_CONTEXT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/config.hpp"
#include "asio/detail/completion_handler.hpp"
#include "asio/detail/executor_op.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_type_requirements.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"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Allocator>
io_context::io_context(allocator_arg_t, const Allocator& a)
: execution_context(std::allocator_arg, a, config_from_concurrency_hint()),
impl_(asio::make_service<impl_type>(*this, false))
{
}
template <typename Allocator>
io_context::io_context(allocator_arg_t,
const Allocator& a, int concurrency_hint)
: execution_context(std::allocator_arg, a,
config_from_concurrency_hint(concurrency_hint)),
impl_(asio::make_service<impl_type>(*this, false))
{
}
template <typename Allocator>
io_context::io_context(allocator_arg_t, const Allocator& a,
const execution_context::service_maker& initial_services)
: execution_context(std::allocator_arg, a, initial_services),
impl_(asio::make_service<impl_type>(*this, false))
{
}
#if !defined(GENERATING_DOCUMENTATION)
template <typename Service>
inline Service& use_service(io_context& ioc)
{
// Check that Service meets the necessary type requirements.
(void)static_cast<execution_context::service*>(static_cast<Service*>(0));
(void)static_cast<const execution_context::id*>(&Service::id);
return ioc.service_registry_->template use_service<Service>(ioc);
}
template <>
inline detail::io_context_impl& use_service<detail::io_context_impl>(
io_context& ioc)
{
return ioc.impl_;
}
#endif // !defined(GENERATING_DOCUMENTATION)
inline io_context::executor_type
io_context::get_executor() noexcept
{
return executor_type(*this);
}
template <typename Rep, typename Period>
std::size_t io_context::run_for(
const chrono::duration<Rep, Period>& rel_time)
{
return this->run_until(chrono::steady_clock::now() + rel_time);
}
template <typename Clock, typename Duration>
std::size_t io_context::run_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
std::size_t n = 0;
while (this->run_one_until(abs_time))
if (n != (std::numeric_limits<std::size_t>::max)())
++n;
return n;
}
template <typename Rep, typename Period>
std::size_t io_context::run_one_for(
const chrono::duration<Rep, Period>& rel_time)
{
return this->run_one_until(chrono::steady_clock::now() + rel_time);
}
template <typename Clock, typename Duration>
std::size_t io_context::run_one_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
typename Clock::time_point now = Clock::now();
while (now < abs_time)
{
typename Clock::duration rel_time = abs_time - now;
if (rel_time > chrono::seconds(1))
rel_time = chrono::seconds(1);
asio::error_code ec;
std::size_t s = impl_.wait_one(
static_cast<long>(chrono::duration_cast<
chrono::microseconds>(rel_time).count()), ec);
asio::detail::throw_error(ec);
if (s || impl_.stopped())
return s;
now = Clock::now();
}
return 0;
}
#if !defined(ASIO_NO_DEPRECATED)
template <typename Handler>
#if defined(GENERATING_DOCUMENTATION)
unspecified
#else
inline detail::wrapped_handler<io_context&, Handler>
#endif
io_context::wrap(Handler handler)
{
return detail::wrapped_handler<io_context&, Handler>(*this, handler);
}
#endif // !defined(ASIO_NO_DEPRECATED)
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
{
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;
}
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
{
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;
}
template <typename Allocator, uintptr_t Bits>
inline bool io_context::basic_executor_type<Allocator,
Bits>::running_in_this_thread() const noexcept
{
return context_ptr()->impl_.can_dispatch();
}
template <typename Allocator, uintptr_t Bits>
template <typename Function>
void io_context::basic_executor_type<Allocator, Bits>::execute(
Function&& f) 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 && context_ptr()->impl_.can_dispatch())
{
// 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)
}
// Allocate and construct an operation to wrap the function.
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;
}
#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();
}
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 Allocator, uintptr_t Bits>
inline void io_context::basic_executor_type<Allocator,
Bits>::on_work_finished() const noexcept
{
context_ptr()->impl_.work_finished();
}
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,
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, "dispatch"));
context_ptr()->impl_.post_immediate_completion(p.p, false);
p.v = p.p = 0;
}
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
{
// 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, "post"));
context_ptr()->impl_.post_immediate_completion(p.p, false);
p.v = p.p = 0;
}
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
{
// 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)
inline asio::io_context& io_context::service::get_io_context()
{
return static_cast<asio::io_context&>(context());
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_IO_CONTEXT_HPP

View File

@@ -0,0 +1,127 @@
//
// impl/io_context.ipp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_IO_CONTEXT_IPP
#define ASIO_IMPL_IO_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/config.hpp"
#include "asio/io_context.hpp"
#include "asio/detail/concurrency_hint.hpp"
#include "asio/detail/limits.hpp"
#include "asio/detail/service_registry.hpp"
#include "asio/detail/throw_error.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 {
io_context::io_context()
: execution_context(config_from_concurrency_hint()),
impl_(asio::make_service<impl_type>(*this, false))
{
}
io_context::io_context(int concurrency_hint)
: execution_context(config_from_concurrency_hint(concurrency_hint)),
impl_(asio::make_service<impl_type>(*this, false))
{
}
io_context::io_context(const execution_context::service_maker& initial_services)
: execution_context(initial_services),
impl_(asio::make_service<impl_type>(*this, false))
{
}
io_context::~io_context()
{
shutdown();
}
io_context::count_type io_context::run()
{
asio::error_code ec;
count_type s = impl_.run(ec);
asio::detail::throw_error(ec);
return s;
}
io_context::count_type io_context::run_one()
{
asio::error_code ec;
count_type s = impl_.run_one(ec);
asio::detail::throw_error(ec);
return s;
}
io_context::count_type io_context::poll()
{
asio::error_code ec;
count_type s = impl_.poll(ec);
asio::detail::throw_error(ec);
return s;
}
io_context::count_type io_context::poll_one()
{
asio::error_code ec;
count_type s = impl_.poll_one(ec);
asio::detail::throw_error(ec);
return s;
}
void io_context::stop()
{
impl_.stop();
}
bool io_context::stopped() const
{
return impl_.stopped();
}
void io_context::restart()
{
impl_.restart();
}
io_context::service::service(asio::io_context& owner)
: execution_context::service(owner)
{
}
io_context::service::~service()
{
}
void io_context::service::shutdown()
{
}
void io_context::service::notify_fork(io_context::fork_event)
{
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_IO_CONTEXT_IPP

View File

@@ -0,0 +1,45 @@
//
// impl/multiple_exceptions.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,170 @@
//
// impl/prepend.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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/initiation_base.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 : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
std::tuple<Values...> values, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
detail::prepend_handler<decay_t<Handler>, Values...>(
static_cast<Handler&&>(handler),
static_cast<std::tuple<Values...>&&>(values)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
std::tuple<Values...> values, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
detail::prepend_handler<decay_t<Handler>, Values...>(
static_cast<Handler&&>(handler),
static_cast<std::tuple<Values...>&&>(values)),
static_cast<Args&&>(args)...);
}
};
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

902
include/asio/impl/read.hpp Normal file
View File

@@ -0,0 +1,902 @@
//
// impl/read.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_READ_HPP
#define ASIO_IMPL_READ_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <algorithm>
#include "asio/associator.hpp"
#include "asio/buffer.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_cont_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"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail
{
template <typename SyncReadStream, typename MutableBufferSequence,
typename MutableBufferIterator, typename CompletionCondition>
std::size_t read_buffer_seq(SyncReadStream& s,
const MutableBufferSequence& buffers, const MutableBufferIterator&,
CompletionCondition completion_condition, asio::error_code& ec)
{
ec = asio::error_code();
asio::detail::consuming_buffers<mutable_buffer,
MutableBufferSequence, MutableBufferIterator> tmp(buffers);
while (!tmp.empty())
{
if (std::size_t max_size = detail::adapt_completion_condition_result(
completion_condition(ec, tmp.total_consumed())))
tmp.consume(s.read_some(tmp.prepare(max_size), ec));
else
break;
}
return tmp.total_consumed();
}
} // namespace detail
template <typename SyncReadStream, typename MutableBufferSequence,
typename CompletionCondition>
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_mutable_buffer_sequence<MutableBufferSequence>::value
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
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,
constraint_t<
is_mutable_buffer_sequence<MutableBufferSequence>::value
>)
{
asio::error_code ec;
std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
asio::detail::throw_error(ec, "read");
return bytes_transferred;
}
template <typename SyncReadStream, typename MutableBufferSequence>
inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
asio::error_code& ec,
constraint_t<
is_mutable_buffer_sequence<MutableBufferSequence>::value
>)
{
return read(s, buffers, transfer_all(), ec);
}
template <typename SyncReadStream, typename MutableBufferSequence,
typename CompletionCondition>
inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
CompletionCondition completion_condition,
constraint_t<
is_mutable_buffer_sequence<MutableBufferSequence>::value
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code ec;
std::size_t bytes_transferred = read(s, buffers,
static_cast<CompletionCondition&&>(completion_condition), ec);
asio::detail::throw_error(ec, "read");
return bytes_transferred;
}
#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
template <typename SyncReadStream, typename DynamicBuffer_v1,
typename CompletionCondition>
std::size_t read(SyncReadStream& s,
DynamicBuffer_v1&& buffers,
CompletionCondition completion_condition, 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
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
decay_t<DynamicBuffer_v1> b(
static_cast<DynamicBuffer_v1&&>(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 bytes_transferred = s.read_some(b.prepare(bytes_available), ec);
b.commit(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_v1>
inline std::size_t read(SyncReadStream& s,
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,
static_cast<DynamicBuffer_v1&&>(buffers), transfer_all(), ec);
asio::detail::throw_error(ec, "read");
return bytes_transferred;
}
template <typename SyncReadStream, typename DynamicBuffer_v1>
inline std::size_t read(SyncReadStream& s,
DynamicBuffer_v1&& buffers,
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
>)
{
return read(s, static_cast<DynamicBuffer_v1&&>(buffers),
transfer_all(), ec);
}
template <typename SyncReadStream, typename DynamicBuffer_v1,
typename CompletionCondition>
inline std::size_t read(SyncReadStream& s,
DynamicBuffer_v1&& buffers,
CompletionCondition completion_condition,
constraint_t<
is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
>,
constraint_t<
!is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code ec;
std::size_t bytes_transferred = read(s,
static_cast<DynamicBuffer_v1&&>(buffers),
static_cast<CompletionCondition&&>(completion_condition), ec);
asio::detail::throw_error(ec, "read");
return bytes_transferred;
}
#if !defined(ASIO_NO_EXTENSIONS)
#if !defined(ASIO_NO_IOSTREAM)
template <typename SyncReadStream, typename Allocator,
typename CompletionCondition>
inline std::size_t read(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
return read(s, basic_streambuf_ref<Allocator>(b),
static_cast<CompletionCondition&&>(completion_condition), ec);
}
template <typename SyncReadStream, typename Allocator>
inline std::size_t read(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b)
{
return read(s, basic_streambuf_ref<Allocator>(b));
}
template <typename SyncReadStream, typename Allocator>
inline std::size_t read(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
asio::error_code& ec)
{
return read(s, basic_streambuf_ref<Allocator>(b), ec);
}
template <typename SyncReadStream, typename Allocator,
typename CompletionCondition>
inline std::size_t read(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
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
>,
constraint_t<
is_completion_condition<CompletionCondition>::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
>,
constraint_t<
is_completion_condition<CompletionCondition>::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
{
template <typename AsyncReadStream, typename MutableBufferSequence,
typename MutableBufferIterator, typename CompletionCondition,
typename ReadHandler>
class read_op
: public base_from_cancellation_state<ReadHandler>,
base_from_completion_cond<CompletionCondition>
{
public:
read_op(AsyncReadStream& stream, const MutableBufferSequence& 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_(buffers),
start_(0),
handler_(static_cast<ReadHandler&&>(handler))
{
}
read_op(const read_op& other)
: base_from_cancellation_state<ReadHandler>(other),
base_from_completion_cond<CompletionCondition>(other),
stream_(other.stream_),
buffers_(other.buffers_),
start_(other.start_),
handler_(other.handler_)
{
}
read_op(read_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<buffers_type&&>(other.buffers_)),
start_(other.start_),
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;
switch (start_ = start)
{
case 1:
max_size = this->check_for_completion(ec, buffers_.total_consumed());
for (;;)
{
{
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());
if (max_size == 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&>(buffers_.total_consumed()));
}
}
//private:
typedef asio::detail::consuming_buffers<mutable_buffer,
MutableBufferSequence, MutableBufferIterator> buffers_type;
AsyncReadStream& stream_;
buffers_type buffers_;
int start_;
ReadHandler 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)
{
return this_handler->start_ == 0 ? true
: asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename AsyncReadStream, typename MutableBufferSequence,
typename MutableBufferIterator, typename CompletionCondition,
typename ReadHandler>
inline void start_read_op(AsyncReadStream& stream,
const MutableBufferSequence& buffers, const MutableBufferIterator&,
CompletionCondition& completion_condition, ReadHandler& handler)
{
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 <template <typename, typename> class Associator,
typename AsyncReadStream, typename MutableBufferSequence,
typename MutableBufferIterator, typename CompletionCondition,
typename ReadHandler, typename DefaultCandidate>
struct associator<Associator,
detail::read_op<AsyncReadStream, MutableBufferSequence,
MutableBufferIterator, CompletionCondition, ReadHandler>,
DefaultCandidate>
: Associator<ReadHandler, DefaultCandidate>
{
static typename Associator<ReadHandler, DefaultCandidate>::type get(
const detail::read_op<AsyncReadStream, MutableBufferSequence,
MutableBufferIterator, CompletionCondition, ReadHandler>& h) noexcept
{
return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::read_op<AsyncReadStream, MutableBufferSequence,
MutableBufferIterator, 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)
#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
namespace detail
{
template <typename AsyncReadStream, typename DynamicBuffer_v1,
typename CompletionCondition, typename ReadHandler>
class read_dynbuf_v1_op
: public base_from_cancellation_state<ReadHandler>,
base_from_completion_cond<CompletionCondition>
{
public:
template <typename BufferSequence>
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_(static_cast<BufferSequence&&>(buffers)),
start_(0),
total_transferred_(0),
handler_(static_cast<ReadHandler&&>(handler))
{
}
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_),
total_transferred_(other.total_transferred_),
handler_(other.handler_)
{
}
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_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
start_(other.start_),
total_transferred_(other.total_transferred_),
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, bytes_available;
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 (;;)
{
{
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);
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_v1 buffers_;
int start_;
std::size_t total_transferred_;
ReadHandler handler_;
};
template <typename AsyncReadStream, typename DynamicBuffer_v1,
typename CompletionCondition, typename ReadHandler>
inline bool asio_handler_is_continuation(
read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
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_v1
{
public:
typedef typename AsyncReadStream::executor_type executor_type;
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 <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>
{
static typename Associator<ReadHandler, DefaultCandidate>::type get(
const detail::read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
CompletionCondition, ReadHandler>& h) noexcept
{
return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
}
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 Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
#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)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_READ_HPP

View File

@@ -0,0 +1,562 @@
//
// impl/read_at.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_READ_AT_HPP
#define ASIO_IMPL_READ_AT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <algorithm>
#include "asio/associator.hpp"
#include "asio/buffer.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_cont_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"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail
{
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
typename MutableBufferIterator, typename CompletionCondition>
std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d,
uint64_t offset, const MutableBufferSequence& buffers,
const MutableBufferIterator&, CompletionCondition completion_condition,
asio::error_code& ec)
{
ec = asio::error_code();
asio::detail::consuming_buffers<mutable_buffer,
MutableBufferSequence, MutableBufferIterator> tmp(buffers);
while (!tmp.empty())
{
if (std::size_t max_size = detail::adapt_completion_condition_result(
completion_condition(ec, tmp.total_consumed())))
{
tmp.consume(d.read_some_at(offset + tmp.total_consumed(),
tmp.prepare(max_size), ec));
}
else
break;
}
return tmp.total_consumed();
}
} // namespace detail
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
return detail::read_at_buffer_sequence(d, offset, buffers,
asio::buffer_sequence_begin(buffers),
static_cast<CompletionCondition&&>(completion_condition), ec);
}
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t bytes_transferred = read_at(
d, offset, buffers, transfer_all(), ec);
asio::detail::throw_error(ec, "read_at");
return bytes_transferred;
}
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return read_at(d, offset, buffers, transfer_all(), ec);
}
template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
typename CompletionCondition>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code 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;
}
#if !defined(ASIO_NO_EXTENSIONS)
#if !defined(ASIO_NO_IOSTREAM)
template <typename SyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition>
std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
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 = read_size_helper(b, max_size);
while (bytes_available > 0)
{
std::size_t bytes_transferred = d.read_some_at(
offset + total_transferred, b.prepare(bytes_available), ec);
b.commit(bytes_transferred);
total_transferred += bytes_transferred;
max_size = detail::adapt_completion_condition_result(
completion_condition(ec, total_transferred));
bytes_available = read_size_helper(b, max_size);
}
return total_transferred;
}
template <typename SyncRandomAccessReadDevice, typename Allocator>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b)
{
asio::error_code ec;
std::size_t bytes_transferred = read_at(
d, offset, b, transfer_all(), ec);
asio::detail::throw_error(ec, "read_at");
return bytes_transferred;
}
template <typename SyncRandomAccessReadDevice, typename Allocator>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b,
asio::error_code& ec)
{
return read_at(d, offset, b, transfer_all(), ec);
}
template <typename SyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition>
inline std::size_t read_at(SyncRandomAccessReadDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code 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;
}
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // !defined(ASIO_NO_EXTENSIONS)
namespace detail
{
template <typename AsyncRandomAccessReadDevice,
typename MutableBufferSequence, typename MutableBufferIterator,
typename CompletionCondition, typename ReadHandler>
class read_at_op
: 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)
: 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_(static_cast<ReadHandler&&>(handler))
{
}
read_at_op(const read_at_op& other)
: base_from_cancellation_state<ReadHandler>(other),
base_from_completion_cond<CompletionCondition>(other),
device_(other.device_),
offset_(other.offset_),
buffers_(other.buffers_),
start_(other.start_),
handler_(other.handler_)
{
}
read_at_op(read_at_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)),
device_(other.device_),
offset_(other.offset_),
buffers_(static_cast<buffers_type&&>(other.buffers_)),
start_(other.start_),
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;
switch (start_ = start)
{
case 1:
max_size = this->check_for_completion(ec, buffers_.total_consumed());
for (;;)
{
{
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());
if (max_size == 0)
break;
if (this->cancelled() != cancellation_type::none)
{
ec = asio::error::operation_aborted;
break;
}
}
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_;
buffers_type buffers_;
int start_;
ReadHandler 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)
{
return this_handler->start_ == 0 ? true
: asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename AsyncRandomAccessReadDevice,
typename MutableBufferSequence, typename MutableBufferIterator,
typename CompletionCondition, typename ReadHandler>
inline void start_read_at_op(AsyncRandomAccessReadDevice& d,
uint64_t offset, const MutableBufferSequence& buffers,
const MutableBufferIterator&, CompletionCondition& completion_condition,
ReadHandler& handler)
{
detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
MutableBufferIterator, CompletionCondition, ReadHandler>(
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 <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>,
DefaultCandidate>
: Associator<ReadHandler, DefaultCandidate>
{
static typename Associator<ReadHandler, DefaultCandidate>::type get(
const detail::read_at_op<AsyncRandomAccessReadDevice,
MutableBufferSequence, MutableBufferIterator,
CompletionCondition, ReadHandler>& h) noexcept
{
return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::read_at_op<AsyncRandomAccessReadDevice,
MutableBufferSequence, MutableBufferIterator,
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)
#if !defined(ASIO_NO_EXTENSIONS)
#if !defined(ASIO_NO_IOSTREAM)
namespace detail
{
template <typename AsyncRandomAccessReadDevice, typename Allocator,
typename CompletionCondition, typename ReadHandler>
class read_at_streambuf_op
: 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)
: 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_(static_cast<ReadHandler&&>(handler))
{
}
read_at_streambuf_op(const read_at_streambuf_op& other)
: base_from_cancellation_state<ReadHandler>(other),
base_from_completion_cond<CompletionCondition>(other),
device_(other.device_),
offset_(other.offset_),
streambuf_(other.streambuf_),
start_(other.start_),
total_transferred_(other.total_transferred_),
handler_(other.handler_)
{
}
read_at_streambuf_op(read_at_streambuf_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)),
device_(other.device_),
offset_(other.offset_),
streambuf_(other.streambuf_),
start_(other.start_),
total_transferred_(other.total_transferred_),
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, bytes_available;
switch (start_ = start)
{
case 1:
max_size = this->check_for_completion(ec, total_transferred_);
bytes_available = read_size_helper(streambuf_, max_size);
for (;;)
{
{
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);
max_size = this->check_for_completion(ec, total_transferred_);
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;
}
}
static_cast<ReadHandler&&>(handler_)(
static_cast<const asio::error_code&>(ec),
static_cast<const std::size_t&>(total_transferred_));
}
}
//private:
AsyncRandomAccessReadDevice& device_;
uint64_t offset_;
asio::basic_streambuf<Allocator>& streambuf_;
int start_;
std::size_t total_transferred_;
ReadHandler 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)
{
return this_handler->start_ == 0 ? true
: asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename AsyncRandomAccessReadDevice>
class initiate_async_read_at_streambuf
{
public:
typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
explicit initiate_async_read_at_streambuf(
AsyncRandomAccessReadDevice& device)
: device_(device)
{
}
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, 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 <template <typename, typename> class Associator,
typename AsyncRandomAccessReadDevice, typename Executor,
typename CompletionCondition, typename ReadHandler,
typename DefaultCandidate>
struct associator<Associator,
detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
Executor, CompletionCondition, ReadHandler>,
DefaultCandidate>
: Associator<ReadHandler, DefaultCandidate>
{
static typename Associator<ReadHandler, DefaultCandidate>::type get(
const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
Executor, CompletionCondition, ReadHandler>& h) noexcept
{
return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
Executor, 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)
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // !defined(ASIO_NO_EXTENSIONS)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_READ_AT_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,287 @@
// impl/redirect_error.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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/associated_executor.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_cont_helpers.hpp"
#include "asio/detail/initiation_base.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>
{
template <typename Initiation>
struct init_wrapper : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
asio::error_code* ec, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
detail::redirect_error_handler<decay_t<Handler>>(
*ec, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
asio::error_code* ec, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
detail::redirect_error_handler<decay_t<Handler>>(
*ec, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
};
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::redirect_error_signature<Signature>::type>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.token_, &token.ec_, static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value,
const CompletionToken, CompletionToken>,
typename detail::redirect_error_signature<Signature>::type>(
init_wrapper<decay_t<Initiation>>(
static_cast<Initiation&&>(initiation)),
token.token_, &token.ec_, 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);
}
};
template <typename... Signatures>
struct async_result<partial_redirect_error, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
redirect_error_t<
default_completion_token_t<associated_executor_t<Initiation>>>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.ec_),
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
redirect_error_t<
default_completion_token_t<associated_executor_t<Initiation>>>(
default_completion_token_t<associated_executor_t<Initiation>>{},
token.ec_),
static_cast<Args&&>(args)...);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_REDIRECT_ERROR_HPP

View File

@@ -0,0 +1,59 @@
//
// impl/serial_port_base.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 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_IMPL_SERIAL_PORT_BASE_HPP
#define ASIO_IMPL_SERIAL_PORT_BASE_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 {
inline serial_port_base::baud_rate::baud_rate(unsigned int rate)
: value_(rate)
{
}
inline unsigned int serial_port_base::baud_rate::value() const
{
return value_;
}
inline serial_port_base::flow_control::type
serial_port_base::flow_control::value() const
{
return value_;
}
inline serial_port_base::parity::type serial_port_base::parity::value() const
{
return value_;
}
inline serial_port_base::stop_bits::type
serial_port_base::stop_bits::value() const
{
return value_;
}
inline unsigned int serial_port_base::character_size::value() const
{
return value_;
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP

View File

@@ -0,0 +1,554 @@
//
// impl/serial_port_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 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_IMPL_SERIAL_PORT_BASE_IPP
#define ASIO_IMPL_SERIAL_PORT_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_SERIAL_PORT)
#include <stdexcept>
#include "asio/error.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/detail/throw_exception.hpp"
#if defined(GENERATING_DOCUMENTATION)
# define ASIO_OPTION_STORAGE implementation_defined
#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
# define ASIO_OPTION_STORAGE DCB
#else
# define ASIO_OPTION_STORAGE termios
#endif
#include "asio/detail/push_options.hpp"
namespace asio {
ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
storage.BaudRate = value_;
#else
speed_t baud;
switch (value_)
{
// Do POSIX-specified rates first.
case 0: baud = B0; break;
case 50: baud = B50; break;
case 75: baud = B75; break;
case 110: baud = B110; break;
case 134: baud = B134; break;
case 150: baud = B150; break;
case 200: baud = B200; break;
case 300: baud = B300; break;
case 600: baud = B600; break;
case 1200: baud = B1200; break;
case 1800: baud = B1800; break;
case 2400: baud = B2400; break;
case 4800: baud = B4800; break;
case 9600: baud = B9600; break;
case 19200: baud = B19200; break;
case 38400: baud = B38400; break;
// And now the extended ones conditionally.
# ifdef B7200
case 7200: baud = B7200; break;
# endif
# ifdef B14400
case 14400: baud = B14400; break;
# endif
# ifdef B57600
case 57600: baud = B57600; break;
# endif
# ifdef B115200
case 115200: baud = B115200; break;
# endif
# ifdef B230400
case 230400: baud = B230400; break;
# endif
# ifdef B460800
case 460800: baud = B460800; break;
# endif
# ifdef B500000
case 500000: baud = B500000; break;
# endif
# ifdef B576000
case 576000: baud = B576000; break;
# endif
# ifdef B921600
case 921600: baud = B921600; break;
# endif
# ifdef B1000000
case 1000000: baud = B1000000; break;
# endif
# ifdef B1152000
case 1152000: baud = B1152000; break;
# endif
# ifdef B2000000
case 2000000: baud = B2000000; break;
# endif
# ifdef B3000000
case 3000000: baud = B3000000; break;
# endif
# ifdef B3500000
case 3500000: baud = B3500000; break;
# endif
# ifdef B4000000
case 4000000: baud = B4000000; break;
# endif
default:
ec = asio::error::invalid_argument;
ASIO_SYNC_OP_VOID_RETURN(ec);
}
# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
::cfsetspeed(&storage, baud);
# else
::cfsetispeed(&storage, baud);
::cfsetospeed(&storage, baud);
# endif
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
ASIO_SYNC_OP_VOID serial_port_base::baud_rate::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
value_ = storage.BaudRate;
#else
speed_t baud = ::cfgetospeed(&storage);
switch (baud)
{
// First do those specified by POSIX.
case B0: value_ = 0; break;
case B50: value_ = 50; break;
case B75: value_ = 75; break;
case B110: value_ = 110; break;
case B134: value_ = 134; break;
case B150: value_ = 150; break;
case B200: value_ = 200; break;
case B300: value_ = 300; break;
case B600: value_ = 600; break;
case B1200: value_ = 1200; break;
case B1800: value_ = 1800; break;
case B2400: value_ = 2400; break;
case B4800: value_ = 4800; break;
case B9600: value_ = 9600; break;
case B19200: value_ = 19200; break;
case B38400: value_ = 38400; break;
// Now conditionally handle a bunch of extended rates.
# ifdef B7200
case B7200: value_ = 7200; break;
# endif
# ifdef B14400
case B14400: value_ = 14400; break;
# endif
# ifdef B57600
case B57600: value_ = 57600; break;
# endif
# ifdef B115200
case B115200: value_ = 115200; break;
# endif
# ifdef B230400
case B230400: value_ = 230400; break;
# endif
# ifdef B460800
case B460800: value_ = 460800; break;
# endif
# ifdef B500000
case B500000: value_ = 500000; break;
# endif
# ifdef B576000
case B576000: value_ = 576000; break;
# endif
# ifdef B921600
case B921600: value_ = 921600; break;
# endif
# ifdef B1000000
case B1000000: value_ = 1000000; break;
# endif
# ifdef B1152000
case B1152000: value_ = 1152000; break;
# endif
# ifdef B2000000
case B2000000: value_ = 2000000; break;
# endif
# ifdef B3000000
case B3000000: value_ = 3000000; break;
# endif
# ifdef B3500000
case B3500000: value_ = 3500000; break;
# endif
# ifdef B4000000
case B4000000: value_ = 4000000; break;
# endif
default:
value_ = 0;
ec = asio::error::invalid_argument;
ASIO_SYNC_OP_VOID_RETURN(ec);
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
serial_port_base::flow_control::flow_control(
serial_port_base::flow_control::type t)
: value_(t)
{
if (t != none && t != software && t != hardware)
{
std::out_of_range ex("invalid flow_control value");
asio::detail::throw_exception(ex);
}
}
ASIO_SYNC_OP_VOID serial_port_base::flow_control::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
storage.fOutxCtsFlow = FALSE;
storage.fOutxDsrFlow = FALSE;
storage.fTXContinueOnXoff = TRUE;
storage.fDtrControl = DTR_CONTROL_ENABLE;
storage.fDsrSensitivity = FALSE;
storage.fOutX = FALSE;
storage.fInX = FALSE;
storage.fRtsControl = RTS_CONTROL_ENABLE;
switch (value_)
{
case none:
break;
case software:
storage.fOutX = TRUE;
storage.fInX = TRUE;
break;
case hardware:
storage.fOutxCtsFlow = TRUE;
storage.fRtsControl = RTS_CONTROL_HANDSHAKE;
break;
default:
break;
}
#else
switch (value_)
{
case none:
storage.c_iflag &= ~(IXOFF | IXON);
# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
storage.c_cflag &= ~CRTSCTS;
# elif defined(__QNXNTO__)
storage.c_cflag &= ~(IHFLOW | OHFLOW);
# endif
break;
case software:
storage.c_iflag |= IXOFF | IXON;
# 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) || defined(_DEFAULT_SOURCE)
storage.c_iflag &= ~(IXOFF | IXON);
storage.c_cflag |= CRTSCTS;
break;
# elif defined(__QNXNTO__)
storage.c_iflag &= ~(IXOFF | IXON);
storage.c_cflag |= (IHFLOW | OHFLOW);
break;
# else
ec = asio::error::operation_not_supported;
ASIO_SYNC_OP_VOID_RETURN(ec);
# endif
default:
break;
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
ASIO_SYNC_OP_VOID serial_port_base::flow_control::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
if (storage.fOutX && storage.fInX)
{
value_ = software;
}
else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE)
{
value_ = hardware;
}
else
{
value_ = none;
}
#else
if (storage.c_iflag & (IXOFF | IXON))
{
value_ = software;
}
# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
else if (storage.c_cflag & CRTSCTS)
{
value_ = hardware;
}
# elif defined(__QNXNTO__)
else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW)
{
value_ = hardware;
}
# endif
else
{
value_ = none;
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
serial_port_base::parity::parity(serial_port_base::parity::type t)
: value_(t)
{
if (t != none && t != odd && t != even)
{
std::out_of_range ex("invalid parity value");
asio::detail::throw_exception(ex);
}
}
ASIO_SYNC_OP_VOID serial_port_base::parity::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
switch (value_)
{
case none:
storage.fParity = FALSE;
storage.Parity = NOPARITY;
break;
case odd:
storage.fParity = TRUE;
storage.Parity = ODDPARITY;
break;
case even:
storage.fParity = TRUE;
storage.Parity = EVENPARITY;
break;
default:
break;
}
#else
switch (value_)
{
case none:
storage.c_iflag |= IGNPAR;
storage.c_cflag &= ~(PARENB | PARODD);
break;
case even:
storage.c_iflag &= ~(IGNPAR | PARMRK);
storage.c_iflag |= INPCK;
storage.c_cflag |= PARENB;
storage.c_cflag &= ~PARODD;
break;
case odd:
storage.c_iflag &= ~(IGNPAR | PARMRK);
storage.c_iflag |= INPCK;
storage.c_cflag |= (PARENB | PARODD);
break;
default:
break;
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
ASIO_SYNC_OP_VOID serial_port_base::parity::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
if (storage.Parity == EVENPARITY)
{
value_ = even;
}
else if (storage.Parity == ODDPARITY)
{
value_ = odd;
}
else
{
value_ = none;
}
#else
if (storage.c_cflag & PARENB)
{
if (storage.c_cflag & PARODD)
{
value_ = odd;
}
else
{
value_ = even;
}
}
else
{
value_ = none;
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
serial_port_base::stop_bits::stop_bits(
serial_port_base::stop_bits::type t)
: value_(t)
{
if (t != one && t != onepointfive && t != two)
{
std::out_of_range ex("invalid stop_bits value");
asio::detail::throw_exception(ex);
}
}
ASIO_SYNC_OP_VOID serial_port_base::stop_bits::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
switch (value_)
{
case one:
storage.StopBits = ONESTOPBIT;
break;
case onepointfive:
storage.StopBits = ONE5STOPBITS;
break;
case two:
storage.StopBits = TWOSTOPBITS;
break;
default:
break;
}
#else
switch (value_)
{
case one:
storage.c_cflag &= ~CSTOPB;
break;
case two:
storage.c_cflag |= CSTOPB;
break;
default:
ec = asio::error::operation_not_supported;
ASIO_SYNC_OP_VOID_RETURN(ec);
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
ASIO_SYNC_OP_VOID serial_port_base::stop_bits::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
if (storage.StopBits == ONESTOPBIT)
{
value_ = one;
}
else if (storage.StopBits == ONE5STOPBITS)
{
value_ = onepointfive;
}
else if (storage.StopBits == TWOSTOPBITS)
{
value_ = two;
}
else
{
value_ = one;
}
#else
value_ = (storage.c_cflag & CSTOPB) ? two : one;
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
serial_port_base::character_size::character_size(unsigned int t)
: value_(t)
{
if (t < 5 || t > 8)
{
std::out_of_range ex("invalid character_size value");
asio::detail::throw_exception(ex);
}
}
ASIO_SYNC_OP_VOID serial_port_base::character_size::store(
ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
storage.ByteSize = value_;
#else
storage.c_cflag &= ~CSIZE;
switch (value_)
{
case 5: storage.c_cflag |= CS5; break;
case 6: storage.c_cflag |= CS6; break;
case 7: storage.c_cflag |= CS7; break;
case 8: storage.c_cflag |= CS8; break;
default: break;
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
ASIO_SYNC_OP_VOID serial_port_base::character_size::load(
const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)
{
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
value_ = storage.ByteSize;
#else
if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; }
else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; }
else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; }
else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; }
else
{
// Hmmm, use 8 for now.
value_ = 8;
}
#endif
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#undef ASIO_OPTION_STORAGE
#endif // defined(ASIO_HAS_SERIAL_PORT)
#endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP

1115
include/asio/impl/spawn.hpp Normal file

File diff suppressed because it is too large Load Diff

96
include/asio/impl/src.hpp Normal file
View File

@@ -0,0 +1,96 @@
//
// impl/src.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_SRC_HPP
#define ASIO_IMPL_SRC_HPP
#define ASIO_SOURCE
#include "asio/detail/config.hpp"
#if defined(ASIO_HEADER_ONLY)
# 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/awaitable.ipp"
#include "asio/impl/cancellation_signal.ipp"
#include "asio/impl/config.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/io_context.ipp"
#include "asio/impl/multiple_exceptions.ipp"
#include "asio/impl/serial_port_base.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"
#include "asio/detail/impl/dev_poll_reactor.ipp"
#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_socket_service_base.ipp"
#include "asio/detail/impl/resolver_service_base.ipp"
#include "asio/detail/impl/resolver_thread_pool.ipp"
#include "asio/detail/impl/scheduler.ipp"
#include "asio/detail/impl/select_reactor.ipp"
#include "asio/detail/impl/service_registry.ipp"
#include "asio/detail/impl/signal_set_service.ipp"
#include "asio/detail/impl/socket_ops.ipp"
#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_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"
#include "asio/detail/impl/win_iocp_socket_service_base.ipp"
#include "asio/detail/impl/win_event.ipp"
#include "asio/detail/impl/win_mutex.ipp"
#include "asio/detail/impl/win_object_handle_service.ipp"
#include "asio/detail/impl/win_static_mutex.ipp"
#include "asio/detail/impl/win_thread.ipp"
#include "asio/detail/impl/win_tss_ptr.ipp"
#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"
#include "asio/ip/impl/address_v6.ipp"
#include "asio/ip/impl/host_name.ipp"
#include "asio/ip/impl/network_v4.ipp"
#include "asio/ip/impl/network_v6.ipp"
#include "asio/ip/detail/impl/endpoint.ipp"
#include "asio/local/detail/impl/endpoint.ipp"
#endif // ASIO_IMPL_SRC_HPP

View File

@@ -0,0 +1,34 @@
//
// impl/system_context.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,93 @@
//
// impl/system_context.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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, false))),
threads_(std::allocator<void>())
{
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

View File

@@ -0,0 +1,179 @@
//
// impl/system_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_HPP
#define ASIO_IMPL_SYSTEM_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/executor_op.hpp"
#include "asio/detail/global.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/system_context.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Blocking, typename Relationship, typename Allocator>
inline system_context&
basic_system_executor<Blocking, Relationship, Allocator>::query(
execution::context_t) noexcept
{
return detail::global<system_context>();
}
template <typename Blocking, typename Relationship, typename Allocator>
inline std::size_t
basic_system_executor<Blocking, Relationship, Allocator>::query(
execution::occupancy_t) const noexcept
{
return detail::global<system_context>().num_threads_;
}
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
{
// 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;
}
#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>();
}
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<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"));
ctx.scheduler_.post_immediate_completion(p.p, false);
p.v = p.p = 0;
}
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
{
system_context& ctx = detail::global<system_context>();
// Allocate and construct an operation to wrap the function.
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"));
ctx.scheduler_.post_immediate_completion(p.p, true);
p.v = p.p = 0;
}
#endif // !defined(ASIO_NO_TS_EXECUTORS)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_SYSTEM_EXECUTOR_HPP

View File

@@ -0,0 +1,319 @@
//
// impl/thread_pool.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_THREAD_POOL_HPP
#define ASIO_IMPL_THREAD_POOL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/config.hpp"
#include "asio/detail/blocking_executor_op.hpp"
#include "asio/detail/executor_op.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_NO_TS_EXECUTORS)
template <typename Allocator>
thread_pool::thread_pool(allocator_arg_t, const Allocator& a)
: execution_context(std::allocator_arg, a),
scheduler_(asio::make_service<detail::scheduler>(*this, false)),
threads_(allocator<void>(*this)),
num_threads_(default_thread_pool_size()),
joinable_(true)
{
start();
}
#endif // !defined(ASIO_NO_TS_EXECUTORS)
template <typename Allocator>
thread_pool::thread_pool(allocator_arg_t,
const Allocator& a, std::size_t num_threads)
: execution_context(std::allocator_arg, a,
config_from_concurrency_hint(num_threads == 1 ? 1 : 0)),
scheduler_(asio::make_service<detail::scheduler>(*this, false)),
threads_(allocator<void>(*this)),
num_threads_(clamp_thread_pool_size(num_threads)),
joinable_(true)
{
start();
}
template <typename Allocator>
thread_pool::thread_pool(allocator_arg_t,
const Allocator& a, std::size_t num_threads,
const execution_context::service_maker& initial_services)
: execution_context(std::allocator_arg, a, initial_services),
scheduler_(asio::make_service<detail::scheduler>(*this, false)),
threads_(allocator<void>(*this)),
num_threads_(clamp_thread_pool_size(num_threads)),
joinable_(true)
{
start();
}
inline thread_pool::executor_type
thread_pool::get_executor() noexcept
{
return executor_type(*this);
}
inline thread_pool::executor_type
thread_pool::executor() noexcept
{
return executor_type(*this);
}
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
{
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;
}
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
{
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 Allocator, unsigned int Bits>
inline bool thread_pool::basic_executor_type<Allocator,
Bits>::running_in_this_thread() const noexcept
{
return 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())
{
// 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 (...)
{
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, 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 ((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,
(bits_ & relationship_continuation) != 0);
p.v = p.p = 0;
}
template <typename Allocator, unsigned int Bits>
template <typename Function>
void thread_pool::basic_executor_type<Allocator,
Bits>::do_execute(Function&& f, true_type) const
{
// 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 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, 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, "dispatch"));
pool_->scheduler_.post_immediate_completion(p.p, false);
p.v = p.p = 0;
}
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
{
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, "post"));
pool_->scheduler_.post_immediate_completion(p.p, false);
p.v = p.p = 0;
}
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
{
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
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_THREAD_POOL_HPP

View File

@@ -0,0 +1,145 @@
//
// impl/thread_pool.ipp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_THREAD_POOL_IPP
#define ASIO_IMPL_THREAD_POOL_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#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"
namespace asio {
struct thread_pool::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)
}
};
#if !defined(ASIO_NO_TS_EXECUTORS)
long thread_pool::default_thread_pool_size()
{
std::size_t num_threads = detail::thread::hardware_concurrency() * 2;
num_threads = num_threads == 0 ? 2 : num_threads;
return static_cast<long>(num_threads);
}
thread_pool::thread_pool()
: scheduler_(asio::make_service<detail::scheduler>(*this, false)),
threads_(allocator<void>(*this)),
num_threads_(default_thread_pool_size()),
joinable_(true)
{
start();
}
#endif // !defined(ASIO_NO_TS_EXECUTORS)
long thread_pool::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);
}
thread_pool::thread_pool(std::size_t num_threads)
: execution_context(config_from_concurrency_hint(num_threads == 1 ? 1 : 0)),
scheduler_(asio::make_service<detail::scheduler>(*this, false)),
threads_(allocator<void>(*this)),
num_threads_(clamp_thread_pool_size(num_threads)),
joinable_(true)
{
start();
}
thread_pool::thread_pool(std::size_t num_threads,
const execution_context::service_maker& initial_services)
: execution_context(initial_services),
scheduler_(asio::make_service<detail::scheduler>(*this, false)),
threads_(allocator<void>(*this)),
num_threads_(clamp_thread_pool_size(num_threads)),
joinable_(true)
{
start();
}
thread_pool::~thread_pool()
{
stop();
join();
shutdown();
}
void thread_pool::start()
{
scheduler_.work_started();
thread_function f = { &scheduler_ };
threads_.create_threads(f, static_cast<std::size_t>(num_threads_));
}
void thread_pool::stop()
{
scheduler_.stop();
}
void thread_pool::attach()
{
++num_threads_;
thread_function f = { &scheduler_ };
f();
}
void thread_pool::join()
{
if (joinable_)
{
joinable_ = false;
scheduler_.work_finished();
threads_.join();
}
}
void thread_pool::wait()
{
join();
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_THREAD_POOL_IPP

View File

@@ -0,0 +1,234 @@
//
// impl/use_awaitable.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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/disposition.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, typename T>
class awaitable_handler<Executor, T>
: public awaitable_handler_base<Executor,
conditional_t<is_disposition<T>::value, void, T>>
{
public:
using awaitable_handler_base<Executor,
conditional_t<is_disposition<T>::value, void, T>>
::awaitable_handler_base;
template <typename Arg>
void operator()(Arg&& arg)
{
this->frame()->attach_thread(this);
if constexpr (is_disposition<T>::value)
{
if (arg == no_error)
this->frame()->return_void();
else
this->frame()->set_disposition(arg);
}
else
this->frame()->return_value(std::forward<Arg>(arg));
this->frame()->clear_cancellation_slot();
this->frame()->pop_frame();
this->pump();
}
};
template <typename Executor, typename T0, typename T1>
class awaitable_handler<Executor, T0, T1>
: public awaitable_handler_base<Executor,
conditional_t<is_disposition<T0>::value, T1, std::tuple<T0, T1>>>
{
public:
using awaitable_handler_base<Executor,
conditional_t<is_disposition<T0>::value, T1, std::tuple<T0, T1>>>
::awaitable_handler_base;
template <typename Arg0, typename Arg1>
void operator()(Arg0&& arg0, Arg1&& arg1)
{
this->frame()->attach_thread(this);
if constexpr (is_disposition<T0>::value)
{
if (arg0 == no_error)
this->frame()->return_value(std::forward<Arg1>(arg1));
else
this->frame()->set_disposition(std::forward<Arg0>(arg0));
}
else
{
this->frame()->return_values(std::forward<Arg0>(arg0),
std::forward<Arg1>(arg1));
}
this->frame()->clear_cancellation_slot();
this->frame()->pop_frame();
this->pump();
}
};
template <typename Executor, typename T0, typename... Ts>
class awaitable_handler<Executor, T0, Ts...>
: public awaitable_handler_base<Executor,
conditional_t<is_disposition<T0>::value,
std::tuple<Ts...>, std::tuple<T0, Ts...>>>
{
public:
using awaitable_handler_base<Executor,
conditional_t<is_disposition<T0>::value,
std::tuple<Ts...>, std::tuple<T0, Ts...>>>
::awaitable_handler_base;
template <typename Arg0, typename... Args>
void operator()(Arg0&& arg0, Args&&... args)
{
this->frame()->attach_thread(this);
if constexpr (is_disposition<T0>::value)
{
if (arg0 == no_error)
this->frame()->return_values(std::forward<Args>(args)...);
else
this->frame()->set_disposition(std::forward<Arg0>(arg0));
}
else
{
this->frame()->return_values(std::forward<Arg0>(arg0),
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) && !defined(__clang__)
co_return dummy_return<typename return_type::value_type>();
#endif // defined(_MSC_VER) && !defined(__clang__)
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_USE_AWAITABLE_HPP

View File

@@ -0,0 +1,642 @@
//
// impl/use_future.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_FUTURE_HPP
#define ASIO_IMPL_USE_FUTURE_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/async_result.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/dispatch.hpp"
#include "asio/disposition.hpp"
#include "asio/execution.hpp"
#include "asio/packaged_task.hpp"
#include "asio/system_error.hpp"
#include "asio/system_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename T, typename F, typename... Args>
inline void promise_invoke_and_set(std::promise<T>& p,
F& f, Args&&... args)
{
#if !defined(ASIO_NO_EXCEPTIONS)
try
#endif // !defined(ASIO_NO_EXCEPTIONS)
{
p.set_value(f(static_cast<Args&&>(args)...));
}
#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, Args&&... args)
{
#if !defined(ASIO_NO_EXCEPTIONS)
try
#endif // !defined(ASIO_NO_EXCEPTIONS)
{
f(static_cast<Args&&>(args)...);
p.set_value();
}
#if !defined(ASIO_NO_EXCEPTIONS)
catch (...)
{
p.set_exception(std::current_exception());
}
#endif // !defined(ASIO_NO_EXCEPTIONS)
}
// 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,
F&& f)
: p_(p), f_(static_cast<F&&>(f))
{
}
void operator()()
{
#if !defined(ASIO_NO_EXCEPTIONS)
try
#endif // !defined(ASIO_NO_EXCEPTIONS)
{
f_();
}
#if !defined(ASIO_NO_EXCEPTIONS)
catch (...)
{
p_->set_exception(std::current_exception());
}
#endif // !defined(ASIO_NO_EXCEPTIONS)
}
private:
shared_ptr<std::promise<T>> p_;
decay_t<F> f_;
};
// An executor that adapts the system_executor to capture any exception thrown
// by a submitted function object and save it into a promise.
template <typename T, typename Blocking = execution::blocking_t::possibly_t>
class promise_executor
{
public:
explicit promise_executor(const shared_ptr<std::promise<T>>& p)
: p_(p)
{
}
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 noexcept {}
void on_work_finished() const noexcept {}
template <typename F, typename A>
void dispatch(F&& f, const A&) const
{
promise_invoker<T, F>(p_, static_cast<F&&>(f))();
}
template <typename F, typename A>
void post(F&& f, const A& a) const
{
system_executor().post(
promise_invoker<T, F>(p_, static_cast<F&&>(f)), a);
}
template <typename F, typename A>
void defer(F&& f, const A& a) const
{
system_executor().defer(
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) noexcept
{
return a.p_ == b.p_;
}
friend bool operator!=(const promise_executor& a,
const promise_executor& b) noexcept
{
return a.p_ != b.p_;
}
private:
shared_ptr<std::promise<T>> p_;
};
// The base class for all completion handlers that create promises.
template <typename T>
class promise_creator
{
public:
typedef promise_executor<T> executor_type;
executor_type get_executor() const noexcept
{
return executor_type(p_);
}
typedef std::future<T> future_type;
future_type get_future()
{
return p_->get_future();
}
protected:
template <typename Allocator>
void create_promise(const Allocator& 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_;
};
// For completion signature void().
class promise_handler_0
: public promise_creator<void>
{
public:
void operator()()
{
this->p_->set_value();
}
};
// For completion signature void(disposition auto).
template <typename Disposition>
class promise_handler_d_0
: public promise_creator<void>
{
public:
void operator()(Disposition d)
{
if (d != no_error)
{
this->p_->set_exception(
(to_exception_ptr)(static_cast<Disposition&&>(d)));
}
else
{
this->p_->set_value();
}
}
};
// For completion signature void(T).
template <typename T>
class promise_handler_1
: public promise_creator<T>
{
public:
template <typename Arg>
void operator()(Arg&& arg)
{
this->p_->set_value(static_cast<Arg&&>(arg));
}
};
// For completion signature void(disposition auto, T).
template <typename Disposition, typename T>
class promise_handler_d_1
: public promise_creator<T>
{
public:
template <typename Arg>
void operator()(Disposition d, Arg&& arg)
{
if (d != no_error)
{
this->p_->set_exception(
(to_exception_ptr)(static_cast<Disposition&&>(d)));
}
else
this->p_->set_value(static_cast<Arg&&>(arg));
}
};
// For completion signature void(T1, ..., Tn);
template <typename T>
class promise_handler_n
: public promise_creator<T>
{
public:
template <typename... Args>
void operator()(Args&&... args)
{
this->p_->set_value(
std::forward_as_tuple(
static_cast<Args&&>(args)...));
}
};
// For completion signature void(error_code, T1, ..., Tn);
template <typename Disposition, typename T>
class promise_handler_d_n
: public promise_creator<T>
{
public:
template <typename... Args>
void operator()(Disposition d, Args&&... args)
{
if (d != no_error)
{
this->p_->set_exception(
(to_exception_ptr)(static_cast<Disposition&&>(d)));
}
else
{
this->p_->set_value(
std::forward_as_tuple(
static_cast<Args&&>(args)...));
}
}
};
// Helper template to choose the appropriate concrete promise handler
// implementation based on the supplied completion signature.
template <typename, typename = void> class promise_handler_selector;
template <>
class promise_handler_selector<void()>
: public promise_handler_0 {};
template <typename Arg>
class promise_handler_selector<void(Arg),
enable_if_t<is_disposition<Arg>::value>>
: public promise_handler_d_0<Arg> {};
template <typename Arg>
class promise_handler_selector<void(Arg),
enable_if_t<!is_disposition<Arg>::value>>
: public promise_handler_1<Arg> {};
template <typename Arg0, typename Arg1>
class promise_handler_selector<void(Arg0, Arg1),
enable_if_t<is_disposition<Arg0>::value>>
: public promise_handler_d_1<Arg0, Arg1> {};
template <typename Arg0, typename... ArgN>
class promise_handler_selector<void(Arg0, ArgN...),
enable_if_t<!is_disposition<Arg0>::value>>
: public promise_handler_n<std::tuple<Arg0, ArgN...>> {};
template <typename Arg0, typename... ArgN>
class promise_handler_selector<void(Arg0, ArgN...),
enable_if_t<is_disposition<Arg0>::value>>
: public promise_handler_d_n<Arg0, std::tuple<ArgN...>> {};
// Completion handlers produced from the use_future completion token, when not
// using use_future::operator().
template <typename Signature, typename Allocator>
class promise_handler
: public promise_handler_selector<Signature>
{
public:
typedef Allocator allocator_type;
typedef void result_type;
promise_handler(use_future_t<Allocator> u)
: allocator_(u.get_allocator())
{
this->create_promise(allocator_);
}
allocator_type get_allocator() const noexcept
{
return allocator_;
}
private:
Allocator allocator_;
};
template <typename Function>
struct promise_function_wrapper
{
explicit promise_function_wrapper(Function& f)
: function_(static_cast<Function&&>(f))
{
}
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>
class promise_async_result
{
public:
typedef promise_handler<Signature, Allocator> completion_handler_type;
typedef typename completion_handler_type::future_type return_type;
explicit promise_async_result(completion_handler_type& h)
: future_(h.get_future())
{
}
return_type get()
{
return static_cast<return_type&&>(future_);
}
private:
return_type future_;
};
// Return value from use_future::operator().
template <typename Function, typename Allocator>
class packaged_token
{
public:
packaged_token(Function f, const Allocator& a)
: function_(static_cast<Function&&>(f)),
allocator_(a)
{
}
//private:
Function function_;
Allocator allocator_;
};
// Completion handlers produced from the use_future completion token, when
// using use_future::operator().
template <typename Function, typename Allocator, typename Result>
class packaged_handler
: public promise_creator<Result>
{
public:
typedef Allocator allocator_type;
typedef void result_type;
packaged_handler(packaged_token<Function, Allocator> t)
: function_(static_cast<Function&&>(t.function_)),
allocator_(t.allocator_)
{
this->create_promise(allocator_);
}
allocator_type get_allocator() const noexcept
{
return allocator_;
}
template <typename... Args>
void operator()(Args&&... args)
{
(promise_invoke_and_set)(*this->p_,
function_, static_cast<Args&&>(args)...);
}
private:
Function function_;
Allocator allocator_;
};
// Helper base class for async_result specialisation.
template <typename Function, typename Allocator, typename Result>
class packaged_async_result
{
public:
typedef packaged_handler<Function, Allocator, Result> completion_handler_type;
typedef typename completion_handler_type::future_type return_type;
explicit packaged_async_result(completion_handler_type& h)
: future_(h.get_future())
{
}
return_type get()
{
return static_cast<return_type&&>(future_);
}
private:
return_type future_;
};
} // namespace detail
template <typename Allocator> template <typename Function>
inline detail::packaged_token<decay_t<Function>, Allocator>
use_future_t<Allocator>::operator()(Function&& f) const
{
return detail::packaged_token<decay_t<Function>, Allocator>(
static_cast<Function&&>(f), allocator_);
}
#if !defined(GENERATING_DOCUMENTATION)
template <typename Allocator, typename Result, typename... Args>
class async_result<use_future_t<Allocator>, Result(Args...)>
: public detail::promise_async_result<
void(decay_t<Args>...), Allocator>
{
public:
explicit async_result(
typename detail::promise_async_result<void(decay_t<Args>...),
Allocator>::completion_handler_type& h)
: detail::promise_async_result<
void(decay_t<Args>...), Allocator>(h)
{
}
};
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,
result_of_t<Function(Args...)>>
{
public:
explicit async_result(
typename detail::packaged_async_result<Function, Allocator,
result_of_t<Function(Args...)>>::completion_handler_type& h)
: detail::packaged_async_result<Function, Allocator,
result_of_t<Function(Args...)>>(h)
{
}
};
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <typename T, typename Blocking>
struct equality_comparable<
asio::detail::promise_executor<T, Blocking>>
{
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 T, typename Blocking, typename Function>
struct execute_member<
asio::detail::promise_executor<T, Blocking>, 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 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
>
{
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = true;
typedef Blocking result_type;
static constexpr result_type value() noexcept
{
return Blocking();
}
};
#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
>
{
static constexpr bool is_valid = true;
static constexpr bool is_noexcept = true;
typedef asio::system_context& result_type;
};
#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
>
{
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;
};
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_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
} // namespace traits
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_USE_FUTURE_HPP

780
include/asio/impl/write.hpp Normal file
View File

@@ -0,0 +1,780 @@
//
// impl/write.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_WRITE_HPP
#define ASIO_IMPL_WRITE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/associator.hpp"
#include "asio/buffer.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_cont_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"
namespace asio {
namespace detail
{
template <typename SyncWriteStream, typename ConstBufferSequence,
typename ConstBufferIterator, typename CompletionCondition>
std::size_t write(SyncWriteStream& s,
const ConstBufferSequence& buffers, const ConstBufferIterator&,
CompletionCondition completion_condition, asio::error_code& ec)
{
ec = asio::error_code();
asio::detail::consuming_buffers<const_buffer,
ConstBufferSequence, ConstBufferIterator> tmp(buffers);
while (!tmp.empty())
{
if (std::size_t max_size = detail::adapt_completion_condition_result(
completion_condition(ec, tmp.total_consumed())))
tmp.consume(s.write_some(tmp.prepare(max_size), ec));
else
break;
}
return tmp.total_consumed();
}
} // namespace detail
template <typename SyncWriteStream, typename ConstBufferSequence,
typename CompletionCondition>
inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_const_buffer_sequence<ConstBufferSequence>::value
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
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,
constraint_t<
is_const_buffer_sequence<ConstBufferSequence>::value
>)
{
asio::error_code ec;
std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);
asio::detail::throw_error(ec, "write");
return bytes_transferred;
}
template <typename SyncWriteStream, typename ConstBufferSequence>
inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
asio::error_code& ec,
constraint_t<
is_const_buffer_sequence<ConstBufferSequence>::value
>)
{
return write(s, buffers, transfer_all(), ec);
}
template <typename SyncWriteStream, typename ConstBufferSequence,
typename CompletionCondition>
inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
CompletionCondition completion_condition,
constraint_t<
is_const_buffer_sequence<ConstBufferSequence>::value
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code ec;
std::size_t bytes_transferred = write(s, buffers,
static_cast<CompletionCondition&&>(completion_condition), ec);
asio::detail::throw_error(ec, "write");
return bytes_transferred;
}
#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
template <typename SyncWriteStream, typename DynamicBuffer_v1,
typename CompletionCondition>
std::size_t write(SyncWriteStream& s,
DynamicBuffer_v1&& buffers,
CompletionCondition completion_condition, 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
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
decay_t<DynamicBuffer_v1> b(
static_cast<DynamicBuffer_v1&&>(buffers));
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_v1>
inline std::size_t write(SyncWriteStream& s,
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,
static_cast<DynamicBuffer_v1&&>(buffers),
transfer_all(), ec);
asio::detail::throw_error(ec, "write");
return bytes_transferred;
}
template <typename SyncWriteStream, typename DynamicBuffer_v1>
inline std::size_t write(SyncWriteStream& s,
DynamicBuffer_v1&& buffers,
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
>)
{
return write(s, static_cast<DynamicBuffer_v1&&>(buffers),
transfer_all(), ec);
}
template <typename SyncWriteStream, typename DynamicBuffer_v1,
typename CompletionCondition>
inline std::size_t write(SyncWriteStream& s,
DynamicBuffer_v1&& buffers,
CompletionCondition completion_condition,
constraint_t<
is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
>,
constraint_t<
!is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
>,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code ec;
std::size_t bytes_transferred = write(s,
static_cast<DynamicBuffer_v1&&>(buffers),
static_cast<CompletionCondition&&>(completion_condition), ec);
asio::detail::throw_error(ec, "write");
return bytes_transferred;
}
#if !defined(ASIO_NO_EXTENSIONS)
#if !defined(ASIO_NO_IOSTREAM)
template <typename SyncWriteStream, typename Allocator,
typename CompletionCondition>
inline std::size_t write(SyncWriteStream& s,
asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
return write(s, basic_streambuf_ref<Allocator>(b),
static_cast<CompletionCondition&&>(completion_condition), ec);
}
template <typename SyncWriteStream, typename Allocator>
inline std::size_t write(SyncWriteStream& s,
asio::basic_streambuf<Allocator>& b)
{
return write(s, basic_streambuf_ref<Allocator>(b));
}
template <typename SyncWriteStream, typename Allocator>
inline std::size_t write(SyncWriteStream& s,
asio::basic_streambuf<Allocator>& b,
asio::error_code& ec)
{
return write(s, basic_streambuf_ref<Allocator>(b), ec);
}
template <typename SyncWriteStream, typename Allocator,
typename CompletionCondition>
inline std::size_t write(SyncWriteStream& s,
asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
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
>,
constraint_t<
is_completion_condition<CompletionCondition>::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
>,
constraint_t<
is_completion_condition<CompletionCondition>::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
{
template <typename AsyncWriteStream, typename ConstBufferSequence,
typename ConstBufferIterator, typename CompletionCondition,
typename WriteHandler>
class write_op
: public base_from_cancellation_state<WriteHandler>,
base_from_completion_cond<CompletionCondition>
{
public:
write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers,
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_(static_cast<WriteHandler&&>(handler))
{
}
write_op(const write_op& other)
: base_from_cancellation_state<WriteHandler>(other),
base_from_completion_cond<CompletionCondition>(other),
stream_(other.stream_),
buffers_(other.buffers_),
start_(other.start_),
handler_(other.handler_)
{
}
write_op(write_op&& 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_(static_cast<buffers_type&&>(other.buffers_)),
start_(other.start_),
handler_(static_cast<WriteHandler&&>(other.handler_))
{
}
void operator()(asio::error_code ec,
std::size_t bytes_transferred, int start = 0)
{
std::size_t max_size;
switch (start_ = start)
{
case 1:
max_size = this->check_for_completion(ec, buffers_.total_consumed());
for (;;)
{
{
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());
if (max_size == 0)
break;
if (this->cancelled() != cancellation_type::none)
{
ec = error::operation_aborted;
break;
}
}
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_;
buffers_type buffers_;
int start_;
WriteHandler 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)
{
return this_handler->start_ == 0 ? true
: asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename AsyncWriteStream, typename ConstBufferSequence,
typename ConstBufferIterator, typename CompletionCondition,
typename WriteHandler>
inline void start_write_op(AsyncWriteStream& stream,
const ConstBufferSequence& buffers, const ConstBufferIterator&,
CompletionCondition& completion_condition, WriteHandler& handler)
{
detail::write_op<AsyncWriteStream, ConstBufferSequence,
ConstBufferIterator, CompletionCondition, WriteHandler>(
stream, buffers, completion_condition, handler)(
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 <template <typename, typename> class Associator,
typename AsyncWriteStream, typename ConstBufferSequence,
typename ConstBufferIterator, typename CompletionCondition,
typename WriteHandler, typename DefaultCandidate>
struct associator<Associator,
detail::write_op<AsyncWriteStream, ConstBufferSequence,
ConstBufferIterator, CompletionCondition, WriteHandler>,
DefaultCandidate>
: Associator<WriteHandler, DefaultCandidate>
{
static typename Associator<WriteHandler, DefaultCandidate>::type get(
const detail::write_op<AsyncWriteStream, ConstBufferSequence,
ConstBufferIterator, CompletionCondition, WriteHandler>& h) noexcept
{
return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::write_op<AsyncWriteStream, ConstBufferSequence,
ConstBufferIterator, 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)
#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
namespace detail
{
template <typename AsyncWriteStream, typename DynamicBuffer_v1,
typename CompletionCondition, typename WriteHandler>
class write_dynbuf_v1_op
{
public:
template <typename BufferSequence>
write_dynbuf_v1_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_v1_op(const write_dynbuf_v1_op& other)
: stream_(other.stream_),
buffers_(other.buffers_),
completion_condition_(other.completion_condition_),
handler_(other.handler_)
{
}
write_dynbuf_v1_op(write_dynbuf_v1_op&& other)
: stream_(other.stream_),
buffers_(static_cast<DynamicBuffer_v1&&>(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(),
static_cast<CompletionCondition&&>(completion_condition_),
static_cast<write_dynbuf_v1_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_v1 buffers_;
CompletionCondition completion_condition_;
WriteHandler handler_;
};
template <typename AsyncWriteStream, typename DynamicBuffer_v1,
typename CompletionCondition, typename WriteHandler>
inline bool asio_handler_is_continuation(
write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,
CompletionCondition, WriteHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename AsyncWriteStream>
class initiate_async_write_dynbuf_v1
{
public:
typedef typename AsyncWriteStream::executor_type executor_type;
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 <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>
{
static typename Associator<WriteHandler, DefaultCandidate>::type get(
const detail::write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,
CompletionCondition, WriteHandler>& h) noexcept
{
return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
}
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 Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
#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)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_WRITE_HPP

View File

@@ -0,0 +1,480 @@
//
// impl/write_at.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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_WRITE_AT_HPP
#define ASIO_IMPL_WRITE_AT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/associator.hpp"
#include "asio/buffer.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_cont_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"
namespace asio {
namespace detail
{
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename ConstBufferIterator, typename CompletionCondition>
std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d,
uint64_t offset, const ConstBufferSequence& buffers,
const ConstBufferIterator&, CompletionCondition completion_condition,
asio::error_code& ec)
{
ec = asio::error_code();
asio::detail::consuming_buffers<const_buffer,
ConstBufferSequence, ConstBufferIterator> tmp(buffers);
while (!tmp.empty())
{
if (std::size_t max_size = detail::adapt_completion_condition_result(
completion_condition(ec, tmp.total_consumed())))
{
tmp.consume(d.write_some_at(offset + tmp.total_consumed(),
tmp.prepare(max_size), ec));
}
else
break;
}
return tmp.total_consumed();
}
} // namespace detail
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
return detail::write_at_buffer_sequence(d, offset, buffers,
asio::buffer_sequence_begin(buffers),
static_cast<CompletionCondition&&>(completion_condition), ec);
}
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t bytes_transferred = write_at(
d, offset, buffers, transfer_all(), ec);
asio::detail::throw_error(ec, "write_at");
return bytes_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return write_at(d, offset, buffers, transfer_all(), ec);
}
template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
typename CompletionCondition>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code 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;
}
#if !defined(ASIO_NO_EXTENSIONS)
#if !defined(ASIO_NO_IOSTREAM)
template <typename SyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition>
std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
std::size_t bytes_transferred = write_at(d, offset, b.data(),
static_cast<CompletionCondition&&>(completion_condition), ec);
b.consume(bytes_transferred);
return bytes_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename Allocator>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b)
{
asio::error_code ec;
std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
asio::detail::throw_error(ec, "write_at");
return bytes_transferred;
}
template <typename SyncRandomAccessWriteDevice, typename Allocator>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b,
asio::error_code& ec)
{
return write_at(d, offset, b, transfer_all(), ec);
}
template <typename SyncRandomAccessWriteDevice, typename Allocator,
typename CompletionCondition>
inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition,
constraint_t<
is_completion_condition<CompletionCondition>::value
>)
{
asio::error_code 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;
}
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // !defined(ASIO_NO_EXTENSIONS)
namespace detail
{
template <typename AsyncRandomAccessWriteDevice,
typename ConstBufferSequence, typename ConstBufferIterator,
typename CompletionCondition, typename WriteHandler>
class write_at_op
: 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)
: 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_(static_cast<WriteHandler&&>(handler))
{
}
write_at_op(const write_at_op& other)
: base_from_cancellation_state<WriteHandler>(other),
base_from_completion_cond<CompletionCondition>(other),
device_(other.device_),
offset_(other.offset_),
buffers_(other.buffers_),
start_(other.start_),
handler_(other.handler_)
{
}
write_at_op(write_at_op&& 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_(static_cast<buffers_type&&>(other.buffers_)),
start_(other.start_),
handler_(static_cast<WriteHandler&&>(other.handler_))
{
}
void operator()(asio::error_code ec,
std::size_t bytes_transferred, int start = 0)
{
std::size_t max_size;
switch (start_ = start)
{
case 1:
max_size = this->check_for_completion(ec, buffers_.total_consumed());
for (;;)
{
{
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());
if (max_size == 0)
break;
if (this->cancelled() != cancellation_type::none)
{
ec = asio::error::operation_aborted;
break;
}
}
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_;
buffers_type buffers_;
int start_;
WriteHandler 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)
{
return this_handler->start_ == 0 ? true
: asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename AsyncRandomAccessWriteDevice,
typename ConstBufferSequence, typename ConstBufferIterator,
typename CompletionCondition, typename WriteHandler>
inline void start_write_at_op(AsyncRandomAccessWriteDevice& d,
uint64_t offset, const ConstBufferSequence& buffers,
const ConstBufferIterator&, CompletionCondition& completion_condition,
WriteHandler& handler)
{
detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
ConstBufferIterator, CompletionCondition, WriteHandler>(
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 <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>,
DefaultCandidate>
: Associator<WriteHandler, DefaultCandidate>
{
static typename Associator<WriteHandler, DefaultCandidate>::type get(
const detail::write_at_op<AsyncRandomAccessWriteDevice,
ConstBufferSequence, ConstBufferIterator,
CompletionCondition, WriteHandler>& h) noexcept
{
return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::write_at_op<AsyncRandomAccessWriteDevice,
ConstBufferSequence, ConstBufferIterator,
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)
#if !defined(ASIO_NO_EXTENSIONS)
#if !defined(ASIO_NO_IOSTREAM)
namespace detail
{
template <typename Allocator, typename WriteHandler>
class write_at_streambuf_op
{
public:
write_at_streambuf_op(
asio::basic_streambuf<Allocator>& streambuf,
WriteHandler& handler)
: streambuf_(streambuf),
handler_(static_cast<WriteHandler&&>(handler))
{
}
write_at_streambuf_op(const write_at_streambuf_op& other)
: streambuf_(other.streambuf_),
handler_(other.handler_)
{
}
write_at_streambuf_op(write_at_streambuf_op&& other)
: streambuf_(other.streambuf_),
handler_(static_cast<WriteHandler&&>(other.handler_))
{
}
void operator()(const asio::error_code& ec,
const std::size_t bytes_transferred)
{
streambuf_.consume(bytes_transferred);
static_cast<WriteHandler&&>(handler_)(ec, bytes_transferred);
}
//private:
asio::basic_streambuf<Allocator>& streambuf_;
WriteHandler handler_;
};
template <typename Allocator, typename WriteHandler>
inline bool asio_handler_is_continuation(
write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename AsyncRandomAccessWriteDevice>
class initiate_async_write_at_streambuf
{
public:
typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type;
explicit initiate_async_write_at_streambuf(
AsyncRandomAccessWriteDevice& device)
: device_(device)
{
}
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 <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>
{
static typename Associator<WriteHandler, DefaultCandidate>::type get(
const detail::write_at_streambuf_op<Executor, WriteHandler>& h) noexcept
{
return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::write_at_streambuf_op<Executor, 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)
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // !defined(ASIO_NO_EXTENSIONS)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_WRITE_AT_HPP