update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -14,10 +14,11 @@
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/core/detail/async_base.hpp>
#include <boost/beast/core/detail/filtering_cancellation_slot.hpp>
#include <boost/beast/core/detail/work_guard.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
@@ -117,7 +118,7 @@ namespace beast {
// `net::post` will be used to call the completion handler, otherwise
// the completion handler will be invoked directly.
this->invoke(is_continuation, ec, total_bytes_transferred_);
this->complete(is_continuation, ec, total_bytes_transferred_);
}
};
@@ -182,11 +183,31 @@ class async_base
#endif
{
static_assert(
net::is_executor<Executor1>::value,
net::is_executor<Executor1>::value || net::execution::is_executor<Executor1>::value,
"Executor type requirements not met");
Handler h_;
net::executor_work_guard<Executor1> wg1_;
detail::select_work_guard_t<Executor1> wg1_;
net::cancellation_type act_{net::cancellation_type::terminal};
public:
/** The type of executor associated with this object.
If a class derived from @ref boost::beast::async_base is a completion
handler, then the associated executor of the derived class will
be this type.
*/
using executor_type =
#if BOOST_BEAST_DOXYGEN
__implementation_defined__;
#else
typename
net::associated_executor<
Handler,
typename detail::select_work_guard_t<Executor1>::executor_type
>::type;
#endif
private:
virtual
void
@@ -229,7 +250,7 @@ public:
Handler_&& handler,
Executor1 const& ex1)
: h_(std::forward<Handler_>(handler))
, wg1_(ex1)
, wg1_(detail::make_work_guard(ex1))
{
}
@@ -249,27 +270,22 @@ public:
/// Move Constructor
async_base(async_base&& other) = default;
virtual ~async_base() = default;
async_base(async_base const&) = delete;
async_base& operator=(async_base const&) = delete;
/** The type of allocator associated with this object.
If a class derived from @ref async_base is a completion
If a class derived from @ref boost::beast::async_base is a completion
handler, then the associated allocator of the derived class will
be this type.
*/
using allocator_type =
net::associated_allocator_t<Handler, Allocator>;
/** The type of executor associated with this object.
If a class derived from @ref async_base is a completion
handler, then the associated executor of the derived class will
be this type.
*/
using executor_type =
net::associated_executor_t<Handler, Executor1>;
/** Returns the allocator associated with this object.
If a class derived from @ref async_base is a completion
If a class derived from @ref boost::beast::async_base is a completion
handler, then the object returned from this function will be used
as the associated allocator of the derived class.
*/
@@ -282,7 +298,7 @@ public:
/** Returns the executor associated with this object.
If a class derived from @ref async_base is a completion
If a class derived from @ref boost::beast::async_base is a completion
handler, then the object returned from this function will be used
as the associated executor of the derived class.
*/
@@ -293,6 +309,38 @@ public:
h_, wg1_.get_executor());
}
/** The type of cancellation_slot associated with this object.
If a class derived from @ref async_base is a completion
handler, then the associated cancellation_slot of the
derived class will be this type.
The default type is a filtering cancellation slot,
that only allows terminal cancellation.
*/
using cancellation_slot_type =
beast::detail::filtering_cancellation_slot<net::associated_cancellation_slot_t<Handler>>;
/** Returns the cancellation_slot associated with this object.
If a class derived from @ref async_base is a completion
handler, then the object returned from this function will be used
as the associated cancellation_slot of the derived class.
*/
cancellation_slot_type
get_cancellation_slot() const noexcept
{
return cancellation_slot_type(act_, net::get_associated_cancellation_slot(h_,
net::cancellation_slot()));
}
/// Set the allowed cancellation types, default is `terminal`.
void set_allowed_cancellation(
net::cancellation_type allowed_cancellation_types = net::cancellation_type::terminal)
{
act_ = allowed_cancellation_types;
}
/// Returns the handler associated with this object
Handler const&
handler() const noexcept
@@ -317,16 +365,17 @@ public:
This invokes the final completion handler with the specified
arguments forwarded. It is undefined to call either of
@ref complete or @ref complete_now more than once.
@ref boost::beast::async_base::complete or
@ref boost::beast::async_base::complete_now more than once.
Any temporary objects allocated with @ref beast::allocate_stable will
Any temporary objects allocated with @ref boost::beast::allocate_stable will
be automatically destroyed before the final completion handler
is invoked.
@param is_continuation If this value is `false`, then the
handler will be submitted to the executor using `net::post`.
Otherwise the handler will be invoked as if by calling
@ref complete_now.
@ref boost::beast::async_base::complete_now.
@param args A list of optional parameters to invoke the handler
with. The completion handler must be invocable with the parameter
@@ -340,11 +389,13 @@ public:
if(! is_continuation)
{
auto const ex = get_executor();
net::post(net::bind_executor(
ex,
beast::bind_front_handler(
std::move(h_),
std::forward<Args>(args)...)));
net::post(
wg1_.get_executor(),
net::bind_executor(
ex,
beast::bind_front_handler(
std::move(h_),
std::forward<Args>(args)...)));
wg1_.reset();
}
else
@@ -358,9 +409,9 @@ public:
This invokes the final completion handler with the specified
arguments forwarded. It is undefined to call either of
@ref complete or @ref complete_now more than once.
@ref boost::beast::async_base::complete or @ref boost::beast::async_base::complete_now more than once.
Any temporary objects allocated with @ref beast::allocate_stable will
Any temporary objects allocated with @ref boost::beast::allocate_stable will
be automatically destroyed before the final completion handler
is invoked.

View File

@@ -73,7 +73,7 @@ namespace beast {
be invoked by the executor associated with the stream upon construction.
The type of executor used with this stream must meet the following
requirements:
@li Function objects submitted to the executor shall never run
concurrently with each other.
@@ -182,7 +182,7 @@ namespace beast {
@tparam Executor A type meeting the requirements of <em>Executor</em> to
be used for submitting all completion handlers which do not already have an
associated executor. If this type is omitted, the default of `net::executor`
associated executor. If this type is omitted, the default of `net::any_io_executor`
will be used.
@par Thread Safety
@@ -197,7 +197,7 @@ namespace beast {
*/
template<
class Protocol,
class Executor = net::executor,
class Executor = net::any_io_executor,
class RatePolicy = unlimited_rate_policy
>
class basic_stream
@@ -217,6 +217,15 @@ public:
*/
using executor_type = beast::executor_type<socket_type>;
/// Rebinds the stream type to another executor.
template<class Executor1>
struct rebind_executor
{
/// The stream type when rebound to the specified executor.
using other = basic_stream<
Protocol, Executor1, RatePolicy>;
};
/// The protocol type.
using protocol_type = Protocol;
@@ -224,7 +233,9 @@ public:
using endpoint_type = typename Protocol::endpoint;
private:
static_assert(net::is_executor<Executor>::value,
using op_state = basic_op_state<Executor>;
static_assert(
net::is_executor<Executor>::value || net::execution::is_executor<Executor>::value,
"Executor type requirements not met");
struct impl_type
@@ -237,7 +248,12 @@ private:
op_state read;
op_state write;
net::steady_timer timer; // rate timer
net::basic_waitable_timer<
std::chrono::steady_clock,
net::wait_traits<
std::chrono::steady_clock>,
Executor> timer; // rate timer;
int waiting = 0;
impl_type(impl_type&&) = default;
@@ -274,8 +290,8 @@ private:
template<class Executor2>
void on_timer(Executor2 const& ex2);
void reset(); // set timeouts to never
void close(); // cancel everything
void reset(); // set timeouts to never
void close() noexcept; // cancel everything
};
// We use shared ownership for the state so it can
@@ -284,6 +300,7 @@ private:
// but the implementation is still waiting on a timer.
boost::shared_ptr<impl_type> impl_;
template<class Executor2>
struct timeout_handler;
struct ops;
@@ -337,6 +354,22 @@ public:
! std::is_constructible<RatePolicy, Arg0>::value>::type>
explicit
basic_stream(Arg0&& argo, Args&&... args);
/** Constructor
*
* A constructor that rebinds the executor.
*
* @tparam Executor_ The new executor
* @param other The original socket to be rebound.
*/
template<class Executor_>
explicit
basic_stream(basic_stream<Protocol, Executor_, RatePolicy> && other);
template<typename, typename, typename>
friend class basic_stream;
#endif
/** Constructor
@@ -367,7 +400,7 @@ public:
/** Move constructor
@param other The other object from which the move will occur.
@param other The other object from which the move will occur.
@note Following the move, the moved-from object is in the
same state as if newly constructed.
@@ -438,7 +471,7 @@ public:
*/
void
expires_after(
std::chrono::nanoseconds expiry_time);
net::steady_timer::duration expiry_time);
/** Set the timeout for the next logical operation.
@@ -490,7 +523,7 @@ public:
//--------------------------------------------------------------------------
/** Get the executor associated with the object.
This function may be used to obtain the executor object that the
stream uses to dispatch completion handlers without an assocaited
executor.
@@ -498,7 +531,7 @@ public:
@return A copy of the executor that stream will use to dispatch handlers.
*/
executor_type
get_executor() const noexcept
get_executor() noexcept
{
return impl_->ex();
}
@@ -525,7 +558,7 @@ public:
}
/** Connect the stream to the specified endpoint.
This function is used to connect the underlying socket to the
specified remote endpoint. The function call will block until
the connection is successfully made or an error occurs.
@@ -534,7 +567,7 @@ public:
closed state upon failure.
@param ep The remote endpoint to connect to.
@param ec Set to indicate what error occurred, if any.
@see connect
@@ -546,7 +579,7 @@ public:
}
/** Establishes a connection by trying each endpoint in a sequence.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -556,11 +589,11 @@ public:
The algorithm, known as a <em>composed operation</em>, is implemented
in terms of calls to the underlying socket's `connect` function.
@param endpoints A sequence of endpoints.
@returns The successfully connected endpoint.
@throws system_error Thrown on failure. If the sequence is
empty, the associated error code is `net::error::not_found`.
Otherwise, contains the error from the last connection attempt.
@@ -579,7 +612,7 @@ public:
}
/** Establishes a connection by trying each endpoint in a sequence.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -589,16 +622,16 @@ public:
The algorithm, known as a <em>composed operation</em>, is implemented
in terms of calls to the underlying socket's `connect` function.
@param endpoints A sequence of endpoints.
@param ec Set to indicate what error occurred, if any. If the sequence is
empty, set to `net::error::not_found`. Otherwise, contains the error
from the last connection attempt.
@returns On success, the successfully connected endpoint. Otherwise, a
default-constructed endpoint.
*/
*/
template<class EndpointSequence
#if ! BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
@@ -616,27 +649,27 @@ public:
}
/** Establishes a connection by trying each endpoint in a sequence.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
The underlying socket is automatically opened if needed.
An automatically opened socket is not returned to the
closed state upon failure.
The algorithm, known as a <em>composed operation</em>, is implemented
in terms of calls to the underlying socket's `connect` function.
@param begin An iterator pointing to the start of a sequence of endpoints.
@param end An iterator pointing to the end of a sequence of endpoints.
@returns An iterator denoting the successfully connected endpoint.
@throws system_error Thrown on failure. If the sequence is
empty, the associated error code is `net::error::not_found`.
Otherwise, contains the error from the last connection attempt.
*/
*/
template<class Iterator>
Iterator
connect(
@@ -646,25 +679,25 @@ public:
}
/** Establishes a connection by trying each endpoint in a sequence.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
The underlying socket is automatically opened if needed.
An automatically opened socket is not returned to the
closed state upon failure.
The algorithm, known as a <em>composed operation</em>, is implemented
in terms of calls to the underlying socket's `connect` function.
@param begin An iterator pointing to the start of a sequence of endpoints.
@param end An iterator pointing to the end of a sequence of endpoints.
@param ec Set to indicate what error occurred, if any. If the sequence is
empty, set to boost::asio::error::not_found. Otherwise, contains the error
from the last connection attempt.
@returns On success, an iterator denoting the successfully connected
endpoint. Otherwise, the end iterator.
*/
@@ -678,7 +711,7 @@ public:
}
/** Establishes a connection by trying each endpoint in a sequence.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -688,9 +721,9 @@ public:
The algorithm, known as a <em>composed operation</em>, is implemented
in terms of calls to the underlying socket's `connect` function.
@param endpoints A sequence of endpoints.
@param connect_condition A function object that is called prior to each
connection attempt. The signature of the function object must be:
@code
@@ -703,9 +736,9 @@ public:
indicate success. The @c next parameter is the next endpoint to be tried.
The function object should return true if the next endpoint should be tried,
and false if it should be skipped.
@returns The successfully connected endpoint.
@throws boost::system::system_error Thrown on failure. If the sequence is
empty, the associated error code is `net::error::not_found`.
Otherwise, contains the error from the last connection attempt.
@@ -779,7 +812,7 @@ public:
}
/** Establishes a connection by trying each endpoint in a sequence.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -789,11 +822,11 @@ public:
The algorithm, known as a <em>composed operation</em>, is implemented
in terms of calls to the underlying socket's `connect` function.
@param begin An iterator pointing to the start of a sequence of endpoints.
@param end An iterator pointing to the end of a sequence of endpoints.
@param connect_condition A function object that is called prior to each
connection attempt. The signature of the function object must be:
@code
@@ -806,13 +839,13 @@ public:
indicate success. The @c next parameter is the next endpoint to be tried.
The function object should return true if the next endpoint should be tried,
and false if it should be skipped.
@returns An iterator denoting the successfully connected endpoint.
@throws boost::system::system_error Thrown on failure. If the sequence is
empty, the associated @c error_code is `net::error::not_found`.
Otherwise, contains the error from the last connection attempt.
*/
*/
template<
class Iterator, class ConnectCondition>
Iterator
@@ -824,7 +857,7 @@ public:
}
/** Establishes a connection by trying each endpoint in a sequence.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -834,11 +867,11 @@ public:
The algorithm, known as a <em>composed operation</em>, is implemented
in terms of calls to the underlying socket's `connect` function.
@param begin An iterator pointing to the start of a sequence of endpoints.
@param end An iterator pointing to the end of a sequence of endpoints.
@param connect_condition A function object that is called prior to each
connection attempt. The signature of the function object must be:
@code
@@ -851,11 +884,11 @@ public:
indicate success. The @c next parameter is the next endpoint to be tried.
The function object should return true if the next endpoint should be tried,
and false if it should be skipped.
@param ec Set to indicate what error occurred, if any. If the sequence is
empty, set to `net::error::not_found`. Otherwise, contains the error
from the last connection attempt.
@returns On success, an iterator denoting the successfully connected
endpoint. Otherwise, the end iterator.
*/
@@ -885,7 +918,7 @@ public:
@param ep The remote endpoint to which the underlying socket will be
connected. Copies will be made of the endpoint object as required.
@param handler The completion handler to invoke when the operation
completes. The implementation takes ownership of the handler by
performing a decay-copy. The equivalent function signature of
@@ -900,16 +933,32 @@ public:
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_connect operation.
@see async_connect
*/
template<class ConnectHandler>
template<
BOOST_BEAST_ASYNC_TPARAM1 ConnectHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
async_connect(
endpoint_type const& ep,
ConnectHandler&& handler);
ConnectHandler&& handler =
net::default_completion_token_t<
executor_type>{});
/** Establishes a connection by trying each endpoint in a sequence asynchronously.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -924,10 +973,10 @@ public:
If the timeout timer expires while the operation is outstanding,
the current connection attempt will be canceled and the completion
handler will be invoked with the error @ref error::timeout.
@param endpoints A sequence of endpoints. This this object must meet
the requirements of <em>EndpointSequence</em>.
@param handler The completion handler to invoke when the operation
completes. The implementation takes ownership of the handler by
performing a decay-copy. The equivalent function signature of
@@ -938,7 +987,7 @@ public:
// net::error::not_found. Otherwise, contains the
// error from the last connection attempt.
error_code const& error,
// On success, the successfully connected endpoint.
// Otherwise, a default-constructed endpoint.
typename Protocol::endpoint const& endpoint
@@ -948,23 +997,41 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_connect operation.
*/
template<
class EndpointSequence,
class RangeConnectHandler
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(error_code, typename Protocol::endpoint))
RangeConnectHandler =
net::default_completion_token_t<executor_type>
#if ! BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
net::is_endpoint_sequence<
EndpointSequence>::value>::type
#endif
>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
BOOST_ASIO_INITFN_RESULT_TYPE(
RangeConnectHandler,
void(error_code, typename Protocol::endpoint))
async_connect(
EndpointSequence const& endpoints,
RangeConnectHandler&& handler);
RangeConnectHandler&& handler =
net::default_completion_token_t<executor_type>{});
/** Establishes a connection by trying each endpoint in a sequence asynchronously.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -982,7 +1049,7 @@ public:
@param endpoints A sequence of endpoints. This this object must meet
the requirements of <em>EndpointSequence</em>.
@param connect_condition A function object that is called prior to each
connection attempt. The signature of the function object must be:
@code
@@ -1006,7 +1073,7 @@ public:
// net::error::not_found. Otherwise, contains the
// error from the last connection attempt.
error_code const& error,
// On success, the successfully connected endpoint.
// Otherwise, a default-constructed endpoint.
typename Protocol::endpoint const& endpoint
@@ -1034,25 +1101,43 @@ public:
}
};
@endcode
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_connect operation.
*/
template<
class EndpointSequence,
class ConnectCondition,
class RangeConnectHandler
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(error_code, typename Protocol::endpoint))
RangeConnectHandler =
net::default_completion_token_t<executor_type>
#if ! BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
net::is_endpoint_sequence<
EndpointSequence>::value>::type
#endif
>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
BOOST_ASIO_INITFN_RESULT_TYPE(
RangeConnectHandler,
void(error_code, typename Protocol::endpoint))
async_connect(
EndpointSequence const& endpoints,
ConnectCondition connect_condition,
RangeConnectHandler&& handler);
RangeConnectHandler&& handler =
net::default_completion_token_t<
executor_type>{});
/** Establishes a connection by trying each endpoint in a sequence asynchronously.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -1067,9 +1152,9 @@ public:
If the timeout timer expires while the operation is outstanding,
the current connection attempt will be canceled and the completion
handler will be invoked with the error @ref error::timeout.
@param begin An iterator pointing to the start of a sequence of endpoints.
@param end An iterator pointing to the end of a sequence of endpoints.
@param handler The completion handler to invoke when the operation
@@ -1082,7 +1167,7 @@ public:
// net::error::not_found. Otherwise, contains the
// error from the last connection attempt.
error_code const& error,
// On success, an iterator denoting the successfully
// connected endpoint. Otherwise, the end iterator.
Iterator iterator
@@ -1092,17 +1177,34 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_connect operation.
*/
template<
class Iterator,
class IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(error_code, Iterator))
IteratorConnectHandler =
net::default_completion_token_t<executor_type>>
BOOST_ASIO_INITFN_RESULT_TYPE(
IteratorConnectHandler,
void(error_code, Iterator))
async_connect(
Iterator begin, Iterator end,
IteratorConnectHandler&& handler);
IteratorConnectHandler&& handler =
net::default_completion_token_t<executor_type>{});
/** Establishes a connection by trying each endpoint in a sequence asynchronously.
This function attempts to connect the stream to one of a sequence of
endpoints by trying each endpoint until a connection is successfully
established.
@@ -1113,17 +1215,17 @@ public:
If the timeout timer expires while the operation is outstanding,
the current connection attempt will be canceled and the completion
handler will be invoked with the error @ref error::timeout.
@param begin An iterator pointing to the start of a sequence of endpoints.
@param end An iterator pointing to the end of a sequence of endpoints.
@param connect_condition A function object that is called prior to each
connection attempt. The signature of the function object must be:
@code
bool connect_condition(
error_code const& ec,
Iterator next);
typename Protocol::endpoint const& next);
@endcode
@param handler The completion handler to invoke when the operation
@@ -1136,7 +1238,7 @@ public:
// net::error::not_found. Otherwise, contains the
// error from the last connection attempt.
error_code const& error,
// On success, an iterator denoting the successfully
// connected endpoint. Otherwise, the end iterator.
Iterator iterator
@@ -1146,23 +1248,40 @@ public:
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_connect operation.
*/
template<
class Iterator,
class ConnectCondition,
class IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(error_code, Iterator))
IteratorConnectHandler =
net::default_completion_token_t<executor_type>>
BOOST_ASIO_INITFN_RESULT_TYPE(
IteratorConnectHandler,
void(error_code, Iterator))
async_connect(
Iterator begin, Iterator end,
ConnectCondition connect_condition,
IteratorConnectHandler&& handler);
IteratorConnectHandler&& handler =
net::default_completion_token_t<executor_type>{});
//--------------------------------------------------------------------------
/** Read some data.
This function is used to read some data from the stream.
The call blocks until one of the following is true:
@li One or more bytes are read from the stream.
@@ -1172,11 +1291,11 @@ public:
@param buffers The buffers into which the data will be read. If the
size of the buffers is zero bytes, the call always returns
immediately with no error.
@returns The number of bytes read.
@throws system_error Thrown on failure.
@note The `read_some` operation may not receive all of the requested
number of bytes. Consider using the function `net::read` if you need
to ensure that the requested amount of data is read before the
@@ -1202,11 +1321,11 @@ public:
@param buffers The buffers into which the data will be read. If the
size of the buffers is zero bytes, the call always returns
immediately with no error.
@param ec Set to indicate what error occurred, if any.
@returns The number of bytes read.
@note The `read_some` operation may not receive all of the requested
number of bytes. Consider using the function `net::read` if you need
to ensure that the requested amount of data is read before the
@@ -1224,7 +1343,7 @@ public:
/** Read some data asynchronously.
This function is used to asynchronously read data from the stream.
This call always returns immediately. The asynchronous operation
will continue until one of the following conditions is true:
@@ -1247,7 +1366,7 @@ public:
Although the buffers object may be copied as necessary, ownership of the
underlying memory blocks is retained by the caller, which must guarantee
that they remain valid until the handler is called.
@param handler The completion handler to invoke when the operation
completes. The implementation takes ownership of the handler by
performing a decay-copy. The equivalent function signature of
@@ -1267,17 +1386,34 @@ public:
number of bytes. Consider using the function `net::async_read` if you need
to ensure that the requested amount of data is read before the asynchronous
operation completes.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_read_some operation.
*/
template<class MutableBufferSequence, class ReadHandler>
template<
class MutableBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
net::default_completion_token_t<executor_type>
>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler);
ReadHandler&& handler =
net::default_completion_token_t<executor_type>{}
);
/** Write some data.
This function is used to write some data to the stream.
The call blocks until one of the following is true:
@li One or more bytes are written to the stream.
@@ -1289,9 +1425,9 @@ public:
with no error.
@returns The number of bytes written.
@throws system_error Thrown on failure.
@note The `write_some` operation may not transmit all of the requested
number of bytes. Consider using the function `net::write` if you need
to ensure that the requested amount of data is written before the
@@ -1307,7 +1443,7 @@ public:
/** Write some data.
This function is used to write some data to the stream.
The call blocks until one of the following is true:
@li One or more bytes are written to the stream.
@@ -1321,9 +1457,9 @@ public:
@param ec Set to indicate what error occurred, if any.
@returns The number of bytes written.
@throws system_error Thrown on failure.
@note The `write_some` operation may not transmit all of the requested
number of bytes. Consider using the function `net::write` if you need
to ensure that the requested amount of data is written before the
@@ -1341,7 +1477,7 @@ public:
/** Write some data asynchronously.
This function is used to asynchronously write data to the underlying socket.
This call always returns immediately. The asynchronous operation
will continue until one of the following conditions is true:
@@ -1364,7 +1500,7 @@ public:
Although the buffers object may be copied as necessary, ownership of the
underlying memory blocks is retained by the caller, which must guarantee
that they remain valid until the handler is called.
@param handler The completion handler to invoke when the operation
completes. The implementation takes ownership of the handler by
performing a decay-copy. The equivalent function signature of
@@ -1384,12 +1520,28 @@ public:
number of bytes. Consider using the function `net::async_write` if you need
to ensure that the requested amount of data is sent before the asynchronous
operation completes.
@par Per-Operation Cancellation
This asynchronous operation supports cancellation for the following
net::cancellation_type values:
@li @c net::cancellation_type::terminal
@li @c net::cancellation_type::partial
@li @c net::cancellation_type::total
if they are also supported by the socket's @c async_write_some operation.
*/
template<class ConstBufferSequence, class WriteHandler>
template<
class ConstBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =
net::default_completion_token_t<Executor>
>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler);
WriteHandler&& handler =
net::default_completion_token_t<Executor>{});
};
} // beast

