Refactor buffers_adaptor (API Change):

* Tidy up tests
* Increase code coverage
* Remove move special members
* Correct behavior for default constructed iterators

API Changes:

* buffers_adaptor is renamed (was buffers_adapter)

Actions Required:

* Replace buffers_adapter.hpp with buffers_adaptor.hpp, and
  replace buffers_adapter with buffers_adaptor. Or, define
  BOOST_BEAST_ALLOW_DEPRECATED
This commit is contained in:
Vinnie Falco
2018-12-14 11:13:26 -08:00
parent c1d7a83af2
commit 117dda7b31
15 changed files with 1037 additions and 537 deletions

View File

@ -3,6 +3,17 @@ Version 200
* Don't include OpenSSL for core snippets
* Tidy up msvc-14 workaround in multi_buffer
* buffers_cat fixes and coverage
* Refactor buffers_adaptor
API Changes:
* buffers_adaptor is renamed (was buffers_adapter)
Actions Required:
* Replace buffers_adapter.hpp with buffers_adaptor.hpp, and
replace buffers_adapter with buffers_adaptor. Or, define
BOOST_BEAST_ALLOW_DEPRECATED
--------------------------------------------------------------------------------

View File

@ -88,7 +88,7 @@ set of additional implementations of the dynamic buffer concept:
[table Dynamic Buffer Implementations
[[Name][Description]]
[[
[link beast.ref.boost__beast__buffers_adapter `buffers_adapter`]
[link beast.ref.boost__beast__buffers_adaptor `buffers_adaptor`]
][
This wrapper adapts any __MutableBufferSequence__ into a
__DynamicBuffer__ with an upper limit on the total size of the input and

View File

@ -96,7 +96,7 @@ in future versions.
* Generated WebSocket masks use a secure PRNG by default
* Improvements to [link beast.ref.boost__beast__buffers_adapter `buffers_adapter`]
* Improvements to [link beast.ref.boost__beast__buffers_adaptor `buffers_adaptor`]
* ([issue 1188]) Set "/permissive-" for MSVC builds
@ -134,9 +134,9 @@ in future versions.
* Fix [link beast.ref.boost__beast__http__parser `http::parser`] constructor javadoc
* Fix [link beast.ref.boost__beast__buffers_adapter `buffers_adapter`] iterator value type
* Fix [link beast.ref.boost__beast__buffers_adaptor `buffers_adaptor`] iterator value type
* Fix [link beast.ref.boost__beast__buffers_adapter.max_size `buffers_adapter::max_size`]
* Fix [link beast.ref.boost__beast__buffers_adaptor.max_size `buffers_adaptor::max_size`]
* Fix [link beast.ref.boost__beast__buffers_prefix `buffers_prefix`] iterator decrement

View File

@ -180,7 +180,7 @@
<member><link linkend="beast.ref.boost__beast__basic_flat_buffer">basic_flat_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__basic_multi_buffer">basic_multi_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__buffered_read_stream">buffered_read_stream</link></member>
<member><link linkend="beast.ref.boost__beast__buffers_adapter">buffers_adapter</link></member>
<member><link linkend="beast.ref.boost__beast__buffers_adaptor">buffers_adaptor</link></member>
<member><link linkend="beast.ref.boost__beast__buffers_cat_view">buffers_cat_view</link></member>
<member><link linkend="beast.ref.boost__beast__buffers_prefix_view">buffers_prefix_view</link></member>
<member><link linkend="beast.ref.boost__beast__buffers_suffix">buffers_suffix</link></member>

View File

@ -12,7 +12,7 @@
#include <boost/beast/_experimental/core/detail/dynamic_buffer_ref.hpp>
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/buffers_adapter.hpp>
#include <boost/beast/core/buffers_adaptor.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/detail/buffers_ref.hpp>
@ -132,7 +132,7 @@ class icy_stream<NextLayer>::read_op
struct data
{
icy_stream<NextLayer>& s;
buffers_adapter<MutableBufferSequence> b;
buffers_adaptor<MutableBufferSequence> b;
bool match = false;
data(
@ -234,7 +234,7 @@ operator()(
{
using iterator = net::buffers_iterator<
typename beast::detail::dynamic_buffer_ref<
buffers_adapter<MutableBufferSequence>>::const_buffers_type>;
buffers_adaptor<MutableBufferSequence>>::const_buffers_type>;
auto& d = *d_;
BOOST_ASIO_CORO_REENTER(*this)
{
@ -400,8 +400,8 @@ read_some(MutableBufferSequence const& buffers, error_code& ec)
"MutableBufferSequence requirements not met");
using iterator = net::buffers_iterator<
typename beast::detail::dynamic_buffer_ref<
buffers_adapter<MutableBufferSequence>>::const_buffers_type>;
buffers_adapter<MutableBufferSequence> b(buffers);
buffers_adaptor<MutableBufferSequence>>::const_buffers_type>;
buffers_adaptor<MutableBufferSequence> b(buffers);
if(b.max_size() == 0)
{
ec = {};

View File

@ -15,7 +15,7 @@
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffered_read_stream.hpp>
#include <boost/beast/core/buffers_adapter.hpp>
#include <boost/beast/core/buffers_adaptor.hpp>
#include <boost/beast/core/buffers_cat.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_range.hpp>

View File

@ -11,216 +11,25 @@
#define BOOST_BEAST_BUFFERS_ADAPTER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
#include <type_traits>
#ifdef BOOST_BEAST_ALLOW_DEPRECATED
#include <boost/beast/core/buffers_adaptor.hpp>
namespace boost {
namespace beast {
/** Adapts a <em>MutableBufferSequence</em> into a <em>DynamicBuffer</em>.
This class wraps a <em>MutableBufferSequence</em> to meet the requirements
of <em>DynamicBuffer</em>. Upon construction the input and output sequences
are empty. A copy of the mutable buffer sequence object is stored; however,
ownership of the underlying memory is not transferred. The caller is
responsible for making sure that referenced memory remains valid
for the duration of any operations.
The size of the mutable buffer sequence determines the maximum
number of bytes which may be prepared and committed.
@tparam MutableBufferSequence The type of mutable buffer sequence to wrap.
*/
template<class MutableBufferSequence>
class buffers_adapter
{
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
using iter_type = typename
detail::buffer_sequence_iterator<
MutableBufferSequence>::type;
MutableBufferSequence bs_;
iter_type begin_;
iter_type out_;
iter_type end_;
std::size_t max_size_;
std::size_t in_pos_ = 0; // offset in *begin_
std::size_t in_size_ = 0; // size of input sequence
std::size_t out_pos_ = 0; // offset in *out_
std::size_t out_end_ = 0; // output end offset
template<class Deduced>
buffers_adapter(Deduced&& other,
std::size_t nbegin, std::size_t nout,
std::size_t nend)
: bs_(std::forward<Deduced>(other).bs_)
, begin_(std::next(bs_.begin(), nbegin))
, out_(std::next(bs_.begin(), nout))
, end_(std::next(bs_.begin(), nend))
, max_size_(other.max_size_)
, in_pos_(other.in_pos_)
, in_size_(other.in_size_)
, out_pos_(other.out_pos_)
, out_end_(other.out_end_)
{
}
iter_type end_impl() const;
public:
/// The type of the underlying mutable buffer sequence
using value_type = MutableBufferSequence;
/// Move constructor.
buffers_adapter(buffers_adapter&& other);
/// Copy constructor.
buffers_adapter(buffers_adapter const& other);
/// Move assignment.
buffers_adapter& operator=(buffers_adapter&& other);
/// Copy assignment.
buffers_adapter& operator=(buffers_adapter const&);
/** Construct a buffers adapter.
@param buffers The mutable buffer sequence to wrap. A copy of
the object will be made, but ownership of the memory is not
transferred.
*/
explicit
buffers_adapter(MutableBufferSequence const& buffers);
/** Constructor
This constructs the buffer adapter in-place from
a list of arguments.
@param args Arguments forwarded to the buffers constructor.
*/
template<class... Args>
explicit
buffers_adapter(boost::in_place_init_t, Args&&... args);
/// Returns the original mutable buffer sequence
value_type const&
value() const
{
return bs_;
}
//--------------------------------------------------------------------------
#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
class const_buffers_type;
class mutable_buffers_type;
#endif
/// Returns the number of readable bytes.
std::size_t
size() const noexcept
{
return in_size_;
}
/// Return the maximum number of bytes, both readable and writable, that can ever be held.
std::size_t
max_size() const noexcept
{
return 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 max_size_;
}
/// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
data() const noexcept;
/** Returns a mutable buffer sequence representing writable bytes.
Returns a mutable buffer sequence representing the writable
bytes containing exactly `n` bytes of storage. This function
does not allocate memory. Instead, the storage comes from
the underlying mutable buffer sequence.
All buffer sequences previously obtained using @ref prepare are
invalidated. Buffer sequences previously obtained using @ref data
remain valid.
@param n The desired number of bytes in the returned buffer
sequence.
@throws std::length_error if `size() + n` exceeds `max_size()`.
@par Exception Safety
Strong guarantee.
*/
mutable_buffers_type
prepare(std::size_t n);
/** Append writable bytes to the readable bytes.
Appends n bytes from the start of the writable bytes to the
end of the readable bytes. The remainder of the writable bytes
are discarded. If n is greater than the number of writable
bytes, all writable bytes are appended to the readable bytes.
All buffer sequences previously obtained using @ref prepare are
invalidated. Buffer sequences previously obtained using @ref data
remain valid.
@param n The number of bytes to append. If this number
is greater than the number of writable bytes, all
writable bytes are appended.
@par Exception Safety
No-throw guarantee.
*/
void
commit(std::size_t n) noexcept;
/** Remove bytes from beginning of the readable bytes.
Removes n bytes from the beginning of the readable bytes.
All buffers sequences previously obtained using
@ref data or @ref prepare are invalidated.
@param n The number of bytes to remove. If this number
is greater than the number of readable bytes, all
readable bytes are removed.
@par Exception Safety
No-throw guarantee.
*/
void
consume(std::size_t n) noexcept;
};
using buffers_adapter = buffers_adaptor<MutableBufferSequence>;
} // beast
} // boost
#include <boost/beast/core/impl/buffers_adapter.hpp>
#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

@ -0,0 +1,228 @@
//
// Copyright (c) 2016-2017 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_ADAPTOR_HPP
#define BOOST_BEAST_BUFFERS_ADAPTOR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
#include <type_traits>
namespace boost {
namespace beast {
/** Adapts a <em>MutableBufferSequence</em> into a <em>DynamicBuffer</em>.
This class wraps a <em>MutableBufferSequence</em> to meet the requirements
of <em>DynamicBuffer</em>. Upon construction the input and output sequences
are empty. A copy of the mutable buffer sequence object is stored; however,
ownership of the underlying memory is not transferred. The caller is
responsible for making sure that referenced memory remains valid
for the duration of any operations.
The size of the mutable buffer sequence determines the maximum
number of bytes which may be prepared and committed.
@tparam MutableBufferSequence The type of mutable buffer sequence to adapt.
*/
template<class MutableBufferSequence>
class buffers_adaptor
{
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
using iter_type = typename
detail::buffer_sequence_iterator<
MutableBufferSequence>::type;
template<bool>
class readable_bytes;
MutableBufferSequence bs_;
iter_type begin_;
iter_type out_;
iter_type end_;
std::size_t max_size_;
std::size_t in_pos_ = 0; // offset in *begin_
std::size_t in_size_ = 0; // size of input sequence
std::size_t out_pos_ = 0; // offset in *out_
std::size_t out_end_ = 0; // output end offset
iter_type end_impl() const;
buffers_adaptor(
buffers_adaptor const& other,
std::size_t nbegin,
std::size_t nout,
std::size_t nend);
public:
/// The type of the underlying mutable buffer sequence
using value_type = MutableBufferSequence;
/** Construct a buffers adaptor.
@param buffers The mutable buffer sequence to wrap. A copy of
the object will be made, but ownership of the memory is not
transferred.
*/
explicit
buffers_adaptor(MutableBufferSequence const& buffers);
/** Constructor
This constructs the buffer adaptor in-place from
a list of arguments.
@param args Arguments forwarded to the buffers constructor.
*/
template<class... Args>
explicit
buffers_adaptor(boost::in_place_init_t, Args&&... args);
/// Copy Constructor
buffers_adaptor(buffers_adaptor const& other);
/// Copy Assignment
buffers_adaptor& operator=(buffers_adaptor const&);
/// Returns the original mutable buffer sequence
value_type const&
value() const
{
return bs_;
}
//--------------------------------------------------------------------------
#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.
std::size_t
size() const noexcept
{
return in_size_;
}
/// Return the maximum number of bytes, both readable and writable, that can ever be held.
std::size_t
max_size() const noexcept
{
return 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 max_size_;
}
/// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
data() const noexcept;
/// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
cdata() const noexcept
{
return data();
}
/// Returns a mutable buffer sequence representing the readable bytes.
mutable_data_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. This function
does not allocate memory. Instead, the storage comes from
the underlying mutable buffer sequence.
All buffer sequences previously obtained using @ref prepare are
invalidated. Buffer sequences previously obtained using @ref data
remain valid.
@param n The desired number of bytes in the returned buffer
sequence.
@throws std::length_error if `size() + n` exceeds `max_size()`.
@par Exception Safety
Strong guarantee.
*/
mutable_buffers_type
prepare(std::size_t n);
/** Append writable bytes to the readable bytes.
Appends n bytes from the start of the writable bytes to the
end of the readable bytes. The remainder of the writable bytes
are discarded. If n is greater than the number of writable
bytes, all writable bytes are appended to the readable bytes.
All buffer sequences previously obtained using @ref prepare are
invalidated. Buffer sequences previously obtained using @ref data
remain valid.
@param n The number of bytes to append. If this number
is greater than the number of writable bytes, all
writable bytes are appended.
@par Exception Safety
No-throw guarantee.
*/
void
commit(std::size_t n) noexcept;
/** Remove bytes from beginning of the readable bytes.
Removes n bytes from the beginning of the readable bytes.
All buffers sequences previously obtained using
@ref data or @ref prepare are invalidated.
@param n The number of bytes to remove. If this number
is greater than the number of readable bytes, all
readable bytes are removed.
@par Exception Safety
No-throw guarantee.
*/
void
consume(std::size_t n) noexcept;
};
} // beast
} // boost
#include <boost/beast/core/impl/buffers_adaptor.hpp>
#endif

View File

@ -7,37 +7,84 @@
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP
#define BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP
#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
#define BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/config/workaround.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning (push)
# pragma warning (disable: 4521) // multiple copy constructors specified
# pragma warning (disable: 4522) // multiple assignment operators specified
#endif
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
const_buffers_type
template<bool isMutable>
class buffers_adaptor<MutableBufferSequence>::
readable_bytes
{
buffers_adapter const* b_;
buffers_adaptor const* b_;
public:
using value_type = net::const_buffer;
using value_type = typename
std::conditional<isMutable,
net::mutable_buffer,
net::const_buffer>::type;
class const_iterator;
const_buffers_type() = delete;
const_buffers_type(
const_buffers_type const&) = default;
const_buffers_type& operator=(
const_buffers_type const&) = default;
readable_bytes() = delete;
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
readable_bytes(
readable_bytes const& other)
: b_(other.b_)
{
}
readable_bytes& operator=(
readable_bytes const& other)
{
b_ = other.b_;
return *this;
}
#else
readable_bytes(
readable_bytes const&) = default;
readable_bytes& operator=(
readable_bytes 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_)
{
}
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
begin() const;
@ -46,23 +93,34 @@ public:
end() const;
private:
friend class buffers_adapter;
friend class buffers_adaptor;
const_buffers_type(buffers_adapter const& b)
readable_bytes(buffers_adaptor const& b)
: b_(&b)
{
}
};
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning (pop)
#endif
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
const_buffers_type::const_iterator
template<bool isMutable>
class buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
const_iterator
{
iter_type it_;
buffers_adapter const* b_ = nullptr;
buffers_adaptor const* b_ = nullptr;
public:
using value_type = net::const_buffer;
using value_type = typename
std::conditional<isMutable,
net::mutable_buffer,
net::const_buffer>::type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@ -70,28 +128,13 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return
(b_ == nullptr) ?
(
other.b_ == nullptr ||
other.it_ == other.b_->end_impl()
):(
(other.b_ == nullptr) ?
(
it_ == b_->end_impl()
): (
b_ == other.b_ &&
it_ == other.it_
)
);
return b_ == other.b_ && it_ == other.it_;
}
bool
@ -144,10 +187,11 @@ public:
}
private:
friend class const_buffers_type;
friend class readable_bytes;
const_iterator(buffers_adapter const& b,
iter_type iter)
const_iterator(
buffers_adaptor const& b,
iter_type iter)
: it_(iter)
, b_(&b)
{
@ -155,18 +199,22 @@ private:
};
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adapter<MutableBufferSequence>::
const_buffers_type::begin() const ->
buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
begin() const ->
const_iterator
{
return const_iterator{*b_, b_->begin_};
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adapter<MutableBufferSequence>::
const_buffers_type::end() const ->
buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
readable_bytes::end() const ->
const_iterator
{
return const_iterator{*b_, b_->end_impl()};
@ -175,10 +223,10 @@ const_buffers_type::end() const ->
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type
{
buffers_adapter const* b_;
buffers_adaptor const* b_;
public:
using value_type = net::mutable_buffer;
@ -198,21 +246,21 @@ public:
end() const;
private:
friend class buffers_adapter;
friend class buffers_adaptor;
mutable_buffers_type(
buffers_adapter const& b)
buffers_adaptor const& b)
: b_(&b)
{
}
};
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::const_iterator
{
iter_type it_;
buffers_adapter const* b_ = nullptr;
buffers_adaptor const* b_ = nullptr;
public:
using value_type = net::mutable_buffer;
@ -223,28 +271,13 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return
(b_ == nullptr) ?
(
other.b_ == nullptr ||
other.it_ == other.b_->end_
):(
(other.b_ == nullptr) ?
(
it_ == b_->end_
): (
b_ == other.b_ &&
it_ == other.it_
)
);
return b_ == other.b_ && it_ == other.it_;
}
bool
@ -299,7 +332,7 @@ public:
private:
friend class mutable_buffers_type;
const_iterator(buffers_adapter const& b,
const_iterator(buffers_adaptor const& b,
iter_type iter)
: it_(iter)
, b_(&b)
@ -309,7 +342,7 @@ private:
template<class MutableBufferSequence>
auto
buffers_adapter<MutableBufferSequence>::
buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
begin() const ->
const_iterator
@ -319,7 +352,7 @@ begin() const ->
template<class MutableBufferSequence>
auto
buffers_adapter<MutableBufferSequence>::
buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
end() const ->
const_iterator
@ -331,7 +364,7 @@ end() const ->
template<class MutableBufferSequence>
auto
buffers_adapter<MutableBufferSequence>::
buffers_adaptor<MutableBufferSequence>::
end_impl() const ->
iter_type
{
@ -339,57 +372,75 @@ end_impl() const ->
}
template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::
buffers_adapter(buffers_adapter&& other)
: buffers_adapter(std::move(other),
std::distance<iter_type>(net::buffer_sequence_begin(other.bs_), other.begin_),
std::distance<iter_type>(net::buffer_sequence_begin(other.bs_), other.out_),
std::distance<iter_type>(net::buffer_sequence_begin(other.bs_), other.end_))
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(
buffers_adaptor const& other,
std::size_t nbegin,
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))
, max_size_(other.max_size_)
, in_pos_(other.in_pos_)
, in_size_(other.in_size_)
, out_pos_(other.out_pos_)
, out_end_(other.out_end_)
{
}
template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::
buffers_adapter(buffers_adapter const& other)
: buffers_adapter(other,
std::distance<iter_type>(net::buffer_sequence_begin(other.bs_), other.begin_),
std::distance<iter_type>(net::buffer_sequence_begin(other.bs_), other.out_),
std::distance<iter_type>(net::buffer_sequence_begin(other.bs_), other.end_))
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(MutableBufferSequence const& bs)
: bs_(bs)
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(
[&bs]
{
using net::buffer_size;
return buffer_size(bs);
}())
{
}
template<class MutableBufferSequence>
template<class... Args>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(
boost::in_place_init_t, Args&&... args)
: bs_{std::forward<Args>(args)...}
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(net::buffer_size(bs_))
{
}
template<class MutableBufferSequence>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(buffers_adaptor const& other)
: buffers_adaptor(
other,
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_),
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.out_),
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_))
{
}
template<class MutableBufferSequence>
auto
buffers_adapter<MutableBufferSequence>::
operator=(buffers_adapter&& other) ->
buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_);
auto const nout = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.out_);
auto const nend = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = std::move(other.bs_);
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_;
out_pos_ = other.out_pos_;
out_end_ = other.out_end_;
return *this;
}
template<class MutableBufferSequence>
auto
buffers_adapter<MutableBufferSequence>::
operator=(buffers_adapter const& other) ->
buffers_adapter&
buffers_adaptor<MutableBufferSequence>::
operator=(buffers_adaptor const& other) ->
buffers_adaptor&
{
auto const nbegin = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
@ -401,9 +452,12 @@ operator=(buffers_adapter const& other) ->
net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
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);
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_;
@ -412,47 +466,43 @@ operator=(buffers_adapter const& other) ->
return *this;
}
template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::
buffers_adapter(MutableBufferSequence const& bs)
: bs_(bs)
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(net::buffer_size(bs_))
{
}
//
template<class MutableBufferSequence>
template<class... Args>
buffers_adapter<MutableBufferSequence>::
buffers_adapter(boost::in_place_init_t, Args&&... args)
: bs_{std::forward<Args>(args)...}
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(net::buffer_size(bs_))
auto
buffers_adaptor<MutableBufferSequence>::
data() const noexcept ->
const_buffers_type
{
return const_buffers_type{*this};
}
template<class MutableBufferSequence>
auto
buffers_adapter<MutableBufferSequence>::
buffers_adaptor<MutableBufferSequence>::
data() noexcept ->
mutable_data_type
{
return mutable_data_type{*this};
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
prepare(std::size_t n) ->
mutable_buffers_type
{
using net::buffer_size;
end_ = out_;
if(end_ != net::buffer_sequence_end(bs_))
{
auto size = buffer_size(*end_) - out_pos_;
auto size = net::buffer_size(*end_) - out_pos_;
if(n > size)
{
n -= size;
while(++end_ !=
net::buffer_sequence_end(bs_))
{
size = buffer_size(*end_);
size = net::buffer_size(*end_);
if(n < size)
{
out_end_ = n;
@ -473,22 +523,13 @@ prepare(std::size_t n) ->
}
if(n > 0)
BOOST_THROW_EXCEPTION(std::length_error{
"buffer overflow"});
"buffers_adaptor too long"});
return mutable_buffers_type{*this};
}
template<class MutableBufferSequence>
auto
buffers_adapter<MutableBufferSequence>::
data() const noexcept ->
const_buffers_type
{
return const_buffers_type{*this};
}
template<class MutableBufferSequence>
void
buffers_adapter<MutableBufferSequence>::
buffers_adaptor<MutableBufferSequence>::
commit(std::size_t n) noexcept
{
if(out_ == end_)
@ -524,7 +565,7 @@ commit(std::size_t n) noexcept
template<class MutableBufferSequence>
void
buffers_adapter<MutableBufferSequence>::
buffers_adaptor<MutableBufferSequence>::
consume(std::size_t n) noexcept
{
while(begin_ != out_)

View File

@ -22,6 +22,7 @@ add_executable (tests-beast-core
buffer_traits.cpp
buffered_read_stream.cpp
buffers_adapter.cpp
buffers_adaptor.cpp
buffers_cat.cpp
buffers_prefix.cpp
buffers_range.cpp
@ -39,9 +40,9 @@ add_executable (tests-beast-core
ostream.cpp
read_size.cpp
span.cpp
static_buffer.cpp
static_string.cpp
string.cpp
static_buffer.cpp
string_param.cpp
type_traits.cpp
detail_base64.cpp

View File

@ -12,6 +12,7 @@ local SOURCES =
buffer_traits.cpp
buffered_read_stream.cpp
buffers_adapter.cpp
buffers_adaptor.cpp
buffers_cat.cpp
buffers_prefix.cpp
buffers_range.cpp

View File

@ -10,18 +10,101 @@
#ifndef BOOST_BEAST_TEST_BUFFER_TEST_HPP
#define BOOST_BEAST_TEST_BUFFER_TEST_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffers_to_string.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/buffers_iterator.hpp>
#include <boost/assert.hpp>
#include <algorithm>
#include <string>
#include <type_traits>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
// VFALCO This is here temporarily
#define SUITE_EXPECT(test, cond) \
((test).expect((cond), __FILE__, __LINE__))
#define SUITE_EXPECTS(test, cond, reason) \
((cond) ? ((test).pass(), true) \
: ((test).fail((reason), __FILE__, __LINE__), false))
//------------------------------------------------------------------------------
/** A MutableBufferSequence for tests, where length is always 3.
*/
class buffers_triple
{
net::mutable_buffer b_[3];
public:
using value_type = net::mutable_buffer;
using const_iterator = net::mutable_buffer const*;
buffers_triple(
buffers_triple const&) = default;
buffers_triple& operator=(
buffers_triple const&) = default;
buffers_triple(char* data, std::size_t size)
{
b_[0] = {data, size/6};
data += b_[0].size();
size -= b_[0].size();
b_[1] = {data, 2*size/5};
data += b_[1].size();
size -= b_[1].size();
b_[2] = {data, size};
BOOST_ASSERT(b_[0].size() > 0);
BOOST_ASSERT(b_[1].size() > 0);
BOOST_ASSERT(b_[2].size() > 0);
}
bool
operator==(buffers_triple const& rhs) const noexcept
{
return
b_[0].data() == rhs.b_[0].data() &&
b_[0].size() == rhs.b_[0].size() &&
b_[1].data() == rhs.b_[1].data() &&
b_[1].size() == rhs.b_[1].size() &&
b_[2].data() == rhs.b_[2].data() &&
b_[2].size() == rhs.b_[2].size();
}
bool
operator!=(buffers_triple const& rhs) const noexcept
{
return !(*this == rhs);
}
const_iterator
begin() const noexcept
{
return &b_[0];
}
const_iterator
end() const noexcept
{
return &b_[3];
}
};
//------------------------------------------------------------------------------
namespace test {
template<class DynamicBuffer>
@ -101,6 +184,397 @@ size_rev_post(ConstBufferSequence const& buffers)
}
} // test
//------------------------------------------------------------------------------
namespace detail {
template<class MutableBufferSequence>
void test_mutable_buffers(
unit_test::suite&,
MutableBufferSequence const&,
net::const_buffer)
{
}
template<class MutableBufferSequence>
void test_mutable_buffers(
unit_test::suite& test,
MutableBufferSequence const& b,
net::mutable_buffer)
{
using net::buffer_size;
string_view src = "Hello, world!";
if(src.size() > buffer_size(b))
src = {src.data(), buffer_size(b)};
net::buffer_copy(b, net::const_buffer(
src.data(), src.size()));
SUITE_EXPECT(test,
beast::buffers_to_string(b) == src);
}
} // detail
/** Test an instance of a constant or mutable buffer sequence.
*/
template<class ConstBufferSequence>
void
test_buffer_sequence(
beast::unit_test::suite& test,
ConstBufferSequence const& buffers)
{
BOOST_STATIC_ASSERT(
net::is_const_buffer_sequence<
ConstBufferSequence>::value);
using net::buffer_size;
using iterator = decltype(
net::buffer_sequence_begin(buffers));
SUITE_EXPECT(test, sizeof(iterator) > 0);
auto const size = buffer_size(buffers);
SUITE_EXPECT(test, size > 0 );
// begin, end
auto const length = std::distance(
net::buffer_sequence_begin(buffers),
net::buffer_sequence_end(buffers));
SUITE_EXPECT(test, length > 0);
SUITE_EXPECT(test,
net::buffer_sequence_begin(buffers) !=
net::buffer_sequence_end(buffers));
// copy construction
ConstBufferSequence b1(buffers);
SUITE_EXPECT(test, buffer_size(b1) == size);
// copy assignment
ConstBufferSequence b2(buffers);
b2 = b1;
SUITE_EXPECT(test, buffer_size(b2) == size);
// iterators
{
iterator it1{};
iterator it2{};
iterator it3 =
net::buffer_sequence_begin(buffers);
iterator it4 =
net::buffer_sequence_end(buffers);
SUITE_EXPECT(test, it1 == it2);
SUITE_EXPECT(test, it1 != it3);
SUITE_EXPECT(test, it3 != it1);
SUITE_EXPECT(test, it1 != it4);
SUITE_EXPECT(test, it4 != it1);
}
// bidirectional
{
auto const first =
net::buffer_sequence_begin(buffers);
auto const last =
net::buffer_sequence_end(buffers);
std::size_t n, m;
iterator it;
// pre-increment
m = 0;
n = length;
for(it = first; n--; ++it)
m += net::buffer_size(*it);
SUITE_EXPECT(test, it == last);
SUITE_EXPECT(test, m == size);
// post-increment
m = 0;
n = length;
for(it = first; n--;)
m += net::buffer_size(*it++);
SUITE_EXPECT(test, it == last);
SUITE_EXPECT(test, m == size);
// pre-decrement
m = 0;
n = length;
for(it = last; n--;)
m += net::buffer_size(*--it);
SUITE_EXPECT(test, it == first);
SUITE_EXPECT(test, m == size);
// post-decrement
m = 0;
n = length;
for(it = last; n--;)
{
it--;
m += net::buffer_size(*it);
}
SUITE_EXPECT(test, it == first);
SUITE_EXPECT(test, m == size);
}
detail::test_mutable_buffers(test, buffers,
buffers_type<ConstBufferSequence>{});
}
//------------------------------------------------------------------------------
/** Metafunction to determine if a type meets the requirements of MutableDynamicBuffer
*/
/* @{ */
// VFALCO This trait needs tests
template<class T, class = void>
struct is_mutable_dynamic_buffer
: std::false_type
{
};
template<class T>
struct is_mutable_dynamic_buffer<T, detail::void_t<decltype(
std::declval<typename T::const_buffers_type&>() =
std::declval<T const&>().data(),
std::declval<typename T::const_buffers_type&>() =
std::declval<T&>().cdata(),
std::declval<typename T::mutable_data_type&>() =
std::declval<T&>().data()
) > > : net::is_dynamic_buffer<T>
{
};
/** @} */
namespace detail {
template<class MutableDynamicBuffer>
void
test_mutable_dynamic_buffer(
unit_test::suite&,
MutableDynamicBuffer const&,
std::false_type)
{
}
template<class MutableDynamicBuffer>
void
test_mutable_dynamic_buffer(
unit_test::suite& test,
MutableDynamicBuffer const& b0,
std::true_type)
{
using net::buffer_size;
BOOST_STATIC_ASSERT(
net::is_mutable_buffer_sequence<typename
MutableDynamicBuffer::mutable_data_type>::value);
string_view src = "Hello, world!";
if(src.size() > b0.max_size())
src = {src.data(), b0.max_size()};
// modify readable bytes
{
MutableDynamicBuffer b(b0);
auto const mb = b.prepare(src.size());
using iter_type = net::buffers_iterator<decltype(mb)>;
SUITE_EXPECT(test, buffer_size(mb) == src.size());
std::fill(
iter_type::begin(mb),
iter_type::end(mb), '*');
b.commit(src.size());
SUITE_EXPECT(test, b.size() == src.size());
SUITE_EXPECT(test,
beast::buffers_to_string(b.data()) ==
std::string(src.size(), '*'));
SUITE_EXPECT(test,
beast::buffers_to_string(b.cdata()) ==
std::string(src.size(), '*'));
auto const n = net::buffer_copy(
b.data(), net::const_buffer(
src.data(), src.size()));
SUITE_EXPECT(test, n == src.size());
SUITE_EXPECT(test,
beast::buffers_to_string(b.data()) == src);
SUITE_EXPECT(test,
beast::buffers_to_string(b.cdata()) == src);
}
// mutable to const sequence conversion
{
MutableDynamicBuffer b(b0);
b.commit(net::buffer_copy(
b.prepare(src.size()),
net::const_buffer(src.data(), src.size())));
auto mb = b.data();
auto cb = static_cast<
MutableDynamicBuffer const&>(b).data();
auto cbc = b.cdata();
SUITE_EXPECT(test,
beast::buffers_to_string(b.data()) == src);
SUITE_EXPECT(test,
beast::buffers_to_string(b.cdata()) == src);
beast::test_buffer_sequence(test, cb);
beast::test_buffer_sequence(test, cbc);
beast::test_buffer_sequence(test, mb);
{
decltype(mb) mb2(mb);
mb = mb2;
decltype(cb) cb2(cb);
cb = cb2;
decltype(cbc) cbc2(cbc);
cbc = cbc2;
}
{
decltype(cb) cb2(mb);
decltype(cbc) cbc2(mb);
cb2 = mb;
cbc2 = mb;
}
}
}
} // detail
/** Test an instance of a dynamic buffer or mutable dynamic buffer.
*/
template<class DynamicBuffer>
void
test_dynamic_buffer(
unit_test::suite& test,
DynamicBuffer const& b0)
{
using net::buffer_size;
BOOST_STATIC_ASSERT(
net::is_dynamic_buffer<DynamicBuffer>::value);
BOOST_STATIC_ASSERT(
net::is_const_buffer_sequence<typename
DynamicBuffer::const_buffers_type>::value);
BOOST_STATIC_ASSERT(
net::is_mutable_buffer_sequence<typename
DynamicBuffer::mutable_buffers_type>::value);
SUITE_EXPECT(test, b0.size() == 0);
SUITE_EXPECT(test, buffer_size(b0.data()) == 0);
// n == 0
{
DynamicBuffer b(b0);
b.commit(1);
SUITE_EXPECT(test, b.size() == 0);
SUITE_EXPECT(test, buffer_size(b.prepare(0)) == 0);
b.commit(0);
SUITE_EXPECT(test, b.size() == 0);
b.commit(1);
SUITE_EXPECT(test, b.size() == 0);
b.commit(b.max_size() + 1);
SUITE_EXPECT(test, b.size() == 0);
b.consume(0);
SUITE_EXPECT(test, b.size() == 0);
b.consume(1);
SUITE_EXPECT(test, b.size() == 0);
b.consume(b.max_size() + 1);
SUITE_EXPECT(test, b.size() == 0);
}
// max_size
{
DynamicBuffer b(b0);
if(SUITE_EXPECT(test,
b.max_size() + 1 > b.max_size()))
{
try
{
b.prepare(b.max_size() + 1);
test.fail("no exception", __FILE__, __LINE__);
}
catch(std::length_error const&)
{
test.pass();
}
catch(...)
{
test.fail("wrong exception", __FILE__, __LINE__);
}
}
}
char buf[13];
unsigned char k0 = 0;
string_view src(buf, sizeof(buf));
if(src.size() > b0.max_size())
src = {src.data(), b0.max_size()};
SUITE_EXPECT(test, b0.max_size() >= src.size());
SUITE_EXPECT(test, b0.size() == 0);
SUITE_EXPECT(test, buffer_size(b0.data()) == 0);
auto const make_new_src =
[&buf, &k0, &src]
{
auto k = k0++;
for(std::size_t i = 0; i < src.size(); ++i)
buf[i] = k++;
};
// readable / writable buffer sequence tests
{
make_new_src();
DynamicBuffer b(b0);
auto const& bc(b);
auto const mb = b.prepare(src.size());
SUITE_EXPECT(test, buffer_size(mb) == src.size());
beast::test_buffer_sequence(test, mb);
b.commit(net::buffer_copy(mb,
net::const_buffer(src.data(), src.size())));
SUITE_EXPECT(test,
buffer_size(bc.data()) == src.size());
beast::test_buffer_sequence(test, bc.data());
}
// h = in size
// i = prepare size
// j = commit size
// k = consume size
for(std::size_t h = 1; h <= src.size(); ++h)
{
string_view in(src.data(), h);
for(std::size_t i = 1; i <= in.size(); ++i) {
for(std::size_t j = 1; j <= i + 1; ++j) {
for(std::size_t k = 1; k <= in.size(); ++k) {
{
make_new_src();
DynamicBuffer b(b0);
auto const& bc(b);
net::const_buffer cb(in.data(), in.size());
while(cb.size() > 0)
{
auto const mb = b.prepare(
std::min<std::size_t>(i,
b.max_size() - b.size()));
auto const n = net::buffer_copy(mb,
net::const_buffer(cb.data(),
std::min<std::size_t>(j, cb.size())));
b.commit(n);
cb += n;
}
SUITE_EXPECT(test, b.size() == in.size());
SUITE_EXPECT(test,
buffer_size(bc.data()) == in.size());
SUITE_EXPECT(test, beast::buffers_to_string(
bc.data()) == in);
while(b.size() > 0)
b.consume(k);
SUITE_EXPECT(test, buffer_size(bc.data()) == 0);
}
} } }
}
// MutableDynamicBuffer refinement
detail::test_mutable_dynamic_buffer(test, b0,
is_mutable_dynamic_buffer<DynamicBuffer>{});
}
} // beast
} // boost

View File

@ -7,186 +7,17 @@
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
#define BOOST_BEAST_ALLOW_DEPRECATED
#endif
// Test that header file is self-contained.
#include <boost/beast/core/buffers_adapter.hpp>
#include "buffer_test.hpp"
#include <boost/beast/core/ostream.hpp>
#include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/streambuf.hpp>
#include <iterator>
namespace boost {
namespace beast {
class buffers_adapter_test : public unit_test::suite
{
public:
void testBuffersAdapter()
{
using net::buffer;
using net::buffer_size;
using net::const_buffer;
using net::mutable_buffer;
char buf[12];
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == sizeof(buf));
for(std::size_t i = 1; i < 4; ++i) {
for(std::size_t j = 1; j < 4; ++j) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
for(std::size_t t = 1; t < 4; ++ t) {
for(std::size_t u = 1; u < 4; ++ u) {
std::size_t k = sizeof(buf) - (i + j);
std::size_t z = sizeof(buf) - (x + y);
std::size_t v = sizeof(buf) - (t + u);
{
std::memset(buf, 0, sizeof(buf));
std::array<mutable_buffer, 3> bs{{
mutable_buffer{&buf[0], i},
mutable_buffer{&buf[i], j},
mutable_buffer{&buf[i+j], k}}};
buffers_adapter<decltype(bs)> ba(std::move(bs));
BEAST_EXPECT(ba.max_size() == sizeof(buf));
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
ba.commit(buffer_copy(d, buffer(s.data(), x)));
}
BEAST_EXPECT(ba.size() == x);
BEAST_EXPECT(ba.max_size() == sizeof(buf));
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
}
ba.commit(1);
BEAST_EXPECT(ba.size() == x + y);
BEAST_EXPECT(ba.max_size() == sizeof(buf));
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
{
auto d = ba.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = ba.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = ba.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
}
ba.commit(2);
BEAST_EXPECT(ba.size() == x + y + z);
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
BEAST_EXPECT(buffers_to_string(ba.data()) == s);
ba.consume(t);
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
BEAST_EXPECT(buffers_to_string(ba.data()) == s.substr(t, std::string::npos));
ba.consume(u);
BEAST_EXPECT(buffers_to_string(ba.data()) == s.substr(t + u, std::string::npos));
ba.consume(v);
BEAST_EXPECT(buffers_to_string(ba.data()) == "");
ba.consume(1);
{
auto d = ba.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
try
{
ba.prepare(1);
fail();
}
catch(...)
{
pass();
}
}
}}}}}}
}
void testCommit()
{
using net::buffer_size;
{
using sb_type = net::streambuf;
sb_type b;
buffers_adapter<
sb_type::mutable_buffers_type> ba(b.prepare(3));
BEAST_EXPECT(buffer_size(ba.prepare(3)) == 3);
ba.commit(2);
BEAST_EXPECT(buffer_size(ba.data()) == 2);
}
{
using sb_type = beast::multi_buffer;
sb_type b;
b.prepare(3);
buffers_adapter<
sb_type::mutable_buffers_type> ba(b.prepare(8));
BEAST_EXPECT(buffer_size(ba.prepare(8)) == 8);
ba.commit(2);
BEAST_EXPECT(buffer_size(ba.data()) == 2);
ba.consume(1);
ba.commit(6);
ba.consume(2);
BEAST_EXPECT(buffer_size(ba.data()) == 5);
ba.consume(5);
}
}
void
testIssue386()
{
using type = net::streambuf;
type buffer;
buffers_adapter<
type::mutable_buffers_type> ba{buffer.prepare(512)};
read_size(ba, 1024);
}
void run() override
{
testBuffersAdapter();
testCommit();
testIssue386();
}
};
BEAST_DEFINE_TESTSUITE(beast,core,buffers_adapter);
BOOST_STATIC_ASSERT(sizeof(buffers_adapter<net::mutable_buffer>) > 0);
} // beast
} // boost

