Add buffers_generator

This commit is contained in:
sehe
2022-05-21 22:12:13 -07:00
committed by Vinnie Falco
parent 344c10ff1e
commit 84e689c447
11 changed files with 871 additions and 3 deletions
+1
View File
@@ -19,6 +19,7 @@
#include <boost/beast/core/buffered_read_stream.hpp>
#include <boost/beast/core/buffers_adaptor.hpp>
#include <boost/beast/core/buffers_cat.hpp>
#include <boost/beast/core/buffers_generator.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_range.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
@@ -0,0 +1,206 @@
//
// 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/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 The generator returns an empty buffers sequence.
@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 The generator returns an empty buffers sequence.
@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 @ref BuffersGenerator to a stream. The
function call always returns immediately. The asynchronous
operation will continue until one of the following
conditions is true:
@li The generator returns an empty buffers sequence.
@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 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 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,
class CompletionToken
#if !BOOST_BEAST_DOXYGEN
,
typename std::enable_if<is_buffers_generator<
BuffersGenerator>::value>::type* = nullptr
#endif
>
auto
async_write(
AsyncWriteStream& stream,
BuffersGenerator generator,
CompletionToken&& token) //
-> typename net::async_result<
typename std::decay<
CompletionToken>::type,
void(error_code, std::size_t)>::
return_type;
} // namespace beast
} // namespace boost
#include <include/boost/beast/core/impl/buffers_generator.hpp>
#endif
@@ -0,0 +1,176 @@
//
// 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,
class CompletionToken,
typename std::enable_if<is_buffers_generator<
BuffersGenerator>::value>::type* /*= nullptr*/
>
auto
async_write(
AsyncWriteStream& stream,
BuffersGenerator generator,
CompletionToken&& token) ->
typename net::async_result<
typename std::decay<CompletionToken>::type,
void(error_code, std::size_t)>::return_type
{
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