View File

@@ -28,7 +28,7 @@ namespace beast {
The passed handler and arguments are forwarded into the returned
handler, whose associated allocator and associated executor will
will be the same as those of the original handler.
be the same as those of the original handler.
@par Example

View File

@@ -0,0 +1,177 @@
//
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_BEAST_BUFFER_REF_HPP
#define BOOST_BEAST_BUFFER_REF_HPP
#include <cstddef>
namespace boost {
namespace beast {
#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
/** The buffer ref provides a wrapper around beast buffers
* to make them usable with asio dynamic_buffer v1.
*
* v2 is current not supported, so that
* `BOOST_ASIO_NO_DYNAMIC_BUFFER_V1` mustn't be defined.
*
* @par Example
*
* @code
*
* asio::tcp::socket sock;
* beast::flat_buffer fb;
* asio::read_until(sock, ref(fb) '\n');
*
* @endcode
*
* @tparam Buffer The underlying buffer
*/
template<typename Buffer>
struct buffer_ref
{
/// The ConstBufferSequence used to represent the readable bytes.
using const_buffers_type = typename Buffer::const_buffers_type;
/// The MutableBufferSequence used to represent the writable bytes.
using mutable_buffers_type = typename Buffer::mutable_buffers_type;
/// Returns the number of readable bytes.
std::size_t
size() const noexcept
{
return buffer_.size();
}
/// Return the maximum number of bytes, both readable and writable, that can ever be held.
std::size_t
max_size() const noexcept
{
return buffer_.max_size();
}
/// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
std::size_t
capacity() const noexcept
{
return buffer_.capacity();
}
/// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
data() const noexcept
{
return buffer_.data();
}
/// Get a list of buffers that represents the output
/// sequence, with the given size.
/**
* Ensures that the output sequence can accommodate @c n bytes, resizing the
* vector object as necessary.
*
* @returns An object of type @c mutable_buffers_type that satisfies
* MutableBufferSequence requirements, representing vector memory at the
* start of the output sequence of size @c n.
*
* @throws std::length_error If <tt>size() + n > max_size()</tt>.
*
* @note The returned object is invalidated by any @c dynamic_vector_buffer
* or @c vector member function that modifies the input sequence or output
* sequence.
*/
mutable_buffers_type prepare(std::size_t n)
{
return buffer_.prepare(n);
}
/// Move bytes from the output sequence to the input
/// sequence.
/**
* @param n The number of bytes to append from the start of the output
* sequence to the end of the input sequence. The remainder of the output
* sequence is discarded.
*
* Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
* no intervening operations that modify the input or output sequence.
*
* @note If @c n is greater than the size of the output sequence, the entire
* output sequence is moved to the input sequence and no error is issued.
*/
void commit(std::size_t n)
{
return buffer_.commit(n);
}
/// Remove `n` bytes from the readable byte sequence.
/**
* @b DynamicBuffer_v1: Removes @c n characters from the beginning of the
* input sequence. @note If @c n is greater than the size of the input
* sequence, the entire input sequence is consumed and no error is issued.
*/
void consume(std::size_t n)
{
return buffer_.consume(n);
}
/// The type of the underlying buffer.
using buffer_type = Buffer;
/// Create a buffer reference around @c buffer.
buffer_ref(Buffer & buffer) : buffer_(buffer) {}
/// Copy the reference.
buffer_ref(const buffer_ref& buffer) = default;
private:
Buffer &buffer_;
};
template<class Allocator>
class basic_flat_buffer;
template<std::size_t N>
class flat_static_buffer;
template<class Allocator>
class basic_multi_buffer;
template<std::size_t N>
class static_buffer;
/// Create a buffer_ref for basic_flat_buffer.
template<class Allocator>
inline buffer_ref<basic_flat_buffer<Allocator>> ref(basic_flat_buffer<Allocator> & buf)
{
return buffer_ref<basic_flat_buffer<Allocator>>(buf);
}
/// Create a buffer_ref for flat_static_buffer.
template<std::size_t N>
inline buffer_ref<flat_static_buffer<N>> ref(flat_static_buffer<N> & buf)
{
return buffer_ref<flat_static_buffer<N>>(buf);
}
/// Create a buffer_ref for basic_multi_buffer.
template<class Allocator>
inline buffer_ref<basic_multi_buffer<Allocator>> ref(basic_multi_buffer<Allocator> & buf)
{
return buffer_ref<basic_multi_buffer<Allocator>>(buf);
}
/// Create a buffer_ref for static_buffer.
template<std::size_t N>
inline buffer_ref<static_buffer<N>> ref(static_buffer<N> & buf)
{
return buffer_ref<static_buffer<N>>(buf);
}
#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
}
}
#endif //BOOST_BEAST_BUFFER_REF_HPP

View File

@@ -140,8 +140,8 @@ using buffers_iterator_type =
argument-dependent lookup. The call `beast::buffer_bytes(b)` is
equivalent to performing:
@code
using namespace net;
buffer_bytes(b);
using net::buffer_size;
return buffer_size(b);
@endcode
In addition this handles types which are convertible to
`net::const_buffer`; these are not handled by `net::buffer_size`.

View File

@@ -261,10 +261,15 @@ public:
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
*/
template<class MutableBufferSequence, class ReadHandler>
template<
class MutableBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
net::default_completion_token_t<executor_type>>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler);
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler =
net::default_completion_token_t<executor_type>{});
/** Write some data to the stream.
@@ -335,10 +340,15 @@ public:
this function. Invocation of the handler will be performed in a
manner equivalent to using `net::post`.
*/
template<class ConstBufferSequence, class WriteHandler>
template<
class ConstBufferSequence,
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =
net::default_completion_token_t<executor_type>>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler);
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler =
net::default_completion_token_t<executor_type>{});
};
} // beast

View File

@@ -1,35 +0,0 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_BUFFERS_ADAPTER_HPP
#define BOOST_BEAST_BUFFERS_ADAPTER_HPP
#include <boost/beast/core/detail/config.hpp>
#ifdef BOOST_BEAST_ALLOW_DEPRECATED
#include <boost/beast/core/buffers_adaptor.hpp>
namespace boost {
namespace beast {
template<class MutableBufferSequence>
using buffers_adapter = buffers_adaptor<MutableBufferSequence>;
} // beast
} // boost
#else
// The new filename is <boost/beast/core/buffers_adaptor.hpp>
#error The file <boost/beast/core/buffers_adapter.hpp> is deprecated, define BOOST_BEAST_ALLOW_DEPRECATED to disable this error
#endif
#endif

View File

@@ -43,7 +43,7 @@ class buffers_adaptor
buffers_iterator_type<MutableBufferSequence>;
template<bool>
class readable_bytes;
class subrange;
MutableBufferSequence bs_;
iter_type begin_;
@@ -106,16 +106,13 @@ public:
/// The ConstBufferSequence used to represent the readable bytes.
using const_buffers_type = __implementation_defined__;
/// The MutableBufferSequence used to represent the readable bytes.
using mutable_data_type = __implementation_defined__;
/// The MutableBufferSequence used to represent the writable bytes.
using mutable_buffers_type = __implementation_defined__;
#else
using const_buffers_type = readable_bytes<false>;
using mutable_data_type = readable_bytes<true>;
class mutable_buffers_type;
using const_buffers_type = subrange<false>;
using mutable_buffers_type = subrange<true>;
#endif
/// Returns the number of readable bytes.
@@ -151,7 +148,7 @@ public:
}
/// Returns a mutable buffer sequence representing the readable bytes.
mutable_data_type
mutable_buffers_type
data() noexcept;
/** Returns a mutable buffer sequence representing writable bytes.
@@ -216,6 +213,19 @@ public:
*/
void
consume(std::size_t n) noexcept;
private:
subrange<true>
make_subrange(std::size_t pos, std::size_t n);
subrange<false>
make_subrange(std::size_t pos, std::size_t n) const;
#ifndef BOOST_BEAST_DOXYGEN
friend struct buffers_adaptor_test_hook;
#endif
};
} // beast

View File

@@ -19,7 +19,6 @@ namespace boost {
namespace beast {
/** A buffer sequence representing a concatenation of buffer sequences.
@see buffers_cat
*/
template<class... Buffers>
@@ -29,7 +28,6 @@ class buffers_cat_view
public:
/** The type of buffer returned when dereferencing an iterator.
If every buffer sequence in the view is a <em>MutableBufferSequence</em>,
then `value_type` will be `net::mutable_buffer`.
Otherwise, `value_type` will be `net::const_buffer`.
@@ -50,7 +48,6 @@ public:
buffers_cat_view& operator=(buffers_cat_view const&) = default;
/** Constructor
@param buffers The list of buffer sequences to concatenate.
Copies of the arguments will be maintained for the lifetime
of the concatenated sequence; however, the ownership of the
@@ -63,12 +60,12 @@ public:
const_iterator
begin() const;
/// Returns an iterator to one past the last buffer in the sequence
/// Returns an iterator to one past the last buffer in the sequence
const_iterator
end() const;
};
/** Concatenate 2 or more buffer sequences.
/** Concatenate 1 or more buffer sequences.
This function returns a constant or mutable buffer sequence which,
when iterated, efficiently concatenates the input buffer sequences.
@@ -76,15 +73,12 @@ public:
object does not take ownership of the underlying memory. The
application is still responsible for managing the lifetime of the
referenced memory.
@param buffers The list of buffer sequences to concatenate.
@return A new buffer sequence that represents the concatenation of
the input buffer sequences. This buffer sequence will be a
<em>MutableBufferSequence</em> if each of the passed buffer sequences is
also a <em>MutableBufferSequence</em>; otherwise the returned buffer
sequence will be a <em>ConstBufferSequence</em>.
@see buffers_cat_view
*/
#if BOOST_BEAST_DOXYGEN
@@ -92,15 +86,15 @@ template<class... BufferSequence>
buffers_cat_view<BufferSequence...>
buffers_cat(BufferSequence const&... buffers)
#else
template<class B1, class B2, class... Bn>
buffers_cat_view<B1, B2, Bn...>
buffers_cat(B1 const& b1, B2 const& b2, Bn const&... bn)
template<class B1, class... Bn>
buffers_cat_view<B1, Bn...>
buffers_cat(B1 const& b1, Bn const&... bn)
#endif
{
static_assert(
is_const_buffer_sequence<B1, B2, Bn...>::value,
is_const_buffer_sequence<B1, Bn...>::value,
"BufferSequence type requirements not met");
return buffers_cat_view<B1, B2, Bn...>{b1, b2, bn...};
return buffers_cat_view<B1, Bn...>{b1, bn...};
}
} // beast

View File

@@ -0,0 +1,199 @@
//
// Copyright (c) 2022 Seth Heeren (sgheeren at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_BUFFERS_GENERATOR_HPP
#define BOOST_BEAST_CORE_BUFFERS_GENERATOR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <type_traits>
namespace boost {
namespace beast {
/** Determine if type satisfies the <em>BuffersGenerator</em> requirements.
This metafunction is used to determine if the specified type meets the
requirements for a buffers generator.
The static member `value` will evaluate to `true` if so, `false` otherwise.
@tparam T a type to check
*/
#ifdef BOOST_BEAST_DOXYGEN
template <class T>
struct is_buffers_generator
: integral_constant<bool, automatically_determined>
{
};
#else
template<class T, class = void>
struct is_buffers_generator
: std::false_type
{
};
template<class T>
struct is_buffers_generator<
T, detail::void_t<decltype(
bool(std::declval<T const&>().is_done()),
typename T::const_buffers_type(
std::declval<T&>().prepare(
std::declval<error_code&>())),
std::declval<T&>().consume(
std::size_t{})
)>> : std::true_type
{
};
#endif
/** Write all output from a BuffersGenerator to a stream.
This function is used to write all of the buffers generated
by a caller-provided BuffersGenerator to a stream. The call
will block until one of the following conditions is true:
@li A call to the generator's `is_done` returns `false`.
@li An error occurs.
This operation is implemented in terms of one or more calls
to the stream's `write_some` function.
@param stream The stream to which the data is to be written.
The type must support the <em>SyncWriteStream</em> concept.
@param generator The generator to use.
@param ec Set to the error, if any occurred.
@return The number of bytes written to the stream.
@see BuffersGenerator
*/
template<
class SyncWriteStream,
class BuffersGenerator
#if ! BOOST_BEAST_DOXYGEN
, typename std::enable_if<is_buffers_generator<
typename std::decay<BuffersGenerator>::
type>::value>::type* = nullptr
#endif
>
std::size_t
write(
SyncWriteStream& stream,
BuffersGenerator&& generator,
beast::error_code& ec);
/** Write all output from a BuffersGenerator to a stream.
This function is used to write all of the buffers generated
by a caller-provided BuffersGenerator to a stream. The call
will block until one of the following conditions is true:
@li A call to the generator's `is_done` returns `false`.
@li An error occurs.
This operation is implemented in terms of one or more calls
to the stream's `write_some` function.
@param stream The stream to which the data is to be written.
The type must support the <em>SyncWriteStream</em> concept.
@param generator The generator to use.
@return The number of bytes written to the stream.
@throws system_error Thrown on failure.
@see BuffersGenerator
*/
template<
class SyncWriteStream,
class BuffersGenerator
#if ! BOOST_BEAST_DOXYGEN
, typename std::enable_if<is_buffers_generator<
typename std::decay<BuffersGenerator>::
type>::value>::type* = nullptr
#endif
>
std::size_t
write(
SyncWriteStream& stream,
BuffersGenerator&& generator);
/** Write all output from a BuffersGenerator asynchronously to a
stream.
This function is used to write all of the buffers generated
by a caller-provided `BuffersGenerator` to a stream. The
function call always returns immediately. The asynchronous
operation will continue until one of the following
conditions is true:
@li A call to the generator's `is_done` returns `false`.
@li An error occurs.
This operation is implemented in terms of zero or more calls
to the stream's `async_write_some` function, and is known as
a <em>composed operation</em>. The program must ensure that
the stream performs no other writes until this operation
completes.
@param stream The stream to which the data is to be written.
The type must support the <em>SyncWriteStream</em> concept.
@param generator The generator to use.
@param token The completion handler to invoke when the
operation completes. The implementation takes ownership of
the handler by performing a decay-copy. The equivalent
function signature of the handler must be:
@code
void handler(
error_code const& error, // result of operation
std::size_t bytes_transferred // the number of bytes written to the stream
);
@endcode
Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from
within this function. Invocation of the handler will be
performed in a manner equivalent to using `net::post`.
@see BuffersGenerator
*/
template<
class AsyncWriteStream,
class BuffersGenerator,
BOOST_BEAST_ASYNC_TPARAM2 CompletionToken
= net::default_completion_token_t<executor_type<AsyncWriteStream>>
#if !BOOST_BEAST_DOXYGEN
, typename std::enable_if<is_buffers_generator<
BuffersGenerator>::value>::type* = nullptr
#endif
>
BOOST_BEAST_ASYNC_RESULT2(CompletionToken)
async_write(
AsyncWriteStream& stream,
BuffersGenerator generator,
CompletionToken&& token
= net::default_completion_token_t<executor_type<AsyncWriteStream>>{});
} // beast
} // boost
#include <boost/beast/core/impl/buffers_generator.hpp>
#endif

View File

@@ -18,7 +18,7 @@
#include <type_traits>
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
#include <boost/type_traits.hpp>
#include <boost/type_traits/is_convertible.hpp>
#endif
namespace boost {

View File

@@ -120,7 +120,6 @@ buffers_range_ref(BufferSequence const& buffers)
return detail::buffers_range_adaptor<
BufferSequence const&>(buffers);
}
/** @} */
} // beast
} // boost

View File

@@ -12,7 +12,6 @@
#include <boost/beast/core/string.hpp>
#include <cctype>
#include <string>
#include <utility>
namespace boost {
@@ -78,26 +77,6 @@ decode(void* dest, char const* src, std::size_t len);
} // base64
BOOST_BEAST_DECL
std::string
base64_encode(std::uint8_t const* data, std::size_t len);
BOOST_BEAST_DECL
std::string
base64_encode(string_view s);
template<class = void>
std::string
base64_decode(string_view data)
{
std::string dest;
dest.resize(base64::decoded_size(data.size()));
auto const result = base64::decode(
&dest[0], data.data(), data.size());
dest.resize(result.first);
return dest;
}
} // detail
} // beast
} // boost

View File

@@ -154,7 +154,7 @@ decode(void* dest, char const* src, std::size_t len)
{
char* out = static_cast<char*>(dest);
auto in = reinterpret_cast<unsigned char const*>(src);
unsigned char c3[3], c4[4];
unsigned char c3[3], c4[4] = {0,0,0,0};
int i = 0;
int j = 0;
@@ -195,24 +195,6 @@ decode(void* dest, char const* src, std::size_t len)
} // base64
std::string
base64_encode(
std::uint8_t const* data,
std::size_t len)
{
std::string dest;
dest.resize(base64::encoded_size(len));
dest.resize(base64::encode(&dest[0], data, len));
return dest;
}
std::string
base64_encode(string_view s)
{
return base64_encode (reinterpret_cast <
std::uint8_t const*> (s.data()), s.size());
}
} // detail
} // beast
} // boost

View File

@@ -67,30 +67,38 @@ public:
h_, this->get());
}
template<class Function>
void
asio_handler_invoke(Function&& f,
bind_default_executor_wrapper* p)
using cancellation_slot_type =
net::associated_cancellation_slot_t<Handler>;
cancellation_slot_type
get_cancellation_slot() const noexcept
{
net::dispatch(p->get_executor(), std::move(f));
return net::get_associated_cancellation_slot(h_,
net::cancellation_slot());
}
// The allocation hooks are still defined because they trivially forward to
// user hooks. Forward here ensures that the user will get a compile error
// if they build their code with BOOST_ASIO_NO_DEPRECATED.
friend
void* asio_handler_allocate(
boost::asio::asio_handler_allocate_is_deprecated
asio_handler_allocate(
std::size_t size, bind_default_executor_wrapper* p)
{
using net::asio_handler_allocate;
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(p->h_));
}
friend
void asio_handler_deallocate(
boost::asio::asio_handler_deallocate_is_deprecated
asio_handler_deallocate(
void* mem, std::size_t size,
bind_default_executor_wrapper* p)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(mem, size,
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(mem, size,
std::addressof(p->h_));
}
@@ -98,7 +106,7 @@ public:
bool asio_handler_is_continuation(
bind_default_executor_wrapper* p)
{
using net::asio_handler_is_continuation;
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
std::addressof(p->h_));
}

View File