View File

@ -0,0 +1,104 @@
//
// Copyright (c) 2016-2017 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
//
// Test that header file is self-contained.
#include <boost/beast/core/buffers_adaptor.hpp>
#include "buffer_test.hpp"
#include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/ostream.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/streambuf.hpp>
#include <iterator>
namespace boost {
namespace beast {
class buffers_adaptor_test : public unit_test::suite
{
public:
BOOST_STATIC_ASSERT(
is_mutable_dynamic_buffer<
buffers_adaptor<buffers_triple>>::value);
void
testDynamicBuffer()
{
char s[13];
buffers_triple tb(s, sizeof(s));
buffers_adaptor<buffers_triple> b(tb);
test_dynamic_buffer(*this, b);
}
void
testSpecial()
{
using net::buffer_size;
char s1[13];
buffers_triple tb1(s1, sizeof(s1));
BEAST_EXPECT(buffer_size(tb1) == sizeof(s1));
char s2[15];
buffers_triple tb2(s2, sizeof(s2));
BEAST_EXPECT(buffer_size(tb2) == sizeof(s2));
{
// construction
buffers_adaptor<buffers_triple> b1(tb1);
BEAST_EXPECT(b1.value() == tb1);
buffers_adaptor<buffers_triple> b2(tb2);
BEAST_EXPECT(b2.value() == tb2);
buffers_adaptor<buffers_triple> b3(b2);
BEAST_EXPECT(b3.value() == tb2);
char s3[15];
buffers_adaptor<buffers_triple> b4(
boost::in_place_init, s3, sizeof(s3));
BEAST_EXPECT(b4.value() == buffers_triple(s3, sizeof(s3)));
// assignment
b3 = b1;
BEAST_EXPECT(b3.value() == tb1);
}
}
void
testIssue386()
{
using type = net::streambuf;
type buffer;
buffers_adaptor<
type::mutable_buffers_type> ba{buffer.prepare(512)};
read_size(ba, 1024);
}
void
run() override
{
testDynamicBuffer();
testSpecial();
testIssue386();
#if 0
testBuffersAdapter();
testCommit();
#endif
}
};
BEAST_DEFINE_TESTSUITE(beast,core,buffers_adaptor);
} // beast
} // boost

View File

@ -10,7 +10,7 @@
// Test that header file is self-contained.
#include <boost/beast/_experimental/http/icy_stream.hpp>
#include <boost/beast/core/buffers_adapter.hpp>
#include <boost/beast/core/buffers_adaptor.hpp>
#include <boost/beast/core/buffers_to_string.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/_experimental/test/stream.hpp>
@ -45,7 +45,7 @@ public:
{
// sync
{
buffers_adapter<decltype(mbs)> ba(mbs);
buffers_adaptor<decltype(mbs)> ba(mbs);
std::memset(p.get(), 0, len);
icy_stream<test::stream> is{ioc};
@ -69,7 +69,7 @@ public:
}
// async
{
buffers_adapter<decltype(mbs)> ba(mbs);
buffers_adaptor<decltype(mbs)> ba(mbs);
std::memset(p.get(), 0, len);
icy_stream<test::stream> is{ioc};