Tune up static_buffer (API Change):

The static buffer is updated:

* reset() is no longer a member. Use b.consume(b.size()) instead.

* Simplified implementaton, uses asio instead of custom types

* Better stream performance: consuming the input makes room
  available in the output. This class is now suitable for
  HTTP reads.

These changes permit the static_buffer wrapper to adapt a user
memory buffer if desired, including a stack based array.
The static_buffer_n class may also be used for this purpose,
it comes with its own storage.
This commit is contained in:
Vinnie Falco
2017-06-07 17:41:27 -07:00
parent 0a5fec1e9d
commit 7952578e1d
9 changed files with 187 additions and 441 deletions

View File

@@ -2,6 +2,10 @@ Version 51
* Fix operator<< for header * Fix operator<< for header
API Changes:
* Tune up static_buffer
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Version 50 Version 50

View File

@@ -75,7 +75,7 @@ private:
return static_cast<std::size_t>(last - first); return static_cast<std::size_t>(last - first);
} }
char* p_; char* begin_;
char* in_; char* in_;
char* out_; char* out_;
char* last_; char* last_;
@@ -218,7 +218,7 @@ public:
std::size_t std::size_t
capacity() const capacity() const
{ {
return dist(p_, end_); return dist(begin_, end_);
} }
/// Get a list of buffers that represent the input sequence. /// Get a list of buffers that represent the input sequence.

View File