@@ -13,12 +13,14 @@
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/detail/tuple.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <boost/bind/std_placeholders.hpp>
#include <boost/is_placeholder.hpp>
#include <functional>
#include <type_traits>
@@ -48,6 +50,9 @@ class bind_wrapper
template<class T, class Allocator>
friend struct net::associated_allocator;
template<class T, class CancellationSlot>
friend struct net::associated_cancellation_slot;
template<class Arg, class Vals>
static
typename std::enable_if<
@@ -81,7 +86,9 @@ class bind_wrapper
static
typename std::enable_if<
boost::is_placeholder<typename
std::decay<Arg>::type>::value != 0,
std::decay<Arg>::type>::value != 0 &&
std::is_placeholder<typename
std::decay<Arg>::type>::value == 0,
tuple_element<boost::is_placeholder<
typename std::decay<Arg>::type>::value - 1,
Vals>>::type&&
@@ -155,37 +162,40 @@ public:
template<class Function>
friend
void asio_handler_invoke(
boost::asio::asio_handler_invoke_is_deprecated
asio_handler_invoke(
Function&& f, bind_wrapper* op)
{
using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(
bind_wrapper* op)
{
using net::asio_handler_is_continuation;
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
std::addressof(op->h_));
}
friend
void* asio_handler_allocate(
boost::asio::asio_handler_allocate_is_deprecated
asio_handler_allocate(
std::size_t size, bind_wrapper* op)
{
using net::asio_handler_allocate;
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
boost::asio::asio_handler_deallocate_is_deprecated
asio_handler_deallocate(
void* p, std::size_t size, bind_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
};
@@ -214,6 +224,10 @@ class bind_front_wrapper
template<class T, class Allocator>
friend struct net::associated_allocator;
template<class T, class CancellationSlot>
friend struct net::associated_cancellation_slot;
template<std::size_t... I, class... Ts>
void
invoke(
@@ -265,37 +279,40 @@ public:
template<class Function>
friend
void asio_handler_invoke(
boost::asio::asio_handler_invoke_is_deprecated
asio_handler_invoke(
Function&& f, bind_front_wrapper* op)
{
using net::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(
bind_front_wrapper* op)
{
using net::asio_handler_is_continuation;
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
std::addressof(op->h_));
}
friend
void* asio_handler_allocate(
boost::asio::asio_handler_allocate_is_deprecated
asio_handler_allocate(
std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_allocate;
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
boost::asio::asio_handler_deallocate_is_deprecated
asio_handler_deallocate(
void* p, std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
};
@@ -379,6 +396,42 @@ struct associated_allocator<
}
};
template<class Handler, class... Args, class CancellationSlot>
struct associated_cancellation_slot<
beast::detail::bind_wrapper<Handler, Args...>, CancellationSlot>
{
using type = typename
associated_cancellation_slot<Handler>::type;
static
type
get(beast::detail::bind_wrapper<Handler, Args...> const& op,
CancellationSlot const& slot = CancellationSlot{}) noexcept
{
return associated_cancellation_slot<
Handler, CancellationSlot>::get(op.h_, slot);
}
};
template<class Handler, class... Args, class CancellationSlot>
struct associated_cancellation_slot<
beast::detail::bind_front_wrapper<Handler, Args...>, CancellationSlot>
{
using type = typename
associated_cancellation_slot<Handler>::type;
static
type
get(beast::detail::bind_front_wrapper<Handler, Args...> const& op,
CancellationSlot const& slot = CancellationSlot{}) noexcept
{
return associated_cancellation_slot<
Handler, CancellationSlot>::get(op.h_, slot);
}
};
} // asio
} // boost

View File

@@ -11,6 +11,7 @@
#define BOOST_BEAST_CORE_DETAIL_BUFFER_HPP
#include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
#include <stdexcept>
@@ -33,7 +34,7 @@ dynamic_buffer_prepare_noexcept(
if(buffer.max_size() - buffer.size() < size)
{
// length error
ec = ev;
BOOST_BEAST_ASSIGN_EC(ec, ev);
return boost::none;
}
boost::optional<typename
@@ -66,7 +67,7 @@ dynamic_buffer_prepare(
}
catch(std::length_error const&)
{
ec = ev;
BOOST_BEAST_ASSIGN_EC(ec, ev);
}
return boost::none;

View File

@@ -38,13 +38,9 @@ public:
buffers_iterator_type<BufferSequence>;
iter_type it_{};
buffers_range_adaptor const* b_ = nullptr;
const_iterator(
buffers_range_adaptor const& b,
iter_type const& it)
const_iterator(iter_type const& it)
: it_(it)
, b_(&b)
{
}
@@ -62,7 +58,7 @@ public:
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
return it_ == other.it_;
}
bool
@@ -111,11 +107,6 @@ public:
}
};
buffers_range_adaptor(
buffers_range_adaptor const&) = default;
buffers_range_adaptor& operator=(
buffers_range_adaptor const&) = default;
explicit
buffers_range_adaptor(BufferSequence const& b)
: b_(b)
@@ -125,13 +116,13 @@ public:
const_iterator
begin() const noexcept
{
return {*this, net::buffer_sequence_begin(b_)};
return {net::buffer_sequence_begin(b_)};
}
const_iterator
end() const noexcept
{
return {*this, net::buffer_sequence_end(b_)};
return {net::buffer_sequence_end(b_)};
}
};

View File

@@ -0,0 +1,78 @@
//
// Copyright (c) 2019 Damian Jarek(damian.jarek93@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_DETAIL_CHAR_BUFFER_HPP
#define BOOST_BEAST_CORE_DETAIL_CHAR_BUFFER_HPP
#include <boost/config.hpp>
#include <cstddef>
#include <cstring>
#include <cstdint>
namespace boost {
namespace beast {
namespace detail {
template <std::size_t N>
class char_buffer
{
public:
bool try_push_back(char c)
{
if (size_ == N)
return false;
buf_[size_++] = c;
return true;
}
bool try_append(char const* first, char const* last)
{
std::size_t const n = last - first;
if (n > N - size_)
return false;
std::memmove(&buf_[size_], first, n);
size_ += n;
return true;
}
void clear() noexcept
{
size_ = 0;
}
char* data() noexcept
{
return buf_;
}
char const* data() const noexcept
{
return buf_;
}
std::size_t size() const noexcept
{
return size_;
}
bool empty() const noexcept
{
return size_ == 0;
}
private:
std::size_t size_= 0;
char buf_[N];
};
} // detail
} // beast
} // boost
#endif

View File

@@ -15,6 +15,7 @@
#include <boost/version.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/static_assert.hpp>
#include <boost/preprocessor/cat.hpp>
namespace boost {
namespace asio
@@ -85,12 +86,35 @@ namespace net = boost::asio;
#ifndef BOOST_BEAST_ASYNC_RESULT1
#define BOOST_BEAST_ASYNC_RESULT1(type) \
BOOST_ASIO_INITFN_RESULT_TYPE(type, void(::boost::beast::error_code))
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(type, void(::boost::beast::error_code))
#endif
#ifndef BOOST_BEAST_ASYNC_RESULT2
#define BOOST_BEAST_ASYNC_RESULT2(type) \
BOOST_ASIO_INITFN_RESULT_TYPE(type, void(::boost::beast::error_code, std::size_t))
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(type, void(::boost::beast::error_code, ::std::size_t))
#endif
#ifndef BOOST_BEAST_ASYNC_TPARAM1
#define BOOST_BEAST_ASYNC_TPARAM1 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::beast::error_code))
#endif
#ifndef BOOST_BEAST_ASYNC_TPARAM2
#define BOOST_BEAST_ASYNC_TPARAM2 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::beast::error_code, ::std::size_t))
#endif
#ifdef BOOST_BEAST_NO_SOURCE_LOCATION
#define BOOST_BEAST_ASSIGN_EC(ec, error) ec = error
#else
#define BOOST_BEAST_ASSIGN_EC(ec, error) \
static constexpr auto BOOST_PP_CAT(loc_, __LINE__) ((BOOST_CURRENT_LOCATION)); \
ec.assign(error, & BOOST_PP_CAT(loc_, __LINE__) )
#endif
#ifndef BOOST_BEAST_FILE_BUFFER_SIZE
#define BOOST_BEAST_FILE_BUFFER_SIZE 4096
#endif
#endif

View File

@@ -0,0 +1,65 @@
//
// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_BEAST_CORE_DETAIL_FILTERING_CANCELLATION_SLOT_HPP
#define BOOST_BEAST_CORE_DETAIL_FILTERING_CANCELLATION_SLOT_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/asio/cancellation_signal.hpp>
namespace boost {
namespace beast {
namespace detail {
template<typename CancellationSlot = net::cancellation_slot>
struct filtering_cancellation_slot : CancellationSlot
{
template<typename ... Args>
filtering_cancellation_slot(net::cancellation_type type, Args && ... args)
: CancellationSlot(std::forward<Args>(args)...), type(type) {}
net::cancellation_type type = net::cancellation_type::terminal;
using CancellationSlot::operator=;
template<typename Handler>
struct handler_wrapper
{
Handler handler;
const net::cancellation_type type;
template<typename ... Args>
handler_wrapper(net::cancellation_type type, Args && ... args)
: handler(std::forward<Args>(args)...),
type(type) {}
void operator()(net::cancellation_type tp)
{
if ((tp & type) != net::cancellation_type::none)
handler(tp);
}
};
template <typename CancellationHandler, typename ... Args>
CancellationHandler& emplace(Args && ... args)
{
return CancellationSlot::template emplace<handler_wrapper<CancellationHandler>>(
type, std::forward<Args>(args)...).handler;
}
template <typename CancellationHandler>
CancellationHandler& assign(CancellationHandler && ch)
{
return CancellationSlot::template emplace<handler_wrapper<CancellationHandler>>(
type, std::forward<CancellationHandler>(ch)).handler;
}
};
}
}
}
#endif //BOOST_BEAST_CORE_DETAIL_FILTERING_CANCELLATION_SLOT_HPP

View File

@@ -11,6 +11,9 @@
#define BOOST_BEAST_DETAIL_GET_IO_CONTEXT_HPP
#include <boost/beast/core/stream_traits.hpp>
#ifdef BOOST_ASIO_NO_TS_EXECUTORS
#include <boost/asio/execution.hpp>
#endif
#include <boost/asio/executor.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp>
@@ -34,7 +37,7 @@ inline
net::io_context*
get_io_context(net::io_context::executor_type const& ex)
{
return std::addressof(ex.context());
return std::addressof(net::query(ex, net::execution::context));
}
inline
@@ -42,8 +45,7 @@ net::io_context*
get_io_context(net::strand<
net::io_context::executor_type> const& ex)
{
return std::addressof(
ex.get_inner_executor().context());
return get_io_context(ex.get_inner_executor());
}
template<class Executor>
@@ -56,7 +58,7 @@ get_io_context(net::strand<Executor> const& ex)
template<
class T,
class = typename std::enable_if<
std::is_same<T, net::executor>::value>::type>
std::is_same<T, net::executor>::value || std::is_same<T, net::any_io_executor>::value>::type>
net::io_context*
get_io_context(T const& ex)
{
@@ -64,7 +66,7 @@ get_io_context(T const& ex)
net::io_context::executor_type>();
if(! p)
return nullptr;
return std::addressof(p->context());
return get_io_context(*p);
}
inline

View File

@@ -13,6 +13,7 @@
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/throw_exception.hpp>
@@ -37,7 +38,7 @@ template<
class Condition,
class Handler>
class read_op
: public net::coroutine
: public asio::coroutine
, public async_base<
Handler, beast::executor_type<Stream>>
{
@@ -73,18 +74,12 @@ public:
std::size_t bytes_transferred,
bool cont = true)
{
std::size_t max_size;
std::size_t max_prepare;
BOOST_ASIO_CORO_REENTER(*this)
{
for(;;)
{
max_size = cond_(ec, total_, b_);
max_prepare = 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()));
max_prepare = beast::read_size(b_, cond_(ec, total_, b_));
if(max_prepare == 0)
break;
BOOST_ASIO_CORO_YIELD
@@ -101,7 +96,7 @@ public:
BOOST_ASIO_CORO_YIELD
s_.async_read_some(
b_.prepare(0), std::move(*this));
ec = ec_;
BOOST_BEAST_ASSIGN_EC(ec, ec_);
}
this->complete_now(ec, total_);
}
@@ -201,16 +196,10 @@ read(
"CompletionCondition type requirements not met");
ec = {};
std::size_t total = 0;
std::size_t max_size;
std::size_t max_prepare;
for(;;)
{
max_size = cond(ec, total, buffer);
max_prepare = std::min<std::size_t>(
std::max<std::size_t>(
512, buffer.capacity() - buffer.size()),
std::min<std::size_t>(
max_size, buffer.max_size() - buffer.size()));
max_prepare = beast::read_size(buffer, cond(ec, total, buffer));
if(max_prepare == 0)
break;
std::size_t const bytes_transferred =
@@ -225,7 +214,7 @@ template<
class AsyncReadStream,
class DynamicBuffer,
class CompletionCondition,
class ReadHandler,
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler,
class>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read(

View File

@@ -0,0 +1,69 @@
//
// Copyright (c) 2019 Damian Jarek(damian.jarek93@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_DETAIL_IMPL_TEMPORARY_BUFFER_IPP
#define BOOST_BEAST_DETAIL_IMPL_TEMPORARY_BUFFER_IPP
#include <boost/beast/core/detail/temporary_buffer.hpp>
#include <boost/beast/core/detail/clamp.hpp>
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <memory>
#include <cstring>
namespace boost {
namespace beast {
namespace detail {
void
temporary_buffer::
append(string_view s)
{
grow(s.size());
unchecked_append(s);
}
void
temporary_buffer::
append(string_view s1, string_view s2)
{
grow(s1.size() + s2.size());
unchecked_append(s1);
unchecked_append(s2);
}
void
temporary_buffer::
unchecked_append(string_view s)
{
auto n = s.size();
std::memcpy(&data_[size_], s.data(), n);
size_ += n;
}
void
temporary_buffer::
grow(std::size_t n)
{
if (capacity_ - size_ >= n)
return;
auto const capacity = (n + size_) * 2u;
BOOST_ASSERT(! detail::sum_exceeds(
n, size_, capacity));
char* const p = new char[capacity];
std::memcpy(p, data_, size_);
deallocate(boost::exchange(data_, p));
capacity_ = capacity;
}
} // detail
} // beast
} // boost
#endif

View File

@@ -10,6 +10,8 @@
#ifndef BOOST_BEAST_DETAIL_IS_INVOCABLE_HPP
#define BOOST_BEAST_DETAIL_IS_INVOCABLE_HPP
#include <boost/asio/async_result.hpp>
#include <boost/type_traits/make_void.hpp>
#include <type_traits>
#include <utility>
@@ -51,6 +53,26 @@ struct is_invocable<C, R(A...)>
};
/** @} */
template<class CompletionToken, class Signature, class = void>
struct is_completion_token_for : std::false_type
{
};
struct any_initiation
{
template<class...AnyArgs>
void operator()(AnyArgs&&...);
};
template<class CompletionToken, class R, class...Args>
struct is_completion_token_for<
CompletionToken, R(Args...), boost::void_t<decltype(
boost::asio::async_initiate<CompletionToken, R(Args...)>(
any_initiation(), std::declval<CompletionToken&>())
)>> : std::true_type
{
};
} // detail
} // beast
} // boost

View File

@@ -12,7 +12,6 @@
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_range.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/throw_exception.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
@@ -43,7 +42,7 @@ class ostream_buffer;
template<class DynamicBuffer, class CharT, class Traits>
class ostream_buffer
<DynamicBuffer, CharT, Traits, true>
<DynamicBuffer, CharT, Traits, true> final
: public std::basic_streambuf<CharT, Traits>
{
using int_type = typename
@@ -67,6 +66,7 @@ public:
ostream_buffer(DynamicBuffer& b)
: b_(b)
{
b_.prepare(0);
}
int_type
@@ -100,6 +100,7 @@ public:
b_.commit(
(this->pptr() - this->pbase()) *
sizeof(CharT));
this->setp(nullptr, nullptr);
return 0;
}
};
@@ -169,6 +170,7 @@ public:
b_.commit(
(this->pptr() - this->pbase()) *
sizeof(CharT));
this->setp(nullptr, nullptr);
return 0;
}
};

View File

@@ -219,7 +219,7 @@ template<
class AsyncReadStream,
class DynamicBuffer,
class CompletionCondition,
class ReadHandler
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler
#if ! BOOST_BEAST_DOXYGEN
, class = typename std::enable_if<
is_async_read_stream<AsyncReadStream>::value &&

View File

@@ -10,7 +10,6 @@
#ifndef BOOST_BEAST_DETAIL_REMAP_POST_TO_DEFER_HPP
#define BOOST_BEAST_DETAIL_REMAP_POST_TO_DEFER_HPP
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/core/empty_value.hpp>
#include <type_traits>

View File

@@ -16,15 +16,10 @@ namespace boost {
namespace beast {
namespace detail {
template<class T>
struct service_id : net::execution_context::id
{
};
template<class T>
struct service_base : net::execution_context::service
{
static service_id<T> id;
static net::execution_context::id const id;
explicit
service_base(net::execution_context& ctx)
@@ -34,7 +29,7 @@ struct service_base : net::execution_context::service
};
template<class T>
service_id<T> service_base<T>::id;
net::execution_context::id const service_base<T>::id;
} // detail
} // beast

View File

@@ -11,10 +11,8 @@
#define BOOST_BEAST_DETAIL_SHA1_HPP
#include <boost/beast/core/detail/config.hpp>
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <cstddef>
// Based on https://github.com/vog/sha1
/*

View File

@@ -10,56 +10,15 @@
#ifndef BOOST_BEAST_DETAIL_STATIC_STRING_HPP
#define BOOST_BEAST_DETAIL_STATIC_STRING_HPP
#include <boost/beast/core/string.hpp>
#include <boost/assert.hpp>
#include <iterator>
#include <boost/core/ignore_unused.hpp>
#include <string>
#include <type_traits>
namespace boost {
namespace beast {
namespace detail {
// Because k-ballo said so
template<class T>
using is_input_iterator =
std::integral_constant<bool,
! std::is_integral<T>::value>;
template<class CharT, class Traits>
int
lexicographical_compare(
CharT const* s1, std::size_t n1,
CharT const* s2, std::size_t n2)
{
if(n1 < n2)
return Traits::compare(
s1, s2, n1) <= 0 ? -1 : 1;
if(n1 > n2)
return Traits::compare(
s1, s2, n2) >= 0 ? 1 : -1;
return Traits::compare(s1, s2, n1);
}
template<class CharT, class Traits>
int
lexicographical_compare(
basic_string_view<CharT, Traits> s1,
CharT const* s2, std::size_t n2)
{
return detail::lexicographical_compare<
CharT, Traits>(s1.data(), s1.size(), s2, n2);
}
template<class CharT, class Traits>
int
lexicographical_compare(
basic_string_view<CharT, Traits> s1,
basic_string_view<CharT, Traits> s2)
{
return detail::lexicographical_compare<CharT, Traits>(
s1.data(), s1.size(), s2.data(), s2.size());
}
// Maximum number of characters in the decimal
// representation of a binary number. This includes
// the potential minus sign.

View File

@@ -39,16 +39,21 @@ struct stream_base
std::chrono::steady_clock::time_point;
using tick_type = std::uint64_t;
struct op_state
template<typename Executor>
struct basic_op_state
{
net::steady_timer timer; // for timing out
net::basic_waitable_timer<
std::chrono::steady_clock,
net::wait_traits<
std::chrono::steady_clock>,
Executor> timer; // for timing out
tick_type tick = 0; // counts waits
bool pending = false; // if op is pending
bool timeout = false; // if timed out
template<class... Args>
explicit
op_state(Args&&... args)
basic_op_state(Args&&... args)
: timer(std::forward<Args>(args)...)
{
}
@@ -56,22 +61,35 @@ struct stream_base
class pending_guard
{
bool& b_;
bool* b_ = nullptr;
bool clear_ = true;
public:
~pending_guard()
{
if(clear_)
b_ = false;
if(clear_ && b_)
*b_ = false;
}
pending_guard()
: b_(nullptr)
, clear_(true)
{
}
explicit
pending_guard(bool& b)
: b_(b)
: b_(&b)
{
BOOST_ASSERT(! b_);
b_ = true;
// If this assert goes off, it means you are attempting
// to issue two of the same asynchronous I/O operation
// at the same time, without waiting for the first one
// to complete. For example, attempting two simultaneous
// calls to async_read_some. Only one pending call of
// each I/O type (read and write) is permitted.
//
BOOST_ASSERT(! *b_);
*b_ = true;
}
pending_guard(
@@ -82,11 +100,29 @@ struct stream_base
{
}
void assign(bool& b)
{
BOOST_ASSERT(!b_);
BOOST_ASSERT(clear_);
b_ = &b;
// If this assert goes off, it means you are attempting
// to issue two of the same asynchronous I/O operation
// at the same time, without waiting for the first one
// to complete. For example, attempting two simultaneous
// calls to async_read_some. Only one pending call of
// each I/O type (read and write) is permitted.
//
BOOST_ASSERT(! *b_);
*b_ = true;
}
void
reset()
{
BOOST_ASSERT(clear_);
b_ = false;
if (b_)
*b_ = false;
clear_ = false;
}
};

View File

@@ -0,0 +1,44 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_DETAIL_STRING_HPP
#define BOOST_BEAST_DETAIL_STRING_HPP
#include <boost/beast/core/string_type.hpp>
namespace boost {
namespace beast {
namespace detail {
// Pulling in the UDL directly breaks in some places on MSVC,
// so introduce a namespace for this purprose.
namespace string_literals {
inline
string_view
operator"" _sv(char const* p, std::size_t n)
{
return string_view{p, n};
}
} // string_literals
inline
char
ascii_tolower(char c)
{
return ((static_cast<unsigned>(c) - 65U) < 26) ?
c + 'a' - 'A' : c;
}
} // detail
} // beast
} // boost
#endif

View File

@@ -0,0 +1,83 @@
//
// Copyright (c) 2019 Damian Jarek(damian.jarek93@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_DETAIL_TEMPORARY_BUFFER_HPP
#define BOOST_BEAST_DETAIL_TEMPORARY_BUFFER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/string.hpp>
#include <memory>
namespace boost {
namespace beast {
namespace detail {
struct temporary_buffer
{
temporary_buffer() = default;
temporary_buffer(temporary_buffer const&) = delete;
temporary_buffer& operator=(temporary_buffer const&) = delete;
~temporary_buffer() noexcept
{
deallocate(data_);
}
BOOST_BEAST_DECL
void
append(string_view s);
BOOST_BEAST_DECL
void
append(string_view s1, string_view s2);
string_view
view() const noexcept
{
return {data_, size_};
}
bool
empty() const noexcept
{
return size_ == 0;
}
private:
BOOST_BEAST_DECL
void
unchecked_append(string_view s);
BOOST_BEAST_DECL
void
grow(std::size_t n);
void
deallocate(char* data) noexcept
{
if (data != buffer_)
delete[] data;
}
char buffer_[4096];
char* data_ = buffer_;
std::size_t capacity_ = sizeof(buffer_);
std::size_t size_ = 0;
};
} // detail
} // beast
} // boost
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/beast/core/detail/impl/temporary_buffer.ipp>
#endif
#endif

View File

@@ -1,5 +1,5 @@
//
// Copyright (c) 2016-2019Damian Jarek (damian dot jarek93 at gmail dot com)
// Copyright (c) 2016-2019 Damian Jarek (damian dot jarek93 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -10,36 +10,14 @@
#ifndef BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP
#define BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/mp11/function.hpp>
#include <boost/type_traits/make_void.hpp>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <string>
#include <utility>
#include <new>
namespace boost {
namespace beast {
namespace detail {
// variadic min
template<class T>
T constexpr min(T t)
{
return t;
}
template<class T, class...Tn>
T constexpr min(T t0, T t1, Tn... tn)
{
return (t0 < t1) ?
(detail::min)(t0, tn...) :
(detail::min)(t1, tn...);
}
template<class U>
std::size_t constexpr
max_sizeof()
@@ -97,32 +75,17 @@ using aligned_union_t =
//------------------------------------------------------------------------------
template<class T>
void
accept_rv(T){}
//------------------------------------------------------------------------------
// for span
template<class T, class E, class = void>
struct is_contiguous_container: std::false_type {};
template<class T, class E>
struct is_contiguous_container<T, E, void_t<
decltype(
std::declval<std::size_t&>() = std::declval<T const&>().size(),
std::declval<E*&>() = std::declval<T&>().data()),
typename std::enable_if<
std::is_same<
typename std::remove_cv<E>::type,
typename std::remove_cv<
typename std::remove_pointer<
decltype(std::declval<T&>().data())
>::type
>::type
>::value
>::type>>: std::true_type
{};
template <class T, class U>
T launder_cast(U* u)
{
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
return std::launder(reinterpret_cast<T>(u));
#elif defined(BOOST_GCC) && BOOST_GCC_VERSION > 80000
return __builtin_launder(reinterpret_cast<T>(u));
#else
return reinterpret_cast<T>(u);
#endif
}
} // detail
} // beast

View File

@@ -45,7 +45,7 @@ class variant
{
using T =
mp11::mp_at_c<variant, I::value - 1>;
reinterpret_cast<T&>(self.buf_).~T();
detail::launder_cast<T*>(&self.buf_)->~T();
}
};
@@ -64,7 +64,7 @@ class variant
using T =
mp11::mp_at_c<variant, I::value - 1>;
::new(&self.buf_) T(
reinterpret_cast<T const&>(other.buf_));
*detail::launder_cast<T const*>(&other.buf_));
self.i_ = I::value;
}
};
@@ -83,9 +83,9 @@ class variant
{
using T =
mp11::mp_at_c<variant, I::value - 1>;
::new(&self.buf_) T(
reinterpret_cast<T&&>(other.buf_));
reinterpret_cast<T&>(other.buf_).~T();
::new(&self.buf_) T(std::move(
*detail::launder_cast<T*>(&other.buf_)));
detail::launder_cast<T*>(&other.buf_)->~T();
self.i_ = I::value;
}
};
@@ -106,8 +106,8 @@ class variant
using T =
mp11::mp_at_c<variant, I::value - 1>;
return
reinterpret_cast<T const&>(self.buf_) ==
reinterpret_cast<T const&>(other.buf_);
*detail::launder_cast<T const*>(&self.buf_) ==
*detail::launder_cast<T const*>(&other.buf_);
}
};
@@ -181,7 +181,7 @@ public:
}
return *this;
}
variant& operator=(variant const& other)
{
if(this != &other)
@@ -208,7 +208,7 @@ public:
get()
{
BOOST_ASSERT(i_ == I);
return *reinterpret_cast<
return *detail::launder_cast<
mp11::mp_at_c<variant, I - 1>*>(&buf_);
}
@@ -217,7 +217,7 @@ public:
get() const
{
BOOST_ASSERT(i_ == I);
return *reinterpret_cast<
return *detail::launder_cast<
mp11::mp_at_c<variant, I - 1> const*>(&buf_);
}

View File

@@ -0,0 +1,82 @@
//
// Copyright (c) 2019 Mika Fischer (mika.fischer@zoopnet.de)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_DETAIL_WIN32_UNICODE_PATH_HPP
#define BOOST_BEAST_CORE_DETAIL_WIN32_UNICODE_PATH_HPP
#ifdef _WIN32
#include <boost/config.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/winapi/character_code_conversion.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/get_last_error.hpp>
#include <array>
#include <vector>
namespace boost {
namespace beast {
namespace detail {
class win32_unicode_path
{
using WCHAR_ = boost::winapi::WCHAR_;
public:
win32_unicode_path(const char* utf8_path, error_code& ec) {
int ret = mb2wide(utf8_path, static_buf_.data(),
static_buf_.size());
if (ret == 0)
{
int sz = mb2wide(utf8_path, nullptr, 0);
if (sz == 0)
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return;
}
dynamic_buf_.resize(sz);
int ret2 = mb2wide(utf8_path,
dynamic_buf_.data(),
dynamic_buf_.size());
if (ret2 == 0)
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return;
}
}
}
WCHAR_ const* c_str() const noexcept
{
return dynamic_buf_.empty()
? static_buf_.data()
: dynamic_buf_.data();
}
private:
int mb2wide(const char* utf8_path, WCHAR_* buf, size_t sz)
{
return boost::winapi::MultiByteToWideChar(
boost::winapi::CP_UTF8_,
boost::winapi::MB_ERR_INVALID_CHARS_,
utf8_path, -1,
buf, static_cast<int>(sz));
}
std::array<WCHAR_, boost::winapi::MAX_PATH_> static_buf_;
std::vector<WCHAR_> dynamic_buf_;
};
} // detail
} // beast
} // boost
#endif
#endif

View File

@@ -0,0 +1,93 @@
#ifndef BOOST_BEAST_CORE_DETAIL_WORK_GUARD_HPP
#define BOOST_BEAST_CORE_DETAIL_WORK_GUARD_HPP
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/execution.hpp>
#include <boost/optional.hpp>
namespace boost {
namespace beast {
namespace detail {
template<class Executor, class Enable = void>
struct select_work_guard;
template<class Executor>
using select_work_guard_t = typename
select_work_guard<Executor>::type;
#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template<class Executor>
struct select_work_guard
<
Executor,
typename std::enable_if
<
net::is_executor<Executor>::value
>::type
>
{
using type = net::executor_work_guard<Executor>;
};
#endif
template<class Executor>
struct execution_work_guard
{
using executor_type = typename std::decay<decltype(
net::prefer(std::declval<Executor const&>(),
net::execution::outstanding_work.tracked))>::type;
execution_work_guard(Executor const& exec)
: ex_(net::prefer(exec, net::execution::outstanding_work.tracked))
{
}
executor_type
get_executor() const noexcept
{
BOOST_ASSERT(ex_.has_value());
return *ex_;
}
void reset() noexcept
{
ex_.reset();
}
private:
boost::optional<executor_type> ex_;
};
template<class Executor>
struct select_work_guard
<
Executor,
typename std::enable_if
<
net::execution::is_executor<Executor>::value
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
|| net::is_executor<Executor>::value
#else
&& !net::is_executor<Executor>::value
#endif
>::type
>
{
using type = execution_work_guard<Executor>;
};
template<class Executor>
select_work_guard_t<Executor>
make_work_guard(Executor const& exec) noexcept
{
return select_work_guard_t<Executor>(exec);
}
}
}
}
#endif // BOOST_BEAST_CORE_DETAIL_WORK_GUARD_HPP

View File

@@ -316,7 +316,9 @@ detect_ssl(
template<
class AsyncReadStream,
class DynamicBuffer,
class CompletionToken>
class CompletionToken =
net::default_completion_token_t<beast::executor_type<AsyncReadStream>>
>
#if BOOST_BEAST_DOXYGEN
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, bool))
#else
@@ -325,7 +327,8 @@ auto
async_detect_ssl(
AsyncReadStream& stream,
DynamicBuffer& buffer,
CompletionToken&& token) ->
CompletionToken&& token = net::default_completion_token_t<
beast::executor_type<AsyncReadStream>>{}) ->
typename net::async_result<
typename std::decay<CompletionToken>::type, /*< `async_result` customizes the return value based on the completion token >*/
void(error_code, bool)>::return_type; /*< This is the signature for the completion handler >*/
@@ -371,13 +374,13 @@ struct run_detect_ssl_op
void operator()(
DetectHandler&& h,
AsyncReadStream* s, // references are passed as pointers
DynamicBuffer& b)
DynamicBuffer* b)
{
detect_ssl_op<
typename std::decay<DetectHandler>::type,
AsyncReadStream,
DynamicBuffer>(
std::forward<DetectHandler>(h), *s, b);
std::forward<DetectHandler>(h), *s, *b);
}
};
@@ -430,14 +433,13 @@ async_detect_ssl(
// Non-const references need to be passed as pointers,
// since we don't want a decay-copy.
return net::async_initiate<
CompletionToken,
void(error_code, bool)>(
detail::run_detect_ssl_op{},
token,
&stream, // pass the reference by pointer
buffer);
&buffer);
}
//]
@@ -505,7 +507,7 @@ public:
AsyncReadStream& stream,
DynamicBuffer& buffer)
: beast::async_base<
DetectHandler_,
DetectHandler,
beast::executor_type<AsyncReadStream>>(
std::forward<DetectHandler_>(handler),
stream.get_executor())
@@ -589,8 +591,19 @@ operator()(error_code ec, std::size_t bytes_transferred, bool cont)
// by the move, are first moved to the stack before calling the
// initiating function.
yield stream_.async_read_some(buffer_.prepare(
read_size(buffer_, 1536)), std::move(*this));
yield
{
// This macro facilitates asynchrnous handler tracking and
// debugging when the preprocessor macro
// BOOST_ASIO_CUSTOM_HANDLER_TRACKING is defined.
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"async_detect_ssl"));
stream_.async_read_some(buffer_.prepare(
read_size(buffer_, 1536)), std::move(*this));
}
// Commit what we read into the buffer's input area.
buffer_.commit(bytes_transferred);
@@ -624,10 +637,17 @@ operator()(error_code ec, std::size_t bytes_transferred, bool cont)
// used in the call to async_read_some above, to avoid
// instantiating another version of the function template.
yield stream_.async_read_some(buffer_.prepare(0), std::move(*this));
yield
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"async_detect_ssl"));
stream_.async_read_some(buffer_.prepare(0), std::move(*this));
}
// Restore the saved error code
ec = ec_;
BOOST_BEAST_ASSIGN_EC(ec, ec_);
}
// Invoke the final handler.

View File

@@ -73,15 +73,14 @@ enum class file_mode
*/
write_existing,
/** Appending to a new or truncated file
/** Appending to a new or existing file
The current file position shall be set to the end of
the file prior to each write.
@li If the file does not exist, it is created.
@li If the file exists, it is truncated to
zero size upon opening.
@li If the file exists, the new data gets appended.
*/
append,

View File

@@ -26,14 +26,14 @@ namespace beast {
*/
class file_stdio
{
FILE* f_ = nullptr;
std::FILE* f_ = nullptr;
public:
/** The type of the underlying file handle.
This is platform-specific.
*/
using native_handle_type = FILE*;
using native_handle_type = std::FILE*;
/** Destructor
@@ -63,7 +63,7 @@ public:
file_stdio& operator=(file_stdio&& other);
/// Returns the native handle associated with the file.
FILE*
std::FILE*
native_handle() const
{
return f_;
@@ -77,7 +77,7 @@ public:
*/
BOOST_BEAST_DECL
void
native_handle(FILE* f);
native_handle(std::FILE* f);
/// Returns `true` if the file is open
bool

View File

@@ -13,7 +13,7 @@
#include <boost/beast/core/detail/config.hpp>
#if ! defined(BOOST_BEAST_USE_WIN32_FILE)
# ifdef BOOST_MSVC
# ifdef _WIN32
# define BOOST_BEAST_USE_WIN32_FILE 1
# else
# define BOOST_BEAST_USE_WIN32_FILE 0

View File

@@ -358,17 +358,17 @@ public:
void
reserve(std::size_t n);
/** Reallocate the buffer to fit the readable bytes exactly.
/** Request the removal of unused capacity.
Buffer sequences previously obtained using @ref data or
@ref prepare become invalid.
This function attempts to reduce @ref capacity()
to @ref size(), which may not succeed.
@esafe
Strong guarantee.
No-throw guarantee.
*/
void
shrink_to_fit();
shrink_to_fit() noexcept;
/** Set the size of the readable and writable bytes to zero.
@@ -396,9 +396,6 @@ public:
/// The ConstBufferSequence used to represent the readable bytes.
using const_buffers_type = net::const_buffer;
/// The MutableBufferSequence used to represent the readable bytes.
using mutable_data_type = net::mutable_buffer;
/// The MutableBufferSequence used to represent the writable bytes.
using mutable_buffers_type = net::mutable_buffer;
@@ -438,7 +435,7 @@ public:
}
/// Returns a mutable buffer sequence representing the readable bytes
mutable_data_type
mutable_buffers_type
data() noexcept
{
return {in_, dist(in_, out_)};

View File

@@ -92,31 +92,11 @@ public:
void
clear() noexcept;
#ifdef BOOST_BEAST_ALLOW_DEPRECATED
/// Change the number of readable and writable bytes to zero.
void
reset() noexcept
{
clear();
}
#elif ! BOOST_BEAST_DOXYGEN
template<std::size_t I = 0>
void
reset() noexcept
{
static_assert(I != 0,
BOOST_BEAST_DEPRECATION_STRING);
}
#endif
//--------------------------------------------------------------------------
/// The ConstBufferSequence used to represent the readable bytes.
using const_buffers_type = net::const_buffer;
/// The MutableBufferSequence used to represent the readable bytes.
using mutable_data_type = net::mutable_buffer;
/// The MutableBufferSequence used to represent the writable bytes.
using mutable_buffers_type = net::mutable_buffer;
@@ -156,7 +136,7 @@ public:
}
/// Returns a mutable buffer sequence representing the readable bytes
mutable_data_type
mutable_buffers_type
data() noexcept
{
return {in_, dist(in_, out_)};

View File

@@ -253,11 +253,13 @@ public:
*/
template<
class MutableBufferSequence,
class ReadHandler>
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler =
net::default_completion_token_t<executor_type>>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler);
ReadHandler&& handler =
net::default_completion_token_t<executor_type>{});
/** Write some data to the stream.
@@ -332,11 +334,13 @@ public:
*/
template<
class ConstBufferSequence,
class WriteHandler>
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler =
net::default_completion_token_t<executor_type>>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler);
WriteHandler&& handler =
net::default_completion_token_t<executor_type>{});
};
} // beast

View File