@@ -16,7 +16,7 @@ namespace beast {
/* Memory is laid out thusly: /* Memory is laid out thusly:
p_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_ begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
*/ */
namespace detail { namespace detail {
@@ -41,13 +41,13 @@ void
basic_flat_buffer<Allocator>:: basic_flat_buffer<Allocator>::
move_from(basic_flat_buffer& other) move_from(basic_flat_buffer& other)
{ {
p_ = other.p_; begin_ = other.begin_;
in_ = other.in_; in_ = other.in_;
out_ = other.out_; out_ = other.out_;
last_ = out_; last_ = out_;
end_ = other.end_; end_ = other.end_;
max_ = other.max_; max_ = other.max_;
other.p_ = nullptr; other.begin_ = nullptr;
other.in_ = nullptr; other.in_ = nullptr;
other.out_ = nullptr; other.out_ = nullptr;
other.last_ = nullptr; other.last_ = nullptr;
@@ -65,16 +65,16 @@ copy_from(basic_flat_buffer<
auto const n = other.size(); auto const n = other.size();
if(n > 0) if(n > 0)
{ {
p_ = alloc_traits::allocate( begin_ = alloc_traits::allocate(
this->member(), n); this->member(), n);
in_ = p_; in_ = begin_;
out_ = p_ + n; out_ = begin_ + n;
last_ = out_; last_ = out_;
end_ = out_; end_ = out_;
std::memcpy(in_, other.in_, n); std::memcpy(in_, other.in_, n);
return; return;
} }
p_ = nullptr; begin_ = nullptr;
in_ = nullptr; in_ = nullptr;
out_ = nullptr; out_ = nullptr;
last_ = nullptr; last_ = nullptr;
@@ -85,9 +85,9 @@ template<class Allocator>
basic_flat_buffer<Allocator>:: basic_flat_buffer<Allocator>::
~basic_flat_buffer() ~basic_flat_buffer()
{ {
if(p_) if(begin_)
alloc_traits::deallocate( alloc_traits::deallocate(
this->member(), p_, dist(p_, end_)); this->member(), begin_, dist(begin_, end_));
} }
template<class Allocator> template<class Allocator>
@@ -160,7 +160,7 @@ basic_flat_buffer(
template<class Allocator> template<class Allocator>
basic_flat_buffer<Allocator>:: basic_flat_buffer<Allocator>::
basic_flat_buffer(std::size_t limit) basic_flat_buffer(std::size_t limit)
: p_(nullptr) : begin_(nullptr)
, in_(nullptr) , in_(nullptr)
, out_(nullptr) , out_(nullptr)
, last_(nullptr) , last_(nullptr)
@@ -176,7 +176,7 @@ basic_flat_buffer(Allocator const& alloc,
std::size_t limit) std::size_t limit)
: detail::empty_base_optimization< : detail::empty_base_optimization<
allocator_type>(alloc) allocator_type>(alloc)
, p_(nullptr) , begin_(nullptr)
, in_(nullptr) , in_(nullptr)
, out_(nullptr) , out_(nullptr)
, last_(nullptr) , last_(nullptr)
@@ -204,8 +204,8 @@ prepare(std::size_t n) ->
// after a memmove, // after a memmove,
// existing capacity is sufficient // existing capacity is sufficient
if(len > 0) if(len > 0)
std::memmove(p_, in_, len); std::memmove(begin_, in_, len);
in_ = p_; in_ = begin_;
out_ = in_ + len; out_ = in_ + len;
last_ = out_ + n; last_ = out_ + n;
return {out_, n}; return {out_, n};
@@ -220,19 +220,19 @@ prepare(std::size_t n) ->
detail::next_pow2(len + n), min_size)); detail::next_pow2(len + n), min_size));
auto const p = alloc_traits::allocate( auto const p = alloc_traits::allocate(
this->member(), new_size); this->member(), new_size);
if(p_) if(begin_)
{ {
BOOST_ASSERT(p); BOOST_ASSERT(p);
BOOST_ASSERT(in_); BOOST_ASSERT(in_);
std::memcpy(p, in_, len); std::memcpy(p, in_, len);
alloc_traits::deallocate( alloc_traits::deallocate(
this->member(), p_, capacity()); this->member(), begin_, capacity());
} }
p_ = p; begin_ = p;
in_ = p_; in_ = begin_;
out_ = in_ + len; out_ = in_ + len;
last_ = out_ + n; last_ = out_ + n;
end_ = p_ + new_size; end_ = begin_ + new_size;
return {out_, n}; return {out_, n};
} }
@@ -243,8 +243,8 @@ consume(std::size_t n)
{ {
if(n >= dist(in_, out_)) if(n >= dist(in_, out_))
{ {
in_ = p_; in_ = begin_;
out_ = p_; out_ = begin_;
return; return;
} }
in_ += n; in_ += n;
@@ -266,19 +266,19 @@ reserve(std::size_t n)
auto const p = alloc_traits::allocate( auto const p = alloc_traits::allocate(
this->member(), new_size); this->member(), new_size);
auto const len = size(); auto const len = size();
if(p_) if(begin_)
{ {
BOOST_ASSERT(p_); BOOST_ASSERT(begin_);
BOOST_ASSERT(in_); BOOST_ASSERT(in_);
std::memcpy(p, in_, len); std::memcpy(p, in_, len);
alloc_traits::deallocate( alloc_traits::deallocate(
this->member(), p_, capacity()); this->member(), begin_, capacity());
} }
p_ = p; begin_ = p;
in_ = p_; in_ = begin_;
out_ = p_ + len; out_ = begin_ + len;
last_ = out_; last_ = out_;
end_ = p_ + new_size; end_ = begin_ + new_size;
} }
template<class Allocator> template<class Allocator>
@@ -292,7 +292,7 @@ shrink_to_fit()
char* p; char* p;
if(len > 0) if(len > 0)
{ {
BOOST_ASSERT(p_); BOOST_ASSERT(begin_);
BOOST_ASSERT(in_); BOOST_ASSERT(in_);
p = alloc_traits::allocate( p = alloc_traits::allocate(
this->member(), len); this->member(), len);
@@ -303,10 +303,10 @@ shrink_to_fit()
p = nullptr; p = nullptr;
} }
alloc_traits::deallocate( alloc_traits::deallocate(
this->member(), p_, dist(p_, end_)); this->member(), begin_, dist(begin_, end_));
p_ = p; begin_ = p;
in_ = p_; in_ = begin_;
out_ = p_ + len; out_ = begin_ + len;
last_ = out_; last_ = out_;
end_ = out_; end_ = out_;
} }

View File

@@ -18,288 +18,85 @@
namespace beast { namespace beast {
class static_buffer::const_buffers_type /* Memory is laid out thusly:
{
std::size_t n_;
std::uint8_t const* p_;
public: begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
using value_type = boost::asio::const_buffer; */
class const_iterator;
const_buffers_type() = delete;
const_buffers_type(
const_buffers_type const&) = default;
const_buffers_type& operator=(
const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class static_buffer;
const_buffers_type(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_buffer::const_buffers_type::const_iterator
{
std::size_t n_ = 0;
std::uint8_t const* p_ = nullptr;
public:
using value_type = boost::asio::const_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&& 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 p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class const_buffers_type;
const_iterator(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline inline
auto auto
static_buffer::const_buffers_type::begin() const -> static_buffer::
const_iterator data() const ->
{
return const_iterator{p_, n_};
}
inline
auto
static_buffer::const_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
class static_buffer::mutable_buffers_type
{
std::size_t n_;
std::uint8_t* p_;
public:
using value_type = boost::asio::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 static_buffer;
mutable_buffers_type(
std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_buffer::mutable_buffers_type::const_iterator
{
std::size_t n_ = 0;
std::uint8_t* p_ = nullptr;
public:
using value_type = boost::asio::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&& 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 p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class mutable_buffers_type;
const_iterator(std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline
auto
static_buffer::mutable_buffers_type::begin() const ->
const_iterator
{
return const_iterator{p_, n_};
}
inline
auto
static_buffer::mutable_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
inline
auto
static_buffer::data() const ->
const_buffers_type const_buffers_type
{ {
return const_buffers_type{in_, return {in_, dist(in_, out_)};
static_cast<std::size_t>(out_ - in_)};
} }
inline inline
auto auto
static_buffer::prepare(std::size_t n) -> static_buffer::
prepare(std::size_t n) ->
mutable_buffers_type mutable_buffers_type
{ {
if(n > static_cast<std::size_t>(end_ - out_)) return prepare_impl(n);
}
inline
void
static_buffer::
reset(void* p, std::size_t n)
{
reset_impl(p, n);
}
template<class>
void
static_buffer::
reset_impl(void* p, std::size_t n)
{
begin_ =
reinterpret_cast<char*>(p);
in_ = begin_;
out_ = begin_;
last_ = begin_;
end_ = begin_ + n;
}
template<class>
auto
static_buffer::
prepare_impl(std::size_t n) ->
mutable_buffers_type
{
if(n <= dist(out_, end_))
{
last_ = out_ + n;
return {out_, n};
}
auto const len = size();
if(n > capacity() - len)
BOOST_THROW_EXCEPTION(std::length_error{ BOOST_THROW_EXCEPTION(std::length_error{
"static_buffer overflow"}); "static_buffer overflow"});
if(len > 0)
std::memmove(begin_, in_, len);
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n; last_ = out_ + n;
return mutable_buffers_type{out_, n}; return {out_, n};
}
template<class>
void
static_buffer::
consume_impl(std::size_t n)
{
if(n >= size())
{
in_ = begin_;
out_ = in_;
return;
}
in_ += n;
} }
} // beast } // beast

View File

@@ -9,9 +9,7 @@
#define BEAST_STATIC_BUFFER_HPP #define BEAST_STATIC_BUFFER_HPP
#include <beast/config.hpp> #include <beast/config.hpp>
#include <boost/utility/base_from_member.hpp> #include <boost/asio/buffer.hpp>
#include <algorithm>
#include <array>
#include <cstring> #include <cstring>
namespace beast { namespace beast {
@@ -33,28 +31,18 @@ namespace beast {
*/ */
class static_buffer class static_buffer
{ {
#if BEAST_DOXYGEN char* begin_;
private: char* in_;
#else char* out_;
protected: char* last_;
#endif char* end_;
std::uint8_t* begin_;
std::uint8_t* in_;
std::uint8_t* out_;
std::uint8_t* last_;
std::uint8_t* end_;
public: public:
#if BEAST_DOXYGEN
/// The type used to represent the input sequence as a list of buffers. /// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined; using const_buffers_type = boost::asio::const_buffers_1;
/// The type used to represent the output sequence as a list of buffers. /// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type = implementation_defined; using mutable_buffers_type = boost::asio::mutable_buffers_1;
#else
class const_buffers_type;
class mutable_buffers_type;
static_buffer( static_buffer(
static_buffer const& other) noexcept = delete; static_buffer const& other) noexcept = delete;
@@ -62,7 +50,18 @@ public:
static_buffer& operator=( static_buffer& operator=(
static_buffer const&) noexcept = delete; static_buffer const&) noexcept = delete;
#endif /** Constructor.
This creates a dynamic buffer using the provided storage area.
@param p A pointer to valid storage of at least `n` bytes.
@param n The number of valid bytes pointed to by `p`.
*/
static_buffer(void* p, std::size_t n)
{
reset_impl(p, n);
}
/// Return the size of the input sequence. /// Return the size of the input sequence.
std::size_t std::size_t
@@ -75,14 +74,14 @@ public:
std::size_t std::size_t
max_size() const max_size() const
{ {
return end_ - begin_; return dist(begin_, end_);
} }
/// Return the maximum sum of input and output sizes that can be held without an allocation. /// Return the maximum sum of input and output sizes that can be held without an allocation.
std::size_t std::size_t
capacity() const capacity() const
{ {
return end_ - in_; return max_size();
} }
/** Get a list of buffers that represent the input sequence. /** Get a list of buffers that represent the input sequence.
@@ -118,28 +117,52 @@ public:
void void
consume(std::size_t n) consume(std::size_t n)
{ {
in_ += std::min<std::size_t>(n, out_ - in_); consume_impl(n);
} }
#if BEAST_DOXYGEN
private:
#else
protected: protected:
#endif /** Default constructor.
static_buffer(std::uint8_t* p, std::size_t n)
The buffer will be in an undefined state. It is necessary
for the derived class to call @ref reset in order to
initialize the object.
*/
static_buffer();
/** Reset the pointed-to buffer.
This function resets the internal state to the buffer provided.
All input and output sequences are invalidated. This function
allows the derived class to construct its members before
initializing the static buffer.
@param p A pointer to valid storage of at least `n` bytes.
@param n The number of valid bytes pointed to by `p`.
*/
void
reset(void* p, std::size_t n);
private:
static
inline
std::size_t
dist(char const* first, char const* last)
{ {
reset(p, n); return static_cast<std::size_t>(last - first);
} }
template<class = void>
void void
reset(std::uint8_t* p, std::size_t n) reset_impl(void* p, std::size_t n);
{
begin_ = p; template<class = void>
in_ = p; mutable_buffers_type
out_ = p; prepare_impl(std::size_t n);
last_ = p;
end_ = p + n; template<class = void>
} void
consume_impl(std::size_t n);
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -157,49 +180,22 @@ protected:
@see @ref static_buffer @see @ref static_buffer
*/ */
template<std::size_t N> template<std::size_t N>
class static_buffer_n class static_buffer_n : public static_buffer
: public static_buffer
#if ! BEAST_DOXYGEN
, private boost::base_from_member<
std::array<std::uint8_t, N>>
#endif
{ {
using member_type = boost::base_from_member< char buf_[N];
std::array<std::uint8_t, N>>;
public: public:
#if BEAST_DOXYGEN /// Copy constructor (disallowed).
private: static_buffer_n(static_buffer_n const&) = delete;
#endif
static_buffer_n( /// Copy assignment (disallowed).
static_buffer_n const&) = delete; static_buffer_n& operator=(static_buffer_n const&) = delete;
static_buffer_n& operator=(
static_buffer_n const&) = delete;
#if BEAST_DOXYGEN
public:
#endif
/// Construct a static buffer. /// Construct a static buffer.
static_buffer_n() static_buffer_n()
: static_buffer( : static_buffer(buf_, N)
member_type::member.data(),
member_type::member.size())
{ {
} }
/** Reset the static buffer.
@par Effects
The input sequence and output sequence are empty,
@ref max_size returns `N`.
*/
void
reset()
{
static_buffer::reset(
member_type::member.data(),
member_type::member.size());
}
}; };
} // beast } // beast

View File

@@ -440,7 +440,7 @@ operator()(error_code ec,
{ {
ping_data payload; ping_data payload;
detail::read(payload, d.fb.data()); detail::read(payload, d.fb.data());
d.fb.reset(); d.fb.consume(d.fb.size());
if(d.ws.ping_cb_) if(d.ws.ping_cb_)
d.ws.ping_cb_(false, payload); d.ws.ping_cb_(false, payload);
if(d.ws.wr_close_) if(d.ws.wr_close_)
@@ -469,7 +469,7 @@ operator()(error_code ec,
detail::read(payload, d.fb.data()); detail::read(payload, d.fb.data());
if(d.ws.ping_cb_) if(d.ws.ping_cb_)
d.ws.ping_cb_(true, payload); d.ws.ping_cb_(true, payload);
d.fb.reset(); d.fb.consume(d.fb.size());
d.state = do_read_fh; d.state = do_read_fh;
break; break;
} }
@@ -488,7 +488,7 @@ operator()(error_code ec,
if(cr.code == close_code::none) if(cr.code == close_code::none)
cr.code = close_code::normal; cr.code = close_code::normal;
cr.reason = ""; cr.reason = "";
d.fb.reset(); d.fb.consume(d.fb.size());
d.ws.template write_close< d.ws.template write_close<
static_buffer>(d.fb, cr); static_buffer>(d.fb, cr);
if(d.ws.wr_block_) if(d.ws.wr_block_)
@@ -535,7 +535,7 @@ operator()(error_code ec,
BOOST_ASSERT(d.ws.wr_block_ == &d); BOOST_ASSERT(d.ws.wr_block_ == &d);
d.ws.wr_block_ = nullptr; d.ws.wr_block_ = nullptr;
} }
d.fb.reset(); d.fb.consume(d.fb.size());
d.state = do_read_fh; d.state = do_read_fh;
break; break;
} }
@@ -550,7 +550,7 @@ operator()(error_code ec,
return; return;
case do_pong + 1: case do_pong + 1:
d.fb.reset(); d.fb.consume(d.fb.size());
d.state = do_read_fh; d.state = do_read_fh;
d.ws.wr_block_ = nullptr; d.ws.wr_block_ = nullptr;
break; break;
@@ -621,7 +621,7 @@ operator()(error_code ec,
d.state = do_fail + 4; d.state = do_fail + 4;
break; break;
} }
d.fb.reset(); d.fb.consume(d.fb.size());
d.ws.template write_close< d.ws.template write_close<
static_buffer>(d.fb, code); static_buffer>(d.fb, code);
if(d.ws.wr_block_) if(d.ws.wr_block_)
@@ -793,7 +793,7 @@ read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec)
{ {
ping_data payload; ping_data payload;
detail::read(payload, fb.data()); detail::read(payload, fb.data());
fb.reset(); fb.consume(fb.size());
if(ping_cb_) if(ping_cb_)
ping_cb_(false, payload); ping_cb_(false, payload);
write_ping<static_buffer>( write_ping<static_buffer>(
@@ -823,7 +823,7 @@ read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec)
if(cr.code == close_code::none) if(cr.code == close_code::none)
cr.code = close_code::normal; cr.code = close_code::normal;
cr.reason = ""; cr.reason = "";
fb.reset(); fb.consume(fb.size());
wr_close_ = true; wr_close_ = true;
write_close<static_buffer>(fb, cr); write_close<static_buffer>(fb, cr);
boost::asio::write(stream_, fb.data(), ec); boost::asio::write(stream_, fb.data(), ec);

View File

@@ -279,7 +279,7 @@ operator()(error_code ec,
case do_nomask_frag + 2: case do_nomask_frag + 2:
d.cb.consume( d.cb.consume(
bytes_transferred - d.fh_buf.size()); bytes_transferred - d.fh_buf.size());
d.fh_buf.reset(); d.fh_buf.consume(d.fh_buf.size());
d.fh.op = opcode::cont; d.fh.op = opcode::cont;
if(d.ws.wr_block_ == &d) if(d.ws.wr_block_ == &d)
d.ws.wr_block_ = nullptr; d.ws.wr_block_ = nullptr;
@@ -384,7 +384,7 @@ operator()(error_code ec,
case do_mask_frag + 2: case do_mask_frag + 2:
d.cb.consume( d.cb.consume(
bytes_transferred - d.fh_buf.size()); bytes_transferred - d.fh_buf.size());
d.fh_buf.reset(); d.fh_buf.consume(d.fh_buf.size());
d.fh.op = opcode::cont; d.fh.op = opcode::cont;
BOOST_ASSERT(d.ws.wr_block_ == &d); BOOST_ASSERT(d.ws.wr_block_ == &d);
d.ws.wr_block_ = nullptr; d.ws.wr_block_ = nullptr;

View File

@@ -130,7 +130,7 @@ public:
} }
try try
{ {
ba.prepare(1); ba.prepare(ba.capacity() - ba.size() + 1);
fail(); fail();
} }
catch(...) catch(...)
@@ -141,59 +141,9 @@ public:
}}}}}} }}}}}}
} }
void testIterators() void
testReadSizeHelper()
{ {
static_buffer_n<2> ba;
{
auto mb = ba.prepare(2);
std::size_t n;
n = 0;
for(auto it = mb.begin();
it != mb.end(); it++)
++n;
BEAST_EXPECT(n == 1);
mb = ba.prepare(2);
n = 0;
for(auto it = mb.begin();
it != mb.end(); ++it)
++n;
BEAST_EXPECT(n == 1);
mb = ba.prepare(2);
n = 0;
for(auto it = mb.end();
it != mb.begin(); it--)
++n;
BEAST_EXPECT(n == 1);
mb = ba.prepare(2);
n = 0;
for(auto it = mb.end();
it != mb.begin(); --it)
++n;
BEAST_EXPECT(n == 1);
}
ba.prepare(2);
ba.commit(1);
std::size_t n;
n = 0;
for(auto it = ba.data().begin();
it != ba.data().end(); it++)
++n;
BEAST_EXPECT(n == 1);
n = 0;
for(auto it = ba.data().begin();
it != ba.data().end(); ++it)
++n;
BEAST_EXPECT(n == 1);
n = 0;
for(auto it = ba.data().end();
it != ba.data().begin(); it--)
++n;
BEAST_EXPECT(n == 1);
n = 0;
for(auto it = ba.data().end();
it != ba.data().begin(); --it)
++n;
BEAST_EXPECT(n == 1);
} }
void run() override void run() override
@@ -201,7 +151,6 @@ public:
test::check_read_size_helper<static_buffer_n<32>>(); test::check_read_size_helper<static_buffer_n<32>>();
testStaticBuffer(); testStaticBuffer();
testIterators();
} }
}; };

View File

@@ -1839,9 +1839,9 @@ public:
BEAST_EXPECT(n < limit); BEAST_EXPECT(n < limit);
} }
void run() override void
run() override
{ {
testHandshake();
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
stream<socket_type>, boost::asio::io_service&>::value); stream<socket_type>, boost::asio::io_service&>::value);