@@ -1,229 +0,0 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_HANDLER_PTR_HPP
#define BOOST_BEAST_HANDLER_PTR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/assert.hpp>
#include <boost/config/pragma_message.hpp>
#include <type_traits>
#include <utility>
#ifndef BOOST_BEAST_DOXYGEN
BOOST_PRAGMA_MESSAGE("<boost/beast/core/handler_ptr.hpp> is DEPRECATED and will be removed in a future release.")
namespace boost {
namespace beast {
/** A smart pointer container with associated completion handler.
This is a smart pointer that retains unique ownership of an
object through a pointer. Memory is managed using the allocator
associated with a completion handler stored in the object. The
managed object is destroyed and its memory deallocated when one
of the following occurs:
@li The function @ref invoke is called.
@li The function @ref release_handler is called.
@li The container is destroyed.
Objects of this type are used in the implementation of composed
operations with states that are expensive or impossible to move.
This container manages that non-trivial state on behalf of the
composed operation.
@par Thread Safety
@e Distinct @e objects: Safe.@n
@e Shared @e objects: Unsafe.
@tparam T The type of the owned object. Must be noexcept destructible.
@tparam Handler The type of the completion handler.
*/
template<class T, class Handler>
class handler_ptr
{
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
static_assert(sizeof(T) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
T* t_ = nullptr;
union
{
Handler h_;
};
void clear();
public:
/// The type of element stored
using element_type = T;
/// The type of handler stored
using handler_type = Handler;
/// Default constructor (deleted).
handler_ptr() = delete;
/// Copy assignment (deleted).
handler_ptr& operator=(handler_ptr const&) = delete;
/// Move assignment (deleted).
handler_ptr& operator=(handler_ptr &&) = delete;
/** Destructor
If `*this` owns an object the object is destroyed and
the memory deallocated using the allocator associated
with the handler.
*/
~handler_ptr();
/** Move constructor.
When this call returns, the moved-from container
will have no owned object.
*/
handler_ptr(handler_ptr&& other);
/// Copy constructor (deleted).
handler_ptr(handler_ptr const& other) = delete;
/** Constructor
This creates a new container with an owned object of
type `T`. The allocator associated with the handler will
be used to allocate memory for the owned object. The
constructor for the owned object will be called with the
following equivalent signature:
@code
T::T(Handler const&, Args&&...)
@endcode
@esafe
Strong guarantee.
@param handler The handler to associate with the owned object.
The implementation takes ownership of the handler by performing a decay-copy.
@param args Optional arguments forwarded to
the owned object's constructor.
*/
template<class DeducedHandler, class... Args>
explicit
handler_ptr(DeducedHandler&& handler, Args&&... args);
/// Return a reference to the handler
handler_type const&
handler() const noexcept
{
return h_;
}
/// Return a reference to the handler
handler_type&
handler() noexcept
{
return h_;
}
/// Return `true` if `*this` owns an object
bool
has_value() const noexcept
{
return t_ != nullptr;
}
/** Return a pointer to the owned object.
@par Preconditions:
`has_value() == true`
*/
T*
get() const
{
BOOST_ASSERT(t_);
return t_;
}
/** Return a reference to the owned object.
@par Preconditions:
`has_value() == true`
*/
T&
operator*() const
{
BOOST_ASSERT(t_);
return *t_;
}
/// Return a pointer to the owned object.
T*
operator->() const
{
BOOST_ASSERT(t_);
return t_;
}
/** Returns ownership of the handler
Before this function returns, the owned object is
destroyed, satisfying the deallocation-before-invocation
Asio guarantee.
@return The released handler.
@par Preconditions:
`has_value() == true`
@par Postconditions:
`has_value() == false`
*/
handler_type
release_handler();
/** Invoke the handler in the owned object.
This function invokes the handler in the owned object
with a forwarded argument list. Before the invocation,
the owned object is destroyed, satisfying the
deallocation-before-invocation Asio guarantee.
@par Preconditions:
`has_value() == true`
@par Postconditions:
`has_value() == false`
@note Care must be taken when the arguments are themselves
stored in the owned object. Such arguments must first be
moved to the stack or elsewhere, and then passed, or else
undefined behavior will result.
*/
template<class... Args>
void
invoke(Args&&... args);
};
} // beast
} // boost
#include <boost/beast/core/impl/handler_ptr.hpp>
#endif
#endif

View File

@@ -42,8 +42,9 @@ struct allocate_stable_state final
allocate_stable_state>;
A a(this->get());
detail::allocator_traits<A>::destroy(a, this);
detail::allocator_traits<A>::deallocate(a, this, 1);
auto* p = this;
p->~allocate_stable_state();
a.deallocate(p, 1);
}
};
@@ -54,12 +55,13 @@ template<
class Executor1,
class Allocator,
class Function>
void asio_handler_invoke(
boost::asio::asio_handler_invoke_is_deprecated
asio_handler_invoke(
Function&& f,
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_invoke;
asio_handler_invoke(f,
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f,
p->get_legacy_handler_pointer());
}
@@ -67,12 +69,12 @@ template<
class Handler,
class Executor1,
class Allocator>
void*
boost::asio::asio_handler_allocate_is_deprecated
asio_handler_allocate(
std::size_t size,
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_allocate;
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(size,
p->get_legacy_handler_pointer());
}
@@ -81,13 +83,13 @@ template<
class Handler,
class Executor1,
class Allocator>
void
boost::asio::asio_handler_deallocate_is_deprecated
asio_handler_deallocate(
void* mem, std::size_t size,
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(mem, size,
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(mem, size,
p->get_legacy_handler_pointer());
}
@@ -99,7 +101,7 @@ bool
asio_handler_is_continuation(
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_is_continuation;
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
p->get_legacy_handler_pointer());
}
@@ -118,33 +120,30 @@ allocate_stable(
{
using allocator_type = typename stable_async_base<
Handler, Executor1, Allocator>::allocator_type;
using state = detail::allocate_stable_state<
State, allocator_type>;
using A = typename detail::allocator_traits<
allocator_type>::template rebind_alloc<
detail::allocate_stable_state<
State, allocator_type>>;
allocator_type>::template rebind_alloc<state>;
struct deleter
{
allocator_type alloc;
detail::allocate_stable_state<
State, allocator_type>* ptr;
state* ptr;
~deleter()
{
if(ptr)
{
A a(alloc);
detail::allocator_traits<A>::deallocate(a, ptr, 1);
a.deallocate(ptr, 1);
}
}
};
A a(base.get_allocator());
deleter d{base.get_allocator(), nullptr};
d.ptr = detail::allocator_traits<A>::allocate(a, 1);
detail::allocator_traits<A>::construct(a, d.ptr,
d.alloc, std::forward<Args>(args)...);
deleter d{base.get_allocator(), a.allocate(1)};
::new(static_cast<void*>(d.ptr))
state(d.alloc, std::forward<Args>(args)...);
d.ptr->next_ = base.list_;
base.list_ = d.ptr;
return boost::exchange(d.ptr, nullptr)->value;

View File

@@ -13,9 +13,7 @@
#include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/websocket/teardown.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/assert.hpp>
#include <boost/make_shared.hpp>
@@ -145,28 +143,43 @@ template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
impl_type::
close()
close() noexcept
{
socket.close();
{
error_code ec;
socket.close(ec);
}
#if !defined(BOOST_NO_EXCEPTIONS)
try
{
timer.cancel();
}
catch(...)
{
}
#else
timer.cancel();
// have to let the read/write ops cancel the timer,
// otherwise we will get error::timeout on close when
// we actually want net::error::operation_aborted.
//
//read.timer.cancel();
//write.timer.cancel();
#endif
}
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
template<class Executor2>
struct basic_stream<Protocol, Executor, RatePolicy>::
timeout_handler
{
using executor_type = Executor2;
op_state& state;
boost::weak_ptr<impl_type> wp;
tick_type tick;
executor_type ex;
executor_type get_executor() const noexcept
{
return ex;
}
void
operator()(error_code ec)
@@ -211,63 +224,35 @@ class transfer_op
using is_read = std::integral_constant<bool, isRead>;
op_state&
state(std::true_type)
{
return impl_->read;
}
op_state&
state(std::false_type)
{
return impl_->write;
}
op_state&
state()
{
return state(
std::integral_constant<bool, isRead>{});
}
std::size_t
available_bytes(std::true_type)
{
return rate_policy_access::
available_read_bytes(impl_->policy());
}
std::size_t
available_bytes(std::false_type)
{
return rate_policy_access::
available_write_bytes(impl_->policy());
if (isRead)
return impl_->read;
else
return impl_->write;
}
std::size_t
available_bytes()
{
return available_bytes(is_read{});
}
void
transfer_bytes(std::size_t n, std::true_type)
{
rate_policy_access::
transfer_read_bytes(impl_->policy(), n);
}
void
transfer_bytes(std::size_t n, std::false_type)
{
rate_policy_access::
transfer_write_bytes(impl_->policy(), n);
if (isRead)
return rate_policy_access::
available_read_bytes(impl_->policy());
else
return rate_policy_access::
available_write_bytes(impl_->policy());
}
void
transfer_bytes(std::size_t n)
{
transfer_bytes(n, is_read{});
if (isRead)
rate_policy_access::
transfer_read_bytes(impl_->policy(), n);
else
rate_policy_access::
transfer_write_bytes(impl_->policy(), n);
}
void
@@ -288,6 +273,8 @@ class transfer_op
std::move(*this));
}
static bool never_pending_;
public:
template<class Handler_>
transfer_op(
@@ -297,10 +284,26 @@ public:
: async_base<Handler, Executor>(
std::forward<Handler_>(h), s.get_executor())
, impl_(s.impl_)
, pg_(state().pending)
, pg_()
, b_(b)
{
(*this)({});
this->set_allowed_cancellation(net::cancellation_type::all);
if (buffer_bytes(b_) == 0 && state().pending)
{
// Workaround:
// Corner case discovered in https://github.com/boostorg/beast/issues/2065
// Enclosing SSL stream wishes to complete a 0-length write early by
// executing a 0-length read against the underlying stream.
// This can occur even if an existing async_read is in progress.
// In this specific case, we will complete the async op with no error
// in order to prevent assertions and/or internal corruption of the basic_stream
this->complete(false, error_code(), 0);
}
else
{
pg_.assign(state().pending);
(*this)({});
}
}
void
@@ -315,27 +318,39 @@ public:
{
// make sure we perform the no-op
BOOST_ASIO_CORO_YIELD
async_perform(0, is_read{});
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
(isRead ? "basic_stream::async_read_some"
: "basic_stream::async_write_some")));
async_perform(0, is_read{});
}
// apply the timeout manually, otherwise
// behavior varies across platforms.
if(state().timer.expiry() <= clock_type::now())
{
impl_->close();
ec = beast::error::timeout;
BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
}
goto upcall;
}
// if a timeout is active, wait on the timer
if(state().timer.expiry() != never())
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
(isRead ? "basic_stream::async_read_some"
: "basic_stream::async_write_some")));
state().timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick
}));
timeout_handler<decltype(this->get_executor())>{
state(),
impl_,
state().tick,
this->get_executor()});
}
// check rate limit, maybe wait
std::size_t amount;
@@ -344,7 +359,14 @@ public:
{
++impl_->waiting;
BOOST_ASIO_CORO_YIELD
impl_->timer.async_wait(std::move(*this));
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
(isRead ? "basic_stream::async_read_some"
: "basic_stream::async_write_some")));
impl_->timer.async_wait(std::move(*this));
}
if(ec)
{
// socket was closed, or a timeout
@@ -354,7 +376,7 @@ public:
if(state().timeout)
{
// yes, socket already closed
ec = beast::error::timeout;
BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
state().timeout = false;
}
goto upcall;
@@ -368,7 +390,14 @@ public:
}
BOOST_ASIO_CORO_YIELD
async_perform(amount, is_read{});
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
(isRead ? "basic_stream::async_read_some"
: "basic_stream::async_write_some")));
async_perform(amount, is_read{});
}
if(state().timer.expiry() != never())
{
@@ -383,7 +412,7 @@ public:
if(state().timeout)
{
// yes, socket already closed
ec = beast::error::timeout;
BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
state().timeout = false;
}
}
@@ -428,14 +457,24 @@ public:
, pg0_(impl_->read.pending)
, pg1_(impl_->write.pending)
{
this->set_allowed_cancellation(net::cancellation_type::all);
if(state().timer.expiry() != stream_base::never())
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"basic_stream::async_connect"));
impl_->write.timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick}));
timeout_handler<decltype(this->get_executor())>{
state(),
impl_,
state().tick,
this->get_executor()});
}
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"basic_stream::async_connect"));
impl_->socket.async_connect(
ep, std::move(*this));
@@ -456,14 +495,24 @@ public:
, pg0_(impl_->read.pending)
, pg1_(impl_->write.pending)
{
this->set_allowed_cancellation(net::cancellation_type::all);
if(state().timer.expiry() != stream_base::never())
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"basic_stream::async_connect"));
impl_->write.timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick}));
timeout_handler<decltype(this->get_executor())>{
state(),
impl_,
state().tick,
this->get_executor()});
}
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"basic_stream::async_connect"));
net::async_connect(impl_->socket,
eps, cond, std::move(*this));
@@ -484,14 +533,24 @@ public:
, pg0_(impl_->read.pending)
, pg1_(impl_->write.pending)
{
this->set_allowed_cancellation(net::cancellation_type::all);
if(state().timer.expiry() != stream_base::never())
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"basic_stream::async_connect"));
impl_->write.timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick}));
timeout_handler<decltype(this->get_executor())>{
state(),
impl_,
state().tick,
this->get_executor()});
}
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"basic_stream::async_connect"));
net::async_connect(impl_->socket,
begin, end, cond, std::move(*this));
@@ -515,7 +574,7 @@ public:
if(state().timeout)
{
// yes, socket already closed
ec = beast::error::timeout;
BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
state().timeout = false;
}
}
@@ -705,7 +764,20 @@ basic_stream(basic_stream&& other)
: impl_(boost::make_shared<impl_type>(
std::move(*other.impl_)))
{
// VFALCO I'm not sure this implementation is correct...
// Explainer: Asio's sockets provide the guarantee that a moved-from socket
// will be in a state as-if newly created. i.e.:
// * having the same (valid) executor
// * the socket shall not be open
// We provide the same guarantee by moving the impl rather than the pointer
// controlling its lifetime.
}
template<class Protocol, class Executor, class RatePolicy>
template<class Executor_>
basic_stream<Protocol, Executor, RatePolicy>::
basic_stream(basic_stream<Protocol, Executor_, RatePolicy> && other)
: impl_(boost::make_shared<impl_type>(std::false_type{}, std::move(other.impl_->socket)))
{
}
//------------------------------------------------------------------------------
@@ -723,7 +795,7 @@ release_socket() ->
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
expires_after(std::chrono::nanoseconds expiry_time)
expires_after(net::steady_timer::duration expiry_time)
{
// If assert goes off, it means that there are
// already read or write (or connect) operations
@@ -800,7 +872,7 @@ close()
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
template<class ConnectHandler>
template<BOOST_BEAST_ASYNC_TPARAM1 ConnectHandler>
BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
@@ -819,7 +891,7 @@ async_connect(
template<class Protocol, class Executor, class RatePolicy>
template<
class EndpointSequence,
class RangeConnectHandler,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
class>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void(error_code, typename Protocol::endpoint))
basic_stream<Protocol, Executor, RatePolicy>::
@@ -841,7 +913,7 @@ template<class Protocol, class Executor, class RatePolicy>
template<
class EndpointSequence,
class ConnectCondition,
class RangeConnectHandler,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
class>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
basic_stream<Protocol, Executor, RatePolicy>::
@@ -863,7 +935,7 @@ async_connect(
template<class Protocol, class Executor, class RatePolicy>
template<
class Iterator,
class IteratorConnectHandler>
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
@@ -884,7 +956,7 @@ template<class Protocol, class Executor, class RatePolicy>
template<
class Iterator,
class ConnectCondition,
class IteratorConnectHandler>
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
@@ -905,7 +977,7 @@ async_connect(
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
template<class MutableBufferSequence, class ReadHandler>
template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
basic_stream<Protocol, Executor, RatePolicy>::
async_read_some(
@@ -925,7 +997,7 @@ async_read_some(
}
template<class Protocol, class Executor, class RatePolicy>
template<class ConstBufferSequence, class WriteHandler>
template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
basic_stream<Protocol, Executor, RatePolicy>::
async_write_some(

View File

@@ -15,7 +15,7 @@
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
@@ -110,7 +110,7 @@ struct run_read_op
operator()(
ReadHandler&& h,
buffered_read_stream* s,
Buffers const& b)
Buffers const* b)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
@@ -124,7 +124,7 @@ struct run_read_op
read_op<
Buffers,
typename std::decay<ReadHandler>::type>(
std::forward<ReadHandler>(h), *s, b);
std::forward<ReadHandler>(h), *s, *b);
}
};
@@ -141,7 +141,7 @@ buffered_read_stream(Args&&... args)
}
template<class Stream, class DynamicBuffer>
template<class ConstBufferSequence, class WriteHandler>
template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
buffered_read_stream<Stream, DynamicBuffer>::
async_write_some(
@@ -153,7 +153,7 @@ async_write_some(
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
static_assert(detail::is_invocable<WriteHandler,
static_assert(detail::is_completion_token_for<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler type requirements not met");
return next_layer_.async_write_some(buffers,
@@ -212,7 +212,7 @@ read_some(MutableBufferSequence const& buffers,
}
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence, class ReadHandler>
template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
buffered_read_stream<Stream, DynamicBuffer>::
async_read_some(
@@ -233,7 +233,7 @@ async_read_some(
typename ops::run_read_op{},
handler,
this,
buffers);
&buffers);
}
} // beast

View File

@@ -11,7 +11,7 @@
#define BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/core/buffers_adaptor.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/config/workaround.hpp>
#include <boost/throw_exception.hpp>
@@ -35,71 +35,88 @@ namespace beast {
template<class MutableBufferSequence>
template<bool isMutable>
class buffers_adaptor<MutableBufferSequence>::
readable_bytes
class buffers_adaptor<MutableBufferSequence>::subrange
{
buffers_adaptor const* b_;
public:
using value_type = typename
std::conditional<isMutable,
net::mutable_buffer,
net::const_buffer>::type;
using value_type = typename std::conditional<
isMutable,
net::mutable_buffer,
net::const_buffer>::type;
class const_iterator;
struct iterator;
readable_bytes() = delete;
// construct from two iterators plus optionally subrange definition
subrange(
iter_type first, // iterator to first buffer in storage
iter_type last, // iterator to last buffer in storage
std::size_t pos = 0, // the offset in bytes from the beginning of the storage
std::size_t n = // the total length of the subrange
(std::numeric_limits<std::size_t>::max)());
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
readable_bytes(
readable_bytes const& other)
: b_(other.b_)
subrange(
subrange const& other)
: first_(other.first_)
, last_(other.last_)
, first_offset_(other.first_offset_)
, last_size_(other.last_size_)
{
}
readable_bytes& operator=(
readable_bytes const& other)
subrange& operator=(
subrange const& other)
{
b_ = other.b_;
first_ = other.first_;
last_ = other.last_;
first_offset_ = other.first_offset_;
last_size_ = other.last_size_;
return *this;
}
#else
readable_bytes(
readable_bytes const&) = default;
readable_bytes& operator=(
readable_bytes const&) = default;
subrange(
subrange const&) = default;
subrange& operator=(
subrange const&) = default;
#endif
template<bool isMutable_ = isMutable, class =
typename std::enable_if<! isMutable_>::type>
readable_bytes(
readable_bytes<true> const& other) noexcept
: b_(other.b_)
// allow conversion from mutable to const
template<bool isMutable_ = isMutable, typename
std::enable_if<!isMutable_>::type * = nullptr>
subrange(subrange<true> const &other)
: first_(other.first_)
, last_(other.last_)
, first_offset_(other.first_offset_)
, last_size_(other.last_size_)
{
}
template<bool isMutable_ = isMutable, class =
typename std::enable_if<! isMutable_>::type>
readable_bytes& operator=(
readable_bytes<true> const& other) noexcept
{
b_ = other.b_;
return *this;
}
const_iterator
iterator
begin() const;
const_iterator
iterator
end() const;
private:
friend class buffers_adaptor;
readable_bytes(buffers_adaptor const& b)
: b_(&b)
{
}
friend subrange<!isMutable>;
void
adjust(
std::size_t pos,
std::size_t n);
private:
// points to the first buffer in the sequence
iter_type first_;
// Points to one past the end of the underlying buffer sequence
iter_type last_;
// The initial offset into the first buffer
std::size_t first_offset_;
// how many bytes in the penultimate buffer are used (if any)
std::size_t last_size_;
};
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
@@ -110,257 +127,55 @@ private:
template<class MutableBufferSequence>
template<bool isMutable>
class buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
const_iterator
struct buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator
{
iter_type it_{};
buffers_adaptor const* b_ = nullptr;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename
std::conditional<isMutable,
net::mutable_buffer,
net::const_buffer>::type;
using pointer = value_type const*;
using reference = value_type;
buffers_adaptor<MutableBufferSequence>::
template subrange<isMutable>::
value_type;
using reference = value_type&;
using pointer = value_type*;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
iterator(
subrange<isMutable> const *parent,
iter_type it);
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
iterator();
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
value_type const b = *it_;
return value_type{b.data(),
(b_->out_ == net::buffer_sequence_end(b_->bs_) ||
it_ != b_->out_) ? b.size() : b_->out_pos_} +
(it_ == b_->begin_ ? b_->in_pos_ : 0);
}
value_type
operator*() const;
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
iterator &
operator++();
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
iterator
operator++(int);
const_iterator&
operator--()
{
--it_;
return *this;
}
iterator &
operator--();
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class readable_bytes;
const_iterator(
buffers_adaptor const& b,
iter_type iter)
: it_(iter)
, b_(&b)
{
}
};
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
begin() const ->
const_iterator
{
return const_iterator{*b_, b_->begin_};
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
readable_bytes::end() const ->
const_iterator
{
return const_iterator{*b_, b_->end_impl()};
}
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type
{
buffers_adaptor const* b_;
public:
using value_type = net::mutable_buffer;
class const_iterator;
mutable_buffers_type() = delete;
mutable_buffers_type(
mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(
mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class buffers_adaptor;
mutable_buffers_type(
buffers_adaptor const& b)
: b_(&b)
{
}
};
template<class MutableBufferSequence>
class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::const_iterator
{
iter_type it_{};
buffers_adaptor const* b_ = nullptr;
public:
using value_type = net::mutable_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
iterator
operator--(int);
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
operator==(iterator const &b) const;
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
value_type const b = *it_;
return value_type{b.data(),
it_ == std::prev(b_->end_) ?
b_->out_end_ : b.size()} +
(it_ == b_->out_ ? b_->out_pos_ : 0);
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
operator!=(iterator const &b) const;
private:
friend class mutable_buffers_type;
const_iterator(buffers_adaptor const& b,
iter_type iter)
: it_(iter)
, b_(&b)
{
}
subrange<isMutable> const *parent_;
iter_type it_;
};
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
begin() const ->
const_iterator
{
return const_iterator{*b_, b_->out_};
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
end() const ->
const_iterator
{
return const_iterator{*b_, b_->end_};
}
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
@@ -380,9 +195,9 @@ buffers_adaptor(
std::size_t nout,
std::size_t nend)
: bs_(other.bs_)
, begin_(std::next(bs_.begin(), nbegin))
, out_(std::next(bs_.begin(), nout))
, end_(std::next(bs_.begin(), nend))
, begin_(std::next(net::buffer_sequence_begin(bs_), nbegin))
, out_(std::next(net::buffer_sequence_begin(bs_), nout))
, end_(std::next(net::buffer_sequence_begin(bs_), nend))
, max_size_(other.max_size_)
, in_pos_(other.in_pos_)
, in_size_(other.in_size_)
@@ -480,16 +295,20 @@ buffers_adaptor<MutableBufferSequence>::
data() const noexcept ->
const_buffers_type
{
return const_buffers_type{*this};
return const_buffers_type(
begin_, end_,
in_pos_, in_size_);
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
data() noexcept ->
mutable_data_type
mutable_buffers_type
{
return mutable_data_type{*this};
return mutable_buffers_type(
begin_, end_,
in_pos_, in_size_);
}
template<class MutableBufferSequence>
@@ -498,6 +317,7 @@ buffers_adaptor<MutableBufferSequence>::
prepare(std::size_t n) ->
mutable_buffers_type
{
auto prepared = n;
end_ = out_;
if(end_ != net::buffer_sequence_end(bs_))
{
@@ -530,7 +350,7 @@ prepare(std::size_t n) ->
if(n > 0)
BOOST_THROW_EXCEPTION(std::length_error{
"buffers_adaptor too long"});
return mutable_buffers_type{*this};
return mutable_buffers_type(out_, end_, out_pos_, prepared);
}
template<class MutableBufferSequence>
@@ -602,6 +422,285 @@ consume(std::size_t n) noexcept
}
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
make_subrange(std::size_t pos, std::size_t n) ->
subrange<true>
{
return subrange<true>(
begin_, net::buffer_sequence_end(bs_),
in_pos_ + pos, n);
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
make_subrange(std::size_t pos, std::size_t n) const ->
subrange<false>
{
return subrange<false>(
begin_, net::buffer_sequence_end(bs_),
in_pos_ + pos, n);
}
// -------------------------------------------------------------------------
// subrange
template<class MutableBufferSequence>
template<bool isMutable>
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
subrange(
iter_type first, // iterator to first buffer in storage
iter_type last, // iterator to last buffer in storage
std::size_t pos, // the offset in bytes from the beginning of the storage
std::size_t n) // the total length of the subrange
: first_(first)
, last_(last)
, first_offset_(0)
, last_size_((std::numeric_limits<std::size_t>::max)())
{
adjust(pos, n);
}
template<class MutableBufferSequence>
template<bool isMutable>
void
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
adjust(
std::size_t pos,
std::size_t n)
{
if (n == 0)
last_ = first_;
if (first_ == last_)
{
first_offset_ = 0;
last_size_ = 0;
return;
}
auto is_last = [this](iter_type iter) {
return std::next(iter) == last_;
};
pos += first_offset_;
while (pos)
{
auto adjust = (std::min)(pos, first_->size());
if (adjust >= first_->size())
{
++first_;
first_offset_ = 0;
pos -= adjust;
}
else
{
first_offset_ = adjust;
pos = 0;
break;
}
}
auto current = first_;
auto max_elem = current->size() - first_offset_;
if (is_last(current))
{
// both first and last element
last_size_ = (std::min)(max_elem, n);
last_ = std::next(current);
return;
}
else if (max_elem >= n)
{
last_ = std::next(current);
last_size_ = n;
}
else
{
n -= max_elem;
++current;
}
for (;;)
{
max_elem = current->size();
if (is_last(current))
{
last_size_ = (std::min)(n, last_size_);
return;
}
else if (max_elem < n)
{
n -= max_elem;
++current;
}
else
{
last_size_ = n;
last_ = std::next(current);
return;
}
}
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
begin() const ->
iterator
{
return iterator(this, first_);
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
end() const ->
iterator
{
return iterator(this, last_);
}
// -------------------------------------------------------------------------
// buffers_adaptor::subrange::iterator
template<class MutableBufferSequence>
template<bool isMutable>
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
iterator()
: parent_(nullptr)
, it_()
{
}
template<class MutableBufferSequence>
template<bool isMutable>
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
iterator(subrange<isMutable> const *parent,
iter_type it)
: parent_(parent)
, it_(it)
{
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator*() const ->
value_type
{
value_type result = *it_;
if (it_ == parent_->first_)
result += parent_->first_offset_;
if (std::next(it_) == parent_->last_)
{
result = value_type(
result.data(),
(std::min)(
parent_->last_size_,
result.size()));
}
return result;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator++() ->
iterator &
{
++it_;
return *this;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator++(int) ->
iterator
{
auto result = *this;
++it_;
return result;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator--() ->
iterator &
{
--it_;
return *this;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator--(int) ->
iterator
{
auto result = *this;
--it_;
return result;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator==(iterator const &b) const ->
bool
{
return it_ == b.it_;
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
subrange<isMutable>::
iterator::
operator!=(iterator const &b) const ->
bool
{
return !(*this == b);
}
} // beast
} // boost

View File

@@ -11,7 +11,6 @@
#define BOOST_BEAST_IMPL_BUFFERS_CAT_HPP
#include <boost/beast/core/detail/tuple.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/core/detail/variant.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
@@ -23,9 +22,37 @@
namespace boost {
namespace beast {
template<class Buffer>
class buffers_cat_view<Buffer>
{
Buffer buffer_;
public:
using value_type = buffers_type<Buffer>;
using const_iterator = buffers_iterator_type<Buffer>;
explicit
buffers_cat_view(Buffer const& buffer)
: buffer_(buffer)
{
}
const_iterator
begin() const
{
return net::buffer_sequence_begin(buffer_);
}
const_iterator
end() const
{
return net::buffer_sequence_end(buffer_);
}
};
#if defined(_MSC_VER) && ! defined(__clang__)
# define BOOST_BEAST_UNREACHABLE() __assume(false)
# define BOOST_BEAST_UNREACHABLE_RETURN(v) __assume(false)
# define BOOST_BEAST_UNREACHABLE_RETURN(v) return v
#else
# define BOOST_BEAST_UNREACHABLE() __builtin_unreachable()
# define BOOST_BEAST_UNREACHABLE_RETURN(v) \
@@ -35,30 +62,18 @@ namespace beast {
#ifdef BOOST_BEAST_TESTS
#define BOOST_BEAST_LOGIC_ERROR(s) \
do { \
{ \
BOOST_THROW_EXCEPTION(std::logic_error((s))); \
BOOST_BEAST_UNREACHABLE(); \
} while(false)
#define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
do { \
BOOST_THROW_EXCEPTION(std::logic_error(s)); \
BOOST_BEAST_UNREACHABLE_RETURN(v); \
} while(false)
}
#else
#define BOOST_BEAST_LOGIC_ERROR(s) \
do { \
{ \
BOOST_ASSERT_MSG(false, s); \
BOOST_BEAST_UNREACHABLE(); \
} while(false)
#define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
do { \
BOOST_ASSERT_MSG(false, (s)); \
BOOST_BEAST_UNREACHABLE_RETURN(v); \
} while(false)
}
#endif
@@ -70,11 +85,11 @@ struct buffers_cat_view_iterator_base
{
char unused = 0; // make g++8 happy
net::mutable_buffer
BOOST_NORETURN net::mutable_buffer
operator*() const
{
BOOST_BEAST_LOGIC_ERROR_RETURN({},
"Dereferencing a one-past-the-end iterator");
BOOST_BEAST_LOGIC_ERROR(
"Dereferencing a one-past-the-end iterator");
}
operator bool() const noexcept
@@ -158,10 +173,10 @@ private:
{
const_iterator const& self;
reference
BOOST_NORETURN reference
operator()(mp11::mp_size_t<0>)
{
BOOST_BEAST_LOGIC_ERROR_RETURN({},
BOOST_BEAST_LOGIC_ERROR(
"Dereferencing a default-constructed iterator");
}

View File

@@ -0,0 +1,173 @@
//
// Copyright (c) 2022 Seth Heeren (sgheeren at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_BUFFERS_GENERATOR_HPP
#define BOOST_BEAST_CORE_IMPL_BUFFERS_GENERATOR_HPP
#include <boost/beast/core/buffers_generator.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/throw_exception.hpp>
#include <type_traits>
namespace boost {
namespace beast {
namespace detail {
template <
class AsyncWriteStream,
class BuffersGenerator>
struct write_buffers_generator_op
: boost::asio::coroutine
{
write_buffers_generator_op(
AsyncWriteStream& s, BuffersGenerator g)
: s_(s)
, g_(std::move(g))
{
}
template<class Self>
void operator()(
Self& self, error_code ec = {}, std::size_t n = 0)
{
BOOST_ASIO_CORO_REENTER(*this)
{
while(! g_.is_done())
{
BOOST_ASIO_CORO_YIELD
{
auto cb = g_.prepare(ec);
if(ec)
goto complete;
s_.async_write_some(
cb, std::move(self));
}
if(ec)
goto complete;
g_.consume(n);
total_ += n;
}
complete:
self.complete(ec, total_);
}
}
private:
AsyncWriteStream& s_;
BuffersGenerator g_;
std::size_t total_ = 0;
};
} // detail
template<
class SyncWriteStream,
class BuffersGenerator,
typename std::enable_if< //
is_buffers_generator<typename std::decay<
BuffersGenerator>::type>::value>::type* /*= nullptr*/
>
size_t
write(
SyncWriteStream& stream,
BuffersGenerator&& generator,
beast::error_code& ec)
{
static_assert(
is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
ec.clear();
size_t total = 0;
while(! generator.is_done())
{
auto cb = generator.prepare(ec);
if(ec)
break;
size_t n = net::write(stream, cb, ec);
if(ec)
break;
generator.consume(n);
total += n;
}
return total;
}
//----------------------------------------------------------
template<
class SyncWriteStream,
class BuffersGenerator,
typename std::enable_if<is_buffers_generator<
typename std::decay<BuffersGenerator>::type>::value>::
type* /*= nullptr*/
>
std::size_t
write(SyncWriteStream& stream, BuffersGenerator&& generator)
{
static_assert(
is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream type requirements not met");
beast::error_code ec;
std::size_t n = write(
stream, std::forward<BuffersGenerator>(generator), ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ ec });
return n;
}
//----------------------------------------------------------
template<
class AsyncWriteStream,
class BuffersGenerator,
BOOST_BEAST_ASYNC_TPARAM2 CompletionToken,
typename std::enable_if<is_buffers_generator<
BuffersGenerator>::value>::type* /*= nullptr*/
>
BOOST_BEAST_ASYNC_RESULT2(CompletionToken)
async_write(
AsyncWriteStream& stream,
BuffersGenerator generator,
CompletionToken&& token)
{
static_assert(
beast::is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream type requirements not met");
return net::async_compose< //
CompletionToken,
void(error_code, std::size_t)>(
detail::write_buffers_generator_op<
AsyncWriteStream,
BuffersGenerator>{ stream, std::move(generator) },
token,
stream);
}
} // namespace beast
} // namespace boost
#endif

View File

@@ -26,6 +26,9 @@ public:
return "boost.beast";
}
error_codes() : error_category(0x002f6e94401c6e8bu) {}
BOOST_BEAST_DECL
std::string
message(int ev) const override
@@ -62,6 +65,9 @@ public:
return "boost.beast";
}
error_conditions() : error_category(0x3dd0b0ce843c5b10u) {}
BOOST_BEAST_DECL
std::string
message(int cv) const override

View File

@@ -165,14 +165,14 @@ open(char const* path, file_mode mode, error_code& ec)
break;
case file_mode::append:
f = O_WRONLY | O_CREAT | O_TRUNC;
f = O_WRONLY | O_CREAT | O_APPEND;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
case file_mode::append_existing:
f = O_WRONLY;
f = O_WRONLY | O_APPEND;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
@@ -270,8 +270,12 @@ read(void* buffer, std::size_t n, error_code& ec) const
std::size_t nread = 0;
while(n > 0)
{
auto const amount = static_cast<ssize_t>((std::min)(
n, static_cast<std::size_t>(SSIZE_MAX)));
// <limits> not required to define SSIZE_MAX so we avoid it
constexpr auto ssmax =
static_cast<std::size_t>((std::numeric_limits<
decltype(::read(fd_, buffer, n))>::max)());
auto const amount = (std::min)(
n, ssmax);
auto const result = ::read(fd_, buffer, amount);
if(result == -1)
{
@@ -305,8 +309,12 @@ write(void const* buffer, std::size_t n, error_code& ec)
std::size_t nwritten = 0;
while(n > 0)
{
auto const amount = static_cast<ssize_t>((std::min)(
n, static_cast<std::size_t>(SSIZE_MAX)));
// <limits> not required to define SSIZE_MAX so we avoid it
constexpr auto ssmax =
static_cast<std::size_t>((std::numeric_limits<
decltype(::write(fd_, buffer, n))>::max)());
auto const amount = (std::min)(
n, ssmax);
auto const result = ::write(fd_, buffer, amount);
if(result == -1)
{

View File

@@ -11,6 +11,7 @@
#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
#include <boost/beast/core/file_stdio.hpp>
#include <boost/beast/core/detail/win32_unicode_path.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/exchange.hpp>
#include <limits>
@@ -46,7 +47,7 @@ operator=(file_stdio&& other)
void
file_stdio::
native_handle(FILE* f)
native_handle(std::FILE* f)
{
if(f_)
fclose(f_);
@@ -79,31 +80,50 @@ open(char const* path, file_mode mode, error_code& ec)
fclose(f_);
f_ = nullptr;
}
ec = {};
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
boost::winapi::WCHAR_ const* s;
detail::win32_unicode_path unicode_path(path, ec);
if (ec)
return;
#else
char const* s;
#endif
switch(mode)
{
default:
case file_mode::read:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"rb";
#else
s = "rb";
#endif
break;
case file_mode::scan:
#ifdef BOOST_MSVC
s = "rbS";
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"rbS";
#else
s = "rb";
#endif
break;
case file_mode::write:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"wb+";
#else
s = "wb+";
#endif
break;
case file_mode::write_new:
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
FILE* f0;
auto const ev = ::fopen_s(&f0, path, "rb");
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
# if (defined(BOOST_MSVC) && BOOST_MSVC >= 1910) || (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION >= 141)
s = L"wbx";
# else
std::FILE* f0;
auto const ev = ::_wfopen_s(&f0, unicode_path.c_str(), L"rb");
if(! ev)
{
std::fclose(f0);
@@ -116,28 +136,36 @@ open(char const* path, file_mode mode, error_code& ec)
ec.assign(ev, generic_category());
return;
}
s = "wb";
s = L"wb";
# endif
#else
s = "wbx";
#endif
break;
}
case file_mode::write_existing:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"rb+";
#else
s = "rb+";
#endif
break;
case file_mode::append:
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"ab";
#else
s = "ab";
#endif
break;
case file_mode::append_existing:
{
#ifdef BOOST_MSVC
FILE* f0;
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
std::FILE* f0;
auto const ev =
::fopen_s(&f0, path, "rb+");
::_wfopen_s(&f0, unicode_path.c_str(), L"rb+");
if(ev)
{
ec.assign(ev, generic_category());
@@ -153,13 +181,17 @@ open(char const* path, file_mode mode, error_code& ec)
}
#endif
std::fclose(f0);
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
s = L"ab";
#else
s = "ab";
#endif
break;
}
}
#ifdef BOOST_MSVC
auto const ev = ::fopen_s(&f_, path, s);
#if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
auto const ev = ::_wfopen_s(&f_, unicode_path.c_str(), s);
if(ev)
{
f_ = nullptr;
@@ -174,7 +206,6 @@ open(char const* path, file_mode mode, error_code& ec)
return;
}
#endif
ec = {};
}
std::uint64_t
@@ -241,7 +272,7 @@ seek(std::uint64_t offset, error_code& ec)
ec = make_error_code(errc::bad_file_descriptor);
return;
}
if(offset > (std::numeric_limits<long>::max)())
if(offset > static_cast<std::uint64_t>((std::numeric_limits<long>::max)()))
{
ec = make_error_code(errc::invalid_seek);
return;

View File

@@ -14,10 +14,10 @@
#if BOOST_BEAST_USE_WIN32_FILE
#include <boost/beast/core/detail/win32_unicode_path.hpp>
#include <boost/core/exchange.hpp>
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/get_last_error.hpp>
#include <limits>
#include <utility>
@@ -175,7 +175,7 @@ open(char const* path, file_mode mode, error_code& ec)
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::CREATE_ALWAYS_;
creation_disposition = boost::winapi::OPEN_ALWAYS_;
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
@@ -186,19 +186,40 @@ open(char const* path, file_mode mode, error_code& ec)
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
}
h_ = ::CreateFileA(
path,
detail::win32_unicode_path unicode_path(path, ec);
if (ec)
return;
h_ = ::CreateFileW(
unicode_path.c_str(),
desired_access,
share_mode,
NULL,
creation_disposition,
flags_and_attributes,
NULL);
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
if (h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec.assign(boost::winapi::GetLastError(),
system_category());
else
ec = {};
return;
}
if (mode == file_mode::append ||
mode == file_mode::append_existing)
{
boost::winapi::LARGE_INTEGER_ in;
in.QuadPart = 0;
if (!detail::set_file_pointer_ex(h_, in, 0,
boost::winapi::FILE_END_))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
boost::winapi::CloseHandle(h_);
h_ = boost::winapi::INVALID_HANDLE_VALUE_;
return;
}
}
ec = {};
}
std::uint64_t

View File

@@ -124,8 +124,6 @@ basic_flat_buffer(
end_ = nullptr;
max_ = other.max_;
copy_from(other);
other.clear();
other.shrink_to_fit();
return;
}
@@ -262,17 +260,32 @@ reserve(std::size_t n)
template<class Allocator>
void
basic_flat_buffer<Allocator>::
shrink_to_fit()
shrink_to_fit() noexcept
{
auto const len = size();
if(len == capacity())
return;
char* p;
if(len > 0)
{
BOOST_ASSERT(begin_);
BOOST_ASSERT(in_);
p = alloc(len);
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
p = alloc(len);
#ifndef BOOST_NO_EXCEPTIONS
}
catch(std::exception const&)
{
// request could not be fulfilled,
// squelch the exception
return;
}
#endif
std::memcpy(p, in_, len);
}
else
@@ -403,7 +416,7 @@ copy_from(
if(begin_)
{
BOOST_ASSERT(other.begin_);
std::memcpy(begin_, other.begin_, n);
std::memcpy(begin_, other.in_, n);
}
}
@@ -436,8 +449,6 @@ move_assign(basic_flat_buffer& other, std::false_type)
if(this->get() != other.get())
{
copy_from(other);
other.clear();
other.shrink_to_fit();
}
else
{

View File

@@ -16,7 +16,6 @@
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/websocket/teardown.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/coroutine.hpp>
#include <memory>
namespace boost {
@@ -30,7 +29,6 @@ template<class Handler>
class write_op
: public async_base<Handler,
beast::executor_type<flat_stream>>
, public net::coroutine
{
public:
template<
@@ -53,6 +51,11 @@ public:
s.buffer_.commit(net::buffer_copy(
s.buffer_.prepare(result.size),
b, result.size));
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"flat_stream::async_write_some"));
s.stream_.async_write_some(
s.buffer_.data(), std::move(*this));
}
@@ -60,6 +63,11 @@ public:
{
s.buffer_.clear();
s.buffer_.shrink_to_fit();
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"flat_stream::async_write_some"));
s.stream_.async_write_some(
beast::buffers_prefix(
result.size, b), std::move(*this));
@@ -146,7 +154,7 @@ read_some(MutableBufferSequence const& buffers, error_code& ec)
template<class NextLayer>
template<
class MutableBufferSequence,
class ReadHandler>
BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
flat_stream<NextLayer>::
async_read_some(
@@ -227,7 +235,7 @@ write_some(ConstBufferSequence const& buffers, error_code& ec)
template<class NextLayer>
template<
class ConstBufferSequence,
class WriteHandler>
BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
flat_stream<NextLayer>::
async_write_some(

View File

@@ -1,132 +0,0 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_HANDLER_PTR_HPP
#define BOOST_BEAST_IMPL_HANDLER_PTR_HPP
#include <boost/asio/associated_allocator.hpp>
#include <boost/assert.hpp>
#include <memory>
namespace boost {
namespace beast {
template<class T, class Handler>
void
handler_ptr<T, Handler>::
clear()
{
using A = typename detail::allocator_traits<
net::associated_allocator_t<
Handler>>::template rebind_alloc<T>;
using alloc_traits =
beast::detail::allocator_traits<A>;
A alloc(
net::get_associated_allocator(handler()));
alloc_traits::destroy(alloc, t_);
alloc_traits::deallocate(alloc, t_, 1);
t_ = nullptr;
}
template<class T, class Handler>
handler_ptr<T, Handler>::
~handler_ptr()
{
if(t_)
{
clear();
h_.~Handler();
}
}
template<class T, class Handler>
handler_ptr<T, Handler>::
handler_ptr(handler_ptr&& other)
: t_(other.t_)
{
if(other.t_)
{
::new(static_cast<void*>(std::addressof(h_)))
Handler(std::move(other.h_));
other.h_.~Handler();
other.t_ = nullptr;
}
}
template<class T, class Handler>
template<class DeducedHandler, class... Args>
handler_ptr<T, Handler>::
handler_ptr(DeducedHandler&& h, Args&&... args)
{
BOOST_STATIC_ASSERT(! std::is_array<T>::value);
using A = typename detail::allocator_traits<
net::associated_allocator_t<
Handler>>::template rebind_alloc<T>;
using alloc_traits =
beast::detail::allocator_traits<A>;
A alloc{net::get_associated_allocator(h)};
bool destroy = false;
auto deleter = [&alloc, &destroy](T* p)
{
if(destroy)
alloc_traits::destroy(alloc, p);
alloc_traits::deallocate(alloc, p, 1);
};
std::unique_ptr<T, decltype(deleter)> t{
alloc_traits::allocate(alloc, 1), deleter};
alloc_traits::construct(alloc, t.get(),
static_cast<DeducedHandler const&>(h),
std::forward<Args>(args)...);
destroy = true;
::new(static_cast<void*>(std::addressof(h_)))
Handler(std::forward<DeducedHandler>(h));
t_ = t.release();
}
template<class T, class Handler>
auto
handler_ptr<T, Handler>::
release_handler() ->
handler_type
{
BOOST_ASSERT(t_);
clear();
auto deleter = [](Handler* h)
{
h->~Handler();
};
std::unique_ptr<
Handler, decltype(deleter)> destroyer{
std::addressof(h_), deleter};
return std::move(h_);
}
template<class T, class Handler>
template<class... Args>
void
handler_ptr<T, Handler>::
invoke(Args&&... args)
{
BOOST_ASSERT(t_);
clear();
auto deleter = [](Handler* h)
{
boost::ignore_unused(h); // fix #1119
h->~Handler();
};
std::unique_ptr<
Handler, decltype(deleter)> destroyer{
std::addressof(h_), deleter};
h_(std::forward<Args>(args)...);
}
} // beast
} // boost
#endif

View File

@@ -11,13 +11,13 @@
#define BOOST_BEAST_IMPL_MULTI_BUFFER_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <exception>
#include <iterator>
#include <sstream>
#include <string>
#include <type_traits>
@@ -88,41 +88,6 @@ namespace beast {
in_pos_ out_pos_ == 0
out_end_ == 0
*/
//------------------------------------------------------------------------------
template<class Allocator>
class basic_multi_buffer<Allocator>::element
: public boost::intrusive::list_base_hook<
boost::intrusive::link_mode<
boost::intrusive::normal_link>>
{
using size_type = typename
detail::allocator_traits<Allocator>::size_type;
size_type const size_;
public:
element(element const&) = delete;
explicit
element(size_type n) noexcept
: size_(n)
{
}
size_type
size() const noexcept
{
return size_;
}
char*
data() const noexcept
{
return const_cast<char*>(
reinterpret_cast<char const*>(this + 1));
}
};
//------------------------------------------------------------------------------
@@ -134,17 +99,155 @@ public:
template<class Allocator>
template<bool isMutable>
class basic_multi_buffer<Allocator>::readable_bytes
class basic_multi_buffer<Allocator>::subrange
{
basic_multi_buffer const* b_;
const_iter begin_;
const_iter end_;
size_type begin_pos_; // offset in begin_
size_type last_pos_; // offset in std::prev(end_)
friend class basic_multi_buffer;
explicit
readable_bytes(
basic_multi_buffer const& b) noexcept
subrange(
basic_multi_buffer const& b,
size_type pos,
size_type n) noexcept
: b_(&b)
{
auto const set_empty = [&]
{
begin_ = b_->list_.end();
end_ = b_->list_.end();
begin_pos_ = 0;
last_pos_ = 0;
};
// VFALCO Handle this trivial case of
// pos larger than total size, otherwise
// the addition to pos can overflow.
//if(pos >= b_->in_size_)
// skip unused prefix
pos = pos + b_->in_pos_;
// iterate the buffers
auto it = b_->list_.begin();
// is the list empty?
if(it == b_->list_.end())
{
set_empty();
return;
}
// is the requested size zero?
if(n == 0)
{
set_empty();
return;
}
// get last buffer and its size
auto const last =
std::prev(b_->list_.end());
auto const last_end =
[&]
{
if(b_->out_end_ == 0)
return last->size();
return b_->out_end_;
}();
// only one buffer in list?
if(it == last)
{
if(pos >= last_end)
{
set_empty();
return;
}
begin_ = it;
begin_pos_ = pos;
end_ = std::next(it);
if(n > last_end - pos)
last_pos_ = last_end;
else
last_pos_ = pos + n;
return;
}
for(;;)
{
// is pos in this buffer?
if(pos < it->size())
{
begin_ = it;
begin_pos_ = pos;
// does this buffer satisfy n?
auto const avail =
it->size() - pos;
if(n <= avail)
{
end_ = ++it;
last_pos_ = pos + n;
return;
}
n -= avail;
++it;
break;
}
pos -= it->size();
++it;
// did we reach the last buffer?
if(it == last)
{
// is pos past the end?
if(pos >= last_end)
{
set_empty();
return;
}
// satisfy the request
begin_ = it;
begin_pos_ = pos;
end_ = std::next(it);
if(n < last_end - pos)
last_pos_ = pos + n;
else
last_pos_ = last_end;
return;
}
}
// find pos+n
for(;;)
{
if(it == last)
{
end_ = ++it;
if(n >= last_end)
last_pos_ = last_end;
else
last_pos_ = n;
return;
}
if(n <= it->size())
{
end_ = ++it;
last_pos_ = n;
return;
}
n -= it->size();
++it;
}
}
public:
@@ -156,39 +259,55 @@ public:
class const_iterator;
readable_bytes() = delete;
subrange() = delete;
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
readable_bytes(readable_bytes const& other)
subrange(subrange const& other)
: b_(other.b_)
, begin_(other.begin_)
, end_(other.end_)
, begin_pos_(other.begin_pos_)
, last_pos_(other.last_pos_)
{
}
readable_bytes& operator=(readable_bytes const& other)
subrange& operator=(subrange const& other)
{
b_ = other.b_;
begin_ = other.begin_;
end_ = other.end_;
begin_pos_ = other.begin_pos_;
last_pos_ = other.last_pos_;
return *this;
}
#else
readable_bytes(readable_bytes const&) = default;
readable_bytes& operator=(readable_bytes const&) = default;
subrange(subrange const&) = default;
subrange& operator=(subrange const&) = default;
#endif
template<
bool isMutable_ = isMutable,
class = typename std::enable_if<! isMutable_>::type>
readable_bytes(
readable_bytes<true> const& other) noexcept
subrange(
subrange<true> const& other) noexcept
: b_(other.b_)
{
, begin_(other.begin_)
, end_(other.end_)
, begin_pos_(other.begin_pos_)
, last_pos_(other.last_pos_)
{
}
template<
bool isMutable_ = isMutable,
class = typename std::enable_if<! isMutable_>::type>
readable_bytes& operator=(
readable_bytes<true> const& other) noexcept
subrange& operator=(
subrange<true> const& other) noexcept
{
b_ = other.b_;
begin_ = other.begin_;
end_ = other.end_;
begin_pos_ = other.begin_pos_;
last_pos_ = other.last_pos_;
return *this;
}
@@ -212,15 +331,25 @@ template<class Allocator>
template<bool isMutable>
class
basic_multi_buffer<Allocator>::
readable_bytes<isMutable>::
subrange<isMutable>::
const_iterator
{
basic_multi_buffer const* b_ = nullptr;
friend class subrange;
subrange const* sr_ = nullptr;
typename list_type::const_iterator it_;
const_iterator(
subrange const& sr, typename
list_type::const_iterator const& it) noexcept
: sr_(&sr)
, it_(it)
{
}
public:
using value_type =
typename readable_bytes::value_type;
typename subrange::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@@ -233,22 +362,16 @@ public:
const_iterator& operator=(
const_iterator const& other) = default;
const_iterator(
basic_multi_buffer const& b, typename
list_type::const_iterator const& it) noexcept
: b_(&b)
, it_(it)
bool
operator==(
const_iterator const& other) const noexcept
{
return sr_ == other.sr_ && it_ == other.it_;
}
bool
operator==(const_iterator const& other) const noexcept
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const noexcept
operator!=(
const_iterator const& other) const noexcept
{
return !(*this == other);
}
@@ -256,125 +379,17 @@ public:
reference
operator*() const noexcept
{
auto const& e = *it_;
return value_type{e.data(),
(b_->out_ == b_->list_.end() ||
&e != &*b_->out_) ? e.size() : b_->out_pos_} +
(&e == &*b_->list_.begin() ? b_->in_pos_ : 0);
}
pointer
operator->() const = delete;
const_iterator&
operator++() noexcept
{
++it_;
return *this;
}
const_iterator
operator++(int) noexcept
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--() noexcept
{
--it_;
return *this;
}
const_iterator
operator--(int) noexcept
{
auto temp = *this;
--(*this);
return temp;
}
};
//------------------------------------------------------------------------------
template<class Allocator>
class basic_multi_buffer<Allocator>::mutable_buffers_type
{
basic_multi_buffer const* b_;
friend class basic_multi_buffer;
explicit
mutable_buffers_type(
basic_multi_buffer const& b) noexcept
: b_(&b)
{
}
public:
using value_type = net::mutable_buffer;
class const_iterator;
mutable_buffers_type() = delete;
mutable_buffers_type(mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
//------------------------------------------------------------------------------
template<class Allocator>
class basic_multi_buffer<Allocator>::mutable_buffers_type::const_iterator
{
basic_multi_buffer const* b_ = nullptr;
typename list_type::const_iterator it_;
public:
using value_type = typename
mutable_buffers_type::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
const_iterator(
basic_multi_buffer const& b,
typename list_type::const_iterator const& it) noexcept
: b_(&b)
, it_(it)
{
}
bool
operator==(const_iterator const& other) const noexcept
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const noexcept
{
return !(*this == other);
}
reference
operator*() const noexcept
{
auto const& e = *it_;
return value_type{e.data(),
&e == &*std::prev(b_->list_.end()) ?
b_->out_end_ : e.size()} +
(&e == &*b_->out_ ? b_->out_pos_ : 0);
value_type result;
BOOST_ASSERT(sr_->last_pos_ != 0);
if(it_ == std::prev(sr_->end_))
result = {
it_->data(), sr_->last_pos_ };
else
result = {
it_->data(), it_->size() };
if(it_ == sr_->begin_)
result += sr_->begin_pos_;
return result;
}
pointer
@@ -417,44 +432,24 @@ template<class Allocator>
template<bool isMutable>
auto
basic_multi_buffer<Allocator>::
readable_bytes<isMutable>::
subrange<isMutable>::
begin() const noexcept ->
const_iterator
{
return const_iterator{*b_, b_->list_.begin()};
return const_iterator(
*this, begin_);
}
template<class Allocator>
template<bool isMutable>
auto
basic_multi_buffer<Allocator>::
readable_bytes<isMutable>::
subrange<isMutable>::
end() const noexcept ->
const_iterator
{
return const_iterator{*b_, b_->out_ ==
b_->list_.end() ? b_->list_.end() :
std::next(b_->out_)};
}
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
mutable_buffers_type::
begin() const noexcept ->
const_iterator
{
return const_iterator{*b_, b_->out_};
}
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
mutable_buffers_type::
end() const noexcept ->
const_iterator
{
return const_iterator{*b_, b_->list_.end()};
return const_iterator(
*this, end_);
}
//------------------------------------------------------------------------------
@@ -487,7 +482,7 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
Allocator const& alloc) noexcept
: boost::empty_value<base_alloc_type>(
: boost::empty_value<Allocator>(
boost::empty_init_t(), alloc)
, max_(alloc_traits::max_size(this->get()))
, out_(list_.end())
@@ -499,8 +494,8 @@ basic_multi_buffer<Allocator>::
basic_multi_buffer(
std::size_t limit,
Allocator const& alloc) noexcept
: boost::empty_value<
base_alloc_type>(boost::empty_init_t(), alloc)
: boost::empty_value<Allocator>(
boost::empty_init_t(), alloc)
, max_(limit)
, out_(list_.end())
{
@@ -510,7 +505,7 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer&& other) noexcept
: boost::empty_value<base_alloc_type>(
: boost::empty_value<Allocator>(
boost::empty_init_t(), std::move(other.get()))
, max_(other.max_)
, in_size_(boost::exchange(other.in_size_, 0))
@@ -529,17 +524,15 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer&& other,
Allocator const& alloc)
: boost::empty_value<
base_alloc_type>(boost::empty_init_t(), alloc)
Allocator const& alloc)
: boost::empty_value<Allocator>(
boost::empty_init_t(), alloc)
, max_(other.max_)
{
if(this->get() != other.get())
{
out_ = list_.end();
copy_from(other);
other.clear();
other.shrink_to_fit();
return;
}
@@ -562,7 +555,7 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer const& other)
: boost::empty_value<base_alloc_type>(
: boost::empty_value<Allocator>(
boost::empty_init_t(), alloc_traits::
select_on_container_copy_construction(
other.get()))
@@ -577,7 +570,7 @@ basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer const& other,
Allocator const& alloc)
: boost::empty_value<base_alloc_type>(
: boost::empty_value<Allocator>(
boost::empty_init_t(), alloc)
, max_(other.max_)
, out_(list_.end())
@@ -601,8 +594,8 @@ basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer<OtherAlloc> const& other,
allocator_type const& alloc)
: boost::empty_value<
base_alloc_type>(boost::empty_init_t(), alloc)
: boost::empty_value<Allocator>(
boost::empty_init_t(), alloc)
, max_(other.max_)
, out_(list_.end())
{
@@ -669,16 +662,18 @@ basic_multi_buffer<Allocator>::
data() const noexcept ->
const_buffers_type
{
return const_buffers_type(*this);
return const_buffers_type(
*this, 0, in_size_);
}
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
data() noexcept ->
mutable_data_type
mutable_buffers_type
{
return mutable_data_type(*this);
return mutable_buffers_type(
*this, 0, in_size_);
}
template<class Allocator>
@@ -784,7 +779,7 @@ shrink_to_fit()
};
// partial last buffer
if(list_.size() > 1 && out_ != list_.end())
if(out_ != list_.begin() && out_ != list_.end())
{
BOOST_ASSERT(out_ ==
list_.iterator_to(list_.back()));
@@ -820,7 +815,8 @@ shrink_to_fit()
}
else
{
BOOST_ASSERT(list_.size() == 1);
BOOST_ASSERT(out_ ==
list_.iterator_to(list_.back()));
BOOST_ASSERT(out_pos_ > in_pos_);
auto const n = out_pos_ - in_pos_;
auto& e = alloc(n);
@@ -856,6 +852,7 @@ basic_multi_buffer<Allocator>::
prepare(size_type n) ->
mutable_buffers_type
{
auto const n0 = n;
if(in_size_ > max_ || n > (max_ - in_size_))
BOOST_THROW_EXCEPTION(std::length_error{
"basic_multi_buffer too long"});
@@ -916,15 +913,17 @@ prepare(size_type n) ->
destroy(reuse);
if(n > 0)
{
static auto const growth_factor = 2.0f;
std::size_t const growth_factor = 2;
std::size_t altn = in_size_ * growth_factor;
// Overflow detection:
if(in_size_ > altn)
altn = (std::numeric_limits<std::size_t>::max)();
else
altn = (std::max<std::size_t>)(512, altn);
auto const size =
(std::min<std::size_t>)(
max_ - total,
(std::max<std::size_t>)({
static_cast<std::size_t>(
in_size_ * growth_factor - in_size_),
512,
n}));
(std::max<std::size_t>)(n, altn));
auto& e = alloc(size);
list_.push_back(e);
if(out_ == list_.end())
@@ -935,7 +934,12 @@ prepare(size_type n) ->
#endif
}
}
return mutable_buffers_type(*this);
auto const result =
mutable_buffers_type(
*this, in_size_, n0);
BOOST_ASSERT(
net::buffer_size(result) == n0);
return result;
}
template<class Allocator>
@@ -1012,10 +1016,7 @@ consume(size_type n) noexcept
in_pos_ = 0;
auto& e = list_.front();
list_.erase(list_.iterator_to(e));
auto const len = sizeof(e) + e.size();
e.~element();
alloc_traits::deallocate(this->get(),
reinterpret_cast<char*>(&e), len);
destroy(e);
#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
@@ -1099,8 +1100,6 @@ move_assign(basic_multi_buffer& other, std::false_type)
if(this->get() != other.get())
{
copy_from(other);
other.clear();
other.shrink_to_fit();
}
else
{
@@ -1202,24 +1201,19 @@ destroy(list_type& list) noexcept
destroy(*it++);
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
destroy(const_iter it)
{
auto& e = list_.erase(it);
destroy(e);
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
destroy(element& e)
{
auto const len = sizeof(e) + e.size();
auto a = rebind_type{this->get()};
auto const n =
(sizeof(element) + e.size() +
sizeof(align_type) - 1) /
sizeof(align_type);
e.~element();
alloc_traits::deallocate(this->get(),
reinterpret_cast<char*>(&e), len);
alloc_traits::deallocate(a,
reinterpret_cast<align_type*>(&e), n);
}
template<class Allocator>
@@ -1231,9 +1225,11 @@ alloc(std::size_t size) ->
if(size > alloc_traits::max_size(this->get()))
BOOST_THROW_EXCEPTION(std::length_error(
"A basic_multi_buffer exceeded the allocator's maximum size"));
return *::new(alloc_traits::allocate(
this->get(),
sizeof(element) + size)) element(size);
auto a = rebind_type{this->get()};
auto const p = alloc_traits::allocate(a,
(sizeof(element) + size + sizeof(align_type) - 1) /
sizeof(align_type));
return *(::new(p) element(size));
}
template<class Allocator>

View File

@@ -46,7 +46,6 @@ read_size(DynamicBuffer& buffer,
static_assert(
net::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer type requirements not met");
BOOST_ASSERT(max_size >= 1);
auto const size = buffer.size();
auto const limit = buffer.max_size() - size;
BOOST_ASSERT(size <= buffer.max_size());

View File

@@ -12,7 +12,9 @@
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/assert.hpp>
#include <boost/core/empty_value.hpp>
@@ -28,9 +30,10 @@ class saved_handler::base
{
protected:
~base() = default;
saved_handler * owner_;
public:
base() = default;
base(saved_handler * owner) : owner_(owner){}
void set_owner(saved_handler * new_owner) { owner_ = new_owner;}
virtual void destroy() = 0;
virtual void invoke() = 0;
};
@@ -63,14 +66,32 @@ class saved_handler::impl final : public base
};
ebo_pair v_;
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
typename std::decay<decltype(net::prefer(std::declval<
net::associated_executor_t<Handler>>(),
net::execution::outstanding_work.tracked))>::type
wg2_;
#else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
net::executor_work_guard<
net::associated_executor_t<Handler>> wg2_;
#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
net::cancellation_slot slot_{net::get_associated_cancellation_slot(v_.h)};
public:
template<class Handler_>
impl(alloc_type const& a, Handler_&& h)
: v_(a, std::forward<Handler_>(h))
impl(alloc_type const& a, Handler_&& h,
saved_handler * owner)
: base(owner), v_(a, std::forward<Handler_>(h))
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
, wg2_(net::prefer(
net::get_associated_executor(v_.h),
net::execution::outstanding_work.tracked))
#else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
, wg2_(net::get_associated_executor(v_.h))
#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
{
}
~impl()
{
}
@@ -78,6 +99,7 @@ public:
destroy() override
{
auto v = std::move(v_);
slot_.clear();
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
}
@@ -85,11 +107,22 @@ public:
void
invoke() override
{
slot_.clear();
auto v = std::move(v_);
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
v.h();
}
void self_complete()
{
slot_.clear();
owner_->p_ = nullptr;
auto v = std::move(v_);
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
v.h(net::error::operation_aborted);
}
};
//------------------------------------------------------------------------------
@@ -97,7 +130,8 @@ public:
template<class Handler, class Allocator>
void
saved_handler::
emplace(Handler&& handler, Allocator const& alloc)
emplace(Handler&& handler, Allocator const& alloc,
net::cancellation_type cancel_type)
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
@@ -127,22 +161,47 @@ emplace(Handler&& handler, Allocator const& alloc)
alloc_traits::deallocate(a, p, 1);
}
};
auto cancel_slot = net::get_associated_cancellation_slot(handler);
storage s(alloc);
alloc_traits::construct(s.a, s.p,
s.a, std::forward<Handler>(handler));
p_ = boost::exchange(s.p, nullptr);
s.a, std::forward<Handler>(handler), this);
auto tmp = boost::exchange(s.p, nullptr);
p_ = tmp;
if (cancel_slot.is_connected())
{
struct cancel_op
{
impl<Handler, Allocator>* p;
net::cancellation_type accepted_ct;
cancel_op(impl<Handler, Allocator>* p,
net::cancellation_type accepted_ct)
: p(p), accepted_ct(accepted_ct) {}
void operator()(net::cancellation_type ct)
{
if ((ct & accepted_ct) != net::cancellation_type::none)
p->self_complete();
}
};
cancel_slot.template emplace<cancel_op>(tmp, cancel_type);
}
}
template<class Handler>
void
saved_handler::
emplace(Handler&& handler)
emplace(Handler&& handler, net::cancellation_type cancel_type)
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
emplace(
std::forward<Handler>(handler),
net::get_associated_allocator(handler));
net::get_associated_allocator(handler),
cancel_type);
}
} // beast

View File

@@ -27,6 +27,7 @@ saved_handler::
saved_handler(saved_handler&& other) noexcept
: p_(boost::exchange(other.p_, nullptr))
{
p_->set_owner(this);
}
saved_handler&
@@ -36,6 +37,7 @@ operator=(saved_handler&& other) noexcept
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
p_ = boost::exchange(other.p_, nullptr);
p_->set_owner(this);
return *this;
}

View File

@@ -10,12 +10,7 @@
#ifndef BOOST_BEAST_IMPL_STATIC_BUFFER_HPP
#define BOOST_BEAST_IMPL_STATIC_BUFFER_HPP
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
namespace boost {

View File

@@ -11,12 +11,8 @@
#define BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
namespace boost {
@@ -60,7 +56,7 @@ data() const noexcept ->
auto
static_buffer_base::
data() noexcept ->
mutable_data_type
mutable_buffers_type
{
if(in_off_ + in_size_ <= capacity_)
return {

View File

@@ -1,642 +0,0 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STATIC_STRING_HPP
#define BOOST_BEAST_IMPL_STATIC_STRING_HPP
#include <boost/beast/core/detail/static_string.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
namespace beast {
//
// (constructor)
//
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string()
{
n_ = 0;
term();
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(size_type count, CharT ch)
{
assign(count, ch);
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
static_string<N, CharT, Traits>::
static_string(static_string<M, CharT, Traits> const& other,
size_type pos)
{
assign(other, pos);
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
static_string<N, CharT, Traits>::
static_string(static_string<M, CharT, Traits> const& other,
size_type pos, size_type count)
{
assign(other, pos, count);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(CharT const* s, size_type count)
{
assign(s, count);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(CharT const* s)
{
auto const count = Traits::length(s);
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::copy(&s_[0], s, n_ + 1);
}
template<std::size_t N, class CharT, class Traits>
template<class InputIt>
static_string<N, CharT, Traits>::
static_string(InputIt first, InputIt last)
{
assign(first, last);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(static_string const& s)
{
assign(s);
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
static_string<N, CharT, Traits>::
static_string(static_string<M, CharT, Traits> const& s)
{
assign(s);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(std::initializer_list<CharT> init)
{
assign(init.begin(), init.end());
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(string_view_type sv)
{
assign(sv);
}
template<std::size_t N, class CharT, class Traits>
template<class T, class>
static_string<N, CharT, Traits>::
static_string(T const& t, size_type pos, size_type n)
{
assign(t, pos, n);
}
//
// (assignment)
//
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
operator=(CharT const* s) ->
static_string&
{
auto const count = Traits::length(s);
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::copy(&s_[0], s, n_ + 1);
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign(size_type count, CharT ch) ->
static_string&
{
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::assign(&s_[0], n_, ch);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign(static_string const& str) ->
static_string&
{
n_ = str.n_;
auto const n = n_ + 1;
BOOST_BEAST_ASSUME(n != 0);
Traits::copy(&s_[0], &str.s_[0], n);
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
auto
static_string<N, CharT, Traits>::
assign(static_string<M, CharT, Traits> const& str,
size_type pos, size_type count) ->
static_string&
{
auto const ss = str.substr(pos, count);
return assign(ss.data(), ss.size());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign(CharT const* s, size_type count) ->
static_string&
{
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::copy(&s_[0], s, n_);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<class InputIt>
auto
static_string<N, CharT, Traits>::
assign(InputIt first, InputIt last) ->
static_string&
{
std::size_t const n = std::distance(first, last);
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
n_ = n;
for(auto it = &s_[0]; first != last; ++it, ++first)
Traits::assign(*it, *first);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<class T>
auto
static_string<N, CharT, Traits>::
assign(T const& t, size_type pos, size_type count) ->
typename std::enable_if<std::is_convertible<T,
string_view_type>::value, static_string&>::type
{
auto const sv = string_view_type(t).substr(pos, count);
if(sv.size() > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"sv.size() > max_size()"});
n_ = sv.size();
Traits::copy(&s_[0], &sv[0], n_);
term();
return *this;
}
//
// Element access
//
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
at(size_type pos) ->
reference
{
if(pos >= size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos >= size()"});
return s_[pos];
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
at(size_type pos) const ->
const_reference
{
if(pos >= size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos >= size()"});
return s_[pos];
}
//
// Capacity
//
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
reserve(std::size_t n)
{
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
}
//
// Operations
//
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
clear()
{
n_ = 0;
term();
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
insert(size_type index, size_type count, CharT ch) ->
static_string&
{
if(index > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"index > size()"});
insert(begin() + index, count, ch);
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
insert(size_type index, CharT const* s, size_type count) ->
static_string&
{
if(index > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"index > size()"});
if(size() + count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() + count > max_size()"});
Traits::move(
&s_[index + count], &s_[index], size() - index);
n_ += count;
Traits::copy(&s_[index], s, count);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
auto
static_string<N, CharT, Traits>::
insert(size_type index,
static_string<M, CharT, Traits> const& str,
size_type index_str, size_type count) ->
static_string&
{
auto const ss = str.substr(index_str, count);
return insert(index, ss.data(), ss.size());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
insert(const_iterator pos, size_type count, CharT ch) ->
iterator
{
if(size() + count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() + count() > max_size()"});
auto const index = pos - &s_[0];
Traits::move(
&s_[index + count], &s_[index], size() - index);
n_ += count;
Traits::assign(&s_[index], count, ch);
term();
return &s_[index];
}
template<std::size_t N, class CharT, class Traits>
template<class InputIt>
auto
static_string<N, CharT, Traits>::
insert(const_iterator pos, InputIt first, InputIt last) ->
typename std::enable_if<
detail::is_input_iterator<InputIt>::value,
iterator>::type
{
std::size_t const count = std::distance(first, last);
if(size() + count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() + count > max_size()"});
std::size_t const index = pos - begin();
Traits::move(
&s_[index + count], &s_[index], size() - index);
n_ += count;
for(auto it = begin() + index;
first != last; ++it, ++first)
Traits::assign(*it, *first);
term();
return begin() + index;
}
template<std::size_t N, class CharT, class Traits>
template<class T>
auto
static_string<N, CharT, Traits>::
insert(size_type index, const T& t,
size_type index_str, size_type count) ->
typename std::enable_if<std::is_convertible<
T const&, string_view_type>::value &&
! std::is_convertible<T const&, CharT const*>::value,
static_string&>::type
{
auto const str =
string_view_type(t).substr(index_str, count);
return insert(index, str.data(), str.size());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
erase(size_type index, size_type count) ->
static_string&
{
if(index > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"index > size()"});
auto const n = (std::min)(count, size() - index);
Traits::move(
&s_[index], &s_[index + n], size() - (index + n) + 1);
n_ -= n;
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
erase(const_iterator pos) ->
iterator
{
erase(pos - begin(), 1);
return begin() + (pos - begin());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
erase(const_iterator first, const_iterator last) ->
iterator
{
erase(first - begin(),
std::distance(first, last));
return begin() + (first - begin());
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
push_back(CharT ch)
{
if(size() >= max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() >= max_size()"});
Traits::assign(s_[n_++], ch);
term();
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
auto
static_string<N, CharT, Traits>::
append(static_string<M, CharT, Traits> const& str,
size_type pos, size_type count) ->
static_string&
{
// Valid range is [0, size)
if(pos >= str.size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos > str.size()"});
string_view_type const ss{&str.s_[pos],
(std::min)(count, str.size() - pos)};
insert(size(), ss.data(), ss.size());
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
substr(size_type pos, size_type count) const ->
string_view_type
{
if(pos > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos > size()"});
return{&s_[pos], (std::min)(count, size() - pos)};
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
copy(CharT* dest, size_type count, size_type pos) const ->
size_type
{
auto const str = substr(pos, count);
Traits::copy(dest, str.data(), str.size());
return str.size();
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
resize(std::size_t n)
{
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
if(n > n_)
Traits::assign(&s_[n_], n - n_, CharT{});
n_ = n;
term();
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
resize(std::size_t n, CharT c)
{
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
if(n > n_)
Traits::assign(&s_[n_], n - n_, c);
n_ = n;
term();
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
swap(static_string& str)
{
static_string tmp(str);
str.n_ = n_;
Traits::copy(&str.s_[0], &s_[0], n_ + 1);
n_ = tmp.n_;
Traits::copy(&s_[0], &tmp.s_[0], n_ + 1);
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
void
static_string<N, CharT, Traits>::
swap(static_string<M, CharT, Traits>& str)
{
if(size() > str.max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() > str.max_size()"});
if(str.size() > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"str.size() > max_size()"});
static_string tmp(str);
str.n_ = n_;
Traits::copy(&str.s_[0], &s_[0], n_ + 1);
n_ = tmp.n_;
Traits::copy(&s_[0], &tmp.s_[0], n_ + 1);
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign_char(CharT ch, std::true_type) ->
static_string&
{
n_ = 1;
Traits::assign(s_[0], ch);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign_char(CharT, std::false_type) ->
static_string&
{
BOOST_THROW_EXCEPTION(std::length_error{
"max_size() == 0"});
}
namespace detail {
template<class Integer>
static_string<max_digits(sizeof(Integer))>
to_static_string(Integer x, std::true_type)
{
if(x == 0)
return {'0'};
static_string<detail::max_digits(
sizeof(Integer))> s;
if(x < 0)
{
x = -x;
char buf[max_digits(sizeof(x))];
char* p = buf;
for(;x > 0; x /= 10)
*p++ = "0123456789"[x % 10];
s.resize(1 + p - buf);
s[0] = '-';
auto d = &s[1];
while(p > buf)
*d++ = *--p;
}
else
{
char buf[max_digits(sizeof(x))];
char* p = buf;
for(;x > 0; x /= 10)
*p++ = "0123456789"[x % 10];
s.resize(p - buf);
auto d = &s[0];
while(p > buf)
*d++ = *--p;
}
return s;
}
template<class Integer>
static_string<max_digits(sizeof(Integer))>
to_static_string(Integer x, std::false_type)
{
if(x == 0)
return {'0'};
char buf[max_digits(sizeof(x))];
char* p = buf;
for(;x > 0; x /= 10)
*p++ = "0123456789"[x % 10];
static_string<detail::max_digits(
sizeof(Integer))> s;
s.resize(p - buf);
auto d = &s[0];
while(p > buf)
*d++ = *--p;
return s;
}
} // detail
template<class Integer, class>
static_string<detail::max_digits(sizeof(Integer))>
to_static_string(Integer x)
{
using CharT = char;
using Traits = std::char_traits<CharT>;
BOOST_STATIC_ASSERT(std::is_integral<Integer>::value);
char buf[detail::max_digits(sizeof(Integer))];
auto last = buf + sizeof(buf);
auto it = detail::raw_to_string<
CharT, Integer, Traits>(last, sizeof(buf), x);
static_string<detail::max_digits(sizeof(Integer))> s;
s.resize(static_cast<std::size_t>(last - it));
auto p = s.data();
while(it < last)
Traits::assign(*p++, *it++);
return s;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,73 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STRING_IPP
#define BOOST_BEAST_IMPL_STRING_IPP
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/string.hpp>
#include <algorithm>
namespace boost {
namespace beast {
bool
iequals(
beast::string_view lhs,
beast::string_view rhs)
{
auto n = lhs.size();
if(rhs.size() != n)
return false;
auto p1 = lhs.data();
auto p2 = rhs.data();
char a, b;
// fast loop
while(n--)
{
a = *p1++;
b = *p2++;
if(a != b)
goto slow;
}
return true;
slow:
do
{
if( detail::ascii_tolower(a) !=
detail::ascii_tolower(b))
return false;
a = *p1++;
b = *p2++;
}
while(n--);
return true;
}
bool
iless::operator()(
string_view lhs,
string_view rhs) const
{
using std::begin;
using std::end;
return std::lexicographical_compare(
begin(lhs), end(lhs), begin(rhs), end(rhs),
[](char c1, char c2)
{
return detail::ascii_tolower(c1) < detail::ascii_tolower(c2);
}
);
}
} // beast
} // boost
#endif

View File

@@ -15,6 +15,7 @@
#include <boost/asio/buffer.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/type_traits/type_with_alignment.hpp>
#include <iterator>
#include <limits>
#include <memory>
@@ -62,14 +63,13 @@ namespace beast {
template<class Allocator>
class basic_multi_buffer
#if ! BOOST_BEAST_DOXYGEN
: private boost::empty_value<
typename detail::allocator_traits<Allocator>::
template rebind_alloc<char>>
: private boost::empty_value<Allocator>
#endif
{
using base_alloc_type = typename
detail::allocator_traits<Allocator>::
template rebind_alloc<char>;
// Fancy pointers are not supported
static_assert(std::is_pointer<typename
std::allocator_traits<Allocator>::pointer>::value,
"Allocator must use regular pointers");
static bool constexpr default_nothrow =
std::is_nothrow_default_constructible<Allocator>::value;
@@ -77,19 +77,61 @@ class basic_multi_buffer
// Storage for the list of buffers representing the input
// and output sequences. The allocation for each element
// contains `element` followed by raw storage bytes.
class element;
class element
: public boost::intrusive::list_base_hook<
boost::intrusive::link_mode<
boost::intrusive::normal_link>>
{
using size_type = typename
detail::allocator_traits<Allocator>::size_type;
size_type const size_;
public:
element(element const&) = delete;
explicit
element(size_type n) noexcept
: size_(n)
{
}
size_type
size() const noexcept
{
return size_;
}
char*
data() const noexcept
{
return const_cast<char*>(
reinterpret_cast<char const*>(this + 1));
}
};
template<bool>
class readable_bytes;
class subrange;
using size_type = typename
detail::allocator_traits<Allocator>::size_type;
using align_type = typename
boost::type_with_alignment<alignof(element)>::type;
using rebind_type = typename
beast::detail::allocator_traits<Allocator>::
template rebind_alloc<align_type>;
using alloc_traits =
beast::detail::allocator_traits<base_alloc_type>;
using list_type = typename boost::intrusive::make_list<element,
boost::intrusive::constant_time_size<true>>::type;
using iter = typename list_type::iterator;
using const_iter = typename list_type::const_iterator;
beast::detail::allocator_traits<rebind_type>;
using size_type = typename alloc_traits::size_type;
using list_type = typename boost::intrusive::make_list<
element, boost::intrusive::constant_time_size<false>>::type;
using iter = typename list_type::iterator;
using const_iter = typename list_type::const_iterator;
using pocma = typename
alloc_traits::propagate_on_container_move_assignment;
@@ -114,6 +156,18 @@ class basic_multi_buffer
size_type out_end_ = 0; // output end offset in list_.back()
public:
#if BOOST_BEAST_DOXYGEN
/// The ConstBufferSequence used to represent the readable bytes.
using const_buffers_type = __implementation_defined__;
/// The MutableBufferSequence used to represent the writable bytes.
using mutable_buffers_type = __implementation_defined__;
#else
using const_buffers_type = subrange<false>;
using mutable_buffers_type = subrange<true>;
#endif
/// The type of allocator used.
using allocator_type = Allocator;
@@ -405,21 +459,6 @@ public:
//--------------------------------------------------------------------------
#if BOOST_BEAST_DOXYGEN
/// The ConstBufferSequence used to represent the readable bytes.
using const_buffers_type = __implementation_defined__;
/// The MutableBufferSequence used to represent the readable bytes.
using mutable_data_type = __implementation_defined__;
/// The MutableBufferSequence used to represent the writable bytes.
using mutable_buffers_type = __implementation_defined__;
#else
using const_buffers_type = readable_bytes<false>;
using mutable_data_type = readable_bytes<true>;
class mutable_buffers_type;
#endif
/// Returns the number of readable bytes.
size_type
size() const noexcept
@@ -459,7 +498,7 @@ public:
@note The sequence may contain multiple contiguous memory regions.
*/
mutable_data_type
mutable_buffers_type
data() noexcept;
/** Returns a mutable buffer sequence representing writable bytes.
@@ -552,4 +591,4 @@ using multi_buffer = basic_multi_buffer<std::allocator<char>>;
#include <boost/beast/core/impl/multi_buffer.hpp>
#endif
#endif

View File

@@ -41,8 +41,10 @@ namespace beast {
class rate_policy_access
{
private:
#ifndef BOOST_BEAST_DOXYGEN
template<class, class, class>
friend class basic_stream;
#endif
template<class Policy>
static
@@ -101,7 +103,9 @@ private:
*/
class unlimited_rate_policy
{
#ifndef BOOST_BEAST_DOXYGEN
friend class rate_policy_access;
#endif
static std::size_t constexpr all =
(std::numeric_limits<std::size_t>::max)();
@@ -149,10 +153,12 @@ class unlimited_rate_policy
*/
class simple_rate_policy
{
#ifndef BOOST_BEAST_DOXYGEN
friend class rate_policy_access;
#endif
static std::size_t constexpr all =
std::numeric_limits<std::size_t>::max();
(std::numeric_limits<std::size_t>::max)();
std::size_t rd_remain_ = all;
std::size_t wr_remain_ = all;

View File

@@ -11,6 +11,7 @@
#define BOOST_BEAST_CORE_SAVED_HANDLER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/asio/cancellation_type.hpp>
namespace boost {
namespace beast {
@@ -72,10 +73,13 @@ public:
The implementation takes ownership of the handler by performing a decay-copy.
@param alloc The allocator to use.
@param cancel_type The type of cancellation allowed to complete this op.
*/
template<class Handler, class Allocator>
void
emplace(Handler&& handler, Allocator const& alloc);
emplace(Handler&& handler, Allocator const& alloc,
net::cancellation_type cancel_type = net::cancellation_type::terminal);
/** Store a completion handler in the container.
@@ -85,10 +89,13 @@ public:
@param handler The completion handler to store.
The implementation takes ownership of the handler by performing a decay-copy.
@param cancel_type The type of cancellation allowed to complete this op.
*/
template<class Handler>
void
emplace(Handler&& handler);
emplace(Handler&& handler,
net::cancellation_type cancel_type = net::cancellation_type::terminal);
/** Discard the saved handler, if one exists.

View File

@@ -11,203 +11,13 @@
#define BOOST_BEAST_CORE_SPAN_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <algorithm>
#include <iterator>
#include <string>
#include <type_traits>
#include <boost/core/span.hpp>
namespace boost {
namespace beast {
/** A range of bytes expressed as a ContiguousContainer
This class implements a non-owning reference to a storage
area of a certain size and having an underlying integral
type with size of 1.
@tparam T The type pointed to by span iterators
*/
template<class T>
class span
{
T* data_ = nullptr;
std::size_t size_ = 0;
public:
/// The type of value, including cv qualifiers
using element_type = T;
/// The type of value of each span element
using value_type = typename std::remove_const<T>::type;
/// The type of integer used to index the span
using index_type = std::ptrdiff_t;
/// A pointer to a span element
using pointer = T*;
/// A reference to a span element
using reference = T&;
/// The iterator used by the container
using iterator = pointer;
/// The const pointer used by the container
using const_pointer = T const*;
/// The const reference used by the container
using const_reference = T const&;
/// The const iterator used by the container
using const_iterator = const_pointer;
/// Constructor
span() = default;
/// Constructor
span(span const&) = default;
/// Assignment
span& operator=(span const&) = default;
/** Constructor
@param data A pointer to the beginning of the range of elements
@param size The number of elements pointed to by `data`
*/
span(T* data, std::size_t size)
: data_(data), size_(size)
{
}
/** Constructor
@param container The container to construct from
*/
template<class ContiguousContainer
#if ! BOOST_BEAST_DOXYGEN
, class = typename std::enable_if<
detail::is_contiguous_container<
ContiguousContainer, T>::value>::type
#endif
>
explicit
span(ContiguousContainer&& container)
: data_(container.data())
, size_(container.size())
{
}
#if ! BOOST_BEAST_DOXYGEN
template<class CharT, class Traits, class Allocator>
explicit
span(std::basic_string<CharT, Traits, Allocator>& s)
: data_(&s[0])
, size_(s.size())
{
}
template<class CharT, class Traits, class Allocator>
explicit
span(std::basic_string<CharT, Traits, Allocator> const& s)
: data_(s.data())
, size_(s.size())
{
}
#endif
/** Assignment
@param container The container to assign from
*/
template<class ContiguousContainer>
#if BOOST_BEAST_DOXYGEN
span&
#else
typename std::enable_if<detail::is_contiguous_container<
ContiguousContainer, T>::value,
span&>::type
#endif
operator=(ContiguousContainer&& container)
{
data_ = container.data();
size_ = container.size();
return *this;
}
#if ! BOOST_BEAST_DOXYGEN
template<class CharT, class Traits, class Allocator>
span&
operator=(std::basic_string<
CharT, Traits, Allocator>& s)
{
data_ = &s[0];
size_ = s.size();
return *this;
}
template<class CharT, class Traits, class Allocator>
span&
operator=(std::basic_string<
CharT, Traits, Allocator> const& s)
{
data_ = s.data();
size_ = s.size();
return *this;
}
#endif
/// Returns `true` if the span is empty
bool
empty() const
{
return size_ == 0;
}
/// Returns a pointer to the beginning of the span
T*
data() const
{
return data_;
}
/// Returns the number of elements in the span
std::size_t
size() const
{
return size_;
}
/// Returns an iterator to the beginning of the span
const_iterator
begin() const
{
return data_;
}
/// Returns an iterator to the beginning of the span
const_iterator
cbegin() const
{
return data_;
}
/// Returns an iterator to one past the end of the span
const_iterator
end() const
{
return data_ + size_;
}
/// Returns an iterator to one past the end of the span
const_iterator
cend() const
{
return data_ + size_;
}
};
template<class T, std::size_t E = boost::dynamic_extent>
using span = boost::span<T, E>;
} // beast
} // boost

View File

@@ -13,11 +13,7 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/buffers_pair.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstring>
namespace boost {
namespace beast {
@@ -98,14 +94,11 @@ public:
/// The ConstBufferSequence used to represent the readable bytes.
using const_buffers_type = __implementation_defined__;
/// The MutableBufferSequence used to represent the readable bytes.
using mutable_data_type = __implementation_defined__;
/// The MutableBufferSequence used to represent the writable bytes.
using mutable_buffers_type = __implementation_defined__;
#else
using const_buffers_type = detail::buffers_pair<false>;
using mutable_data_type = detail::buffers_pair<true>;
using mutable_buffers_type = detail::buffers_pair<true>;
#endif
@@ -134,7 +127,7 @@ public:
BOOST_BEAST_DECL
const_buffers_type
data() const noexcept;
/// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
cdata() const noexcept
@@ -144,17 +137,16 @@ public:
/// Returns a mutable buffer sequence representing the readable bytes
BOOST_BEAST_DECL
mutable_data_type
mutable_buffers_type
data() noexcept;
/** Returns a mutable buffer sequence representing writable bytes.
Returns a mutable buffer sequence representing the writable
bytes containing exactly `n` bytes of storage. Memory may be
reallocated as needed.
bytes containing exactly `n` bytes of storage.
All buffers sequences previously obtained using
@ref data or @ref prepare are invalidated.
@ref data or @ref prepare may be invalidated.
@param n The desired number of bytes in the returned buffer
sequence.

File diff suppressed because it is too large Load Diff

View File

@@ -111,7 +111,7 @@ using executor_type =
#else
template<class T>
using executor_type =
decltype(std::declval<T&>().get_executor());
typename std::decay<decltype(std::declval<T&>().get_executor())>::type;
#endif
/** Determine if `T` has the `get_executor` member function.

View File

@@ -11,82 +11,11 @@
#define BOOST_BEAST_STRING_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/version.hpp>
#if defined(BOOST_BEAST_USE_STD_STRING_VIEW)
#include <string_view>
#else
#include <boost/utility/string_view.hpp>
#endif
#include <algorithm>
#include <boost/beast/core/string_type.hpp>
namespace boost {
namespace beast {
#if defined(BOOST_BEAST_USE_STD_STRING_VIEW)
/// The type of string view used by the library
using string_view = std::string_view;
/// The type of basic string view used by the library
template<class CharT, class Traits>
using basic_string_view =
std::basic_string_view<CharT, Traits>;
#else
/// The type of string view used by the library
using string_view = boost::string_view;
/// The type of basic string view used by the library
template<class CharT, class Traits>
using basic_string_view =
boost::basic_string_view<CharT, Traits>;
#endif
namespace detail {
inline
char
ascii_tolower(char c)
{
return ((static_cast<unsigned>(c) - 65U) < 26) ?
c + 'a' - 'A' : c;
}
template<class = void>
bool
iequals(
beast::string_view lhs,
beast::string_view rhs)
{
auto n = lhs.size();
if(rhs.size() != n)
return false;
auto p1 = lhs.data();
auto p2 = rhs.data();
char a, b;
// fast loop
while(n--)
{
a = *p1++;
b = *p2++;
if(a != b)
goto slow;
}
return true;
slow:
do
{
if(ascii_tolower(a) != ascii_tolower(b))
return false;
a = *p1++;
b = *p2++;
}
while(n--);
return true;
}
} // detail
/** Returns `true` if two strings are equal, using a case-insensitive comparison.
The case-comparison operation is defined only for low-ASCII characters.
@@ -95,41 +24,38 @@ slow:
@param rhs The string on the right side of the equality
*/
inline
BOOST_BEAST_DECL
bool
iequals(
beast::string_view lhs,
beast::string_view rhs)
{
return detail::iequals(lhs, rhs);
}
beast::string_view rhs);
/** A case-insensitive less predicate for strings.
The case-comparison operation is defined only for low-ASCII characters.
As of C++14, containers using this class as the `Compare` type will take part
in heterogeneous lookup if the search term is implicitly convertible to
@ref string_view.
*/
struct iless
{
BOOST_BEAST_DECL
bool
operator()(
string_view lhs,
string_view rhs) const
{
using std::begin;
using std::end;
return std::lexicographical_compare(
begin(lhs), end(lhs), begin(rhs), end(rhs),
[](char c1, char c2)
{
return detail::ascii_tolower(c1) < detail::ascii_tolower(c2);
}
);
}
string_view rhs) const;
using is_transparent = void;
};
/** A case-insensitive equality predicate for strings.
The case-comparison operation is defined only for low-ASCII characters.
As of C++14, containers using this class as the `Compare` type will take part
in heterogeneous lookup if the search term is implicitly convertible to
@ref string_view.
*/
struct iequal
{
@@ -140,9 +66,15 @@ struct iequal
{
return iequals(lhs, rhs);
}
using is_transparent = void;
};
} // beast
} // boost
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/beast/core/impl/string.ipp>
#endif
#endif

View File

@@ -10,11 +10,13 @@
#ifndef BOOST_BEAST_STRING_PARAM_HPP
#define BOOST_BEAST_STRING_PARAM_HPP
#if defined(BOOST_BEAST_ALLOW_DEPRECATED) && !defined(BOOST_BEAST_DOXYGEN)
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/static_string.hpp>
#include <boost/beast/core/detail/static_ostream.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/optional.hpp>
namespace boost {
@@ -127,4 +129,6 @@ public:
#include <boost/beast/core/impl/string_param.hpp>
#endif // defined(BOOST_BEAST_ALLOW_DEPRECATED) && !BOOST_BEAST_DOXYGEN
#endif

View File

@@ -0,0 +1,42 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_STRING_TYPE_HPP
#define BOOST_BEAST_STRING_TYPE_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#if defined(BOOST_BEAST_USE_STD_STRING_VIEW)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("BOOST_BEAST_USE_STD_STRING_VIEW is deprecated, use BOOST_NO_CXX17_HDR_STRING_VIEW instead");
#endif
namespace boost {
namespace beast {
/// The type of string view used by the library
using string_view = boost::core::string_view;
/// The type of `basic_string_view` used by the library
template<class CharT>
using basic_string_view =
boost::core::basic_string_view<CharT>;
template<class S>
inline string_view
to_string_view(const S& s)
{
return string_view(s.data(), s.size());
}
} // beast
} // boost
#endif

View File

@@ -25,7 +25,7 @@ namespace beast {
*/
using tcp_stream = basic_stream<
net::ip::tcp,
net::executor,
net::any_io_executor,
unlimited_rate_policy>;
} // beast

View File

@@ -1,58 +0,0 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_TYPE_TRAITS_HPP
#define BOOST_BEAST_TYPE_TRAITS_HPP
#ifndef BOOST_BEAST_DOXYGEN
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/config/pragma_message.hpp>
#include <type_traits.hpp>
BOOST_PRAGMA_MESSAGE("<boost/beast/core/type_traits.hpp> is DEPRECATED and will be removed in a future release.")
namespace boost {
namespace beast {
/** Determine if `T` meets the requirements of <em>CompletionHandler</em>.
This trait checks whether a type meets the requirements for a completion
handler, and is also callable with the specified signature.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
struct handler
{
void operator()(error_code&);
};
static_assert(is_completion_handler<handler, void(error_code&)>::value,
"Not a completion handler");
@endcode
*/
template<class T, class Signature>
#if BOOST_BEAST_DOXYGEN
using is_completion_handler = __see_below__
#else
using is_completion_handler = std::integral_constant<bool,
std::is_move_constructible<typename std::decay<T>::type>::value &&
detail::is_invocable<T, Signature>::value>;
#endif
} // beast
} // boost
#endif
#endif