Tidy up multi_buffer:

* Improved tests
* Refactor some declaration material
* basic_multi_buffer::clear is public

and

* Fix flat_buffer::reserve
* flat_buffer::clear is public
This commit is contained in:
Vinnie Falco
2018-12-15 18:48:32 -08:00
parent 74293fb8a5
commit 594a92e515
10 changed files with 386 additions and 389 deletions

View File

@@ -16,6 +16,7 @@ Version 200
* Fix ostream prepare calculation for low limits
* Tidy up flat_static_buffer tests
* Add more tests for dynamic buffers
* Tidy up multi_buffer
API Changes:

View File

@@ -83,7 +83,7 @@ class basic_flat_buffer
static
std::size_t
dist(char const* first, char const* last)
dist(char const* first, char const* last) noexcept
{
return static_cast<std::size_t>(last - first);
}
@@ -370,6 +370,23 @@ public:
void
shrink_to_fit();
/** Deallocate the internal buffer and reduce capacity to zero.
This function deallocates the dynamically allocated
internal buffer, and reduces the capacity to zero without
affecting the maximum size. The readable and writable
bytes will be empty after the object is cleared.
Buffer sequences previously obtained using @ref data or
@ref prepare become invalid.
@par Exception Safety
No-throw guarantee.
*/
void
clear() noexcept;
/// Exchange two dynamic buffers
template<class Alloc>
friend
@@ -506,7 +523,6 @@ private:
void swap(basic_flat_buffer&, std::true_type);
void swap(basic_flat_buffer&, std::false_type);
char* alloc(std::size_t n);
void clear();
};
/// A flat buffer which uses the default allocator.

View File

@@ -254,7 +254,7 @@ reserve(std::size_t n)
{
if(max_ < n)
max_ = n;
if(capacity() < n)
if(n > capacity())
prepare(n - size());
}
@@ -287,6 +287,20 @@ shrink_to_fit()
end_ = out_;
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
clear() noexcept
{
alloc_traits::deallocate(
this->get(), begin_, size());
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
}
//------------------------------------------------------------------------------
template<class Allocator>
@@ -310,7 +324,11 @@ prepare(std::size_t n) ->
// after a memmove,
// existing capacity is sufficient
if(len > 0)
{
BOOST_ASSERT(begin_);
BOOST_ASSERT(in_);
std::memmove(begin_, in_, len);
}
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
@@ -375,7 +393,11 @@ copy_from(
in_ = begin_;
out_ = begin_ + n;
last_ = begin_ + n;
std::memcpy(begin_, other.begin_, n);
if(begin_)
{
BOOST_ASSERT(other.begin_);
std::memcpy(begin_, other.begin_, n);
}
}
template<class Allocator>
@@ -495,20 +517,6 @@ alloc(std::size_t n)
return alloc_traits::allocate(this->get(), n);
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
clear()
{
alloc_traits::deallocate(
this->get(), begin_, size());
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
}
} // beast
} // boost

View File

@@ -148,10 +148,11 @@ class basic_multi_buffer<Allocator>::readable_bytes
}
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;
@@ -228,9 +229,7 @@ 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;
const_iterator(
@@ -314,7 +313,7 @@ class basic_multi_buffer<Allocator>::mutable_buffers_type
}
public:
using value_type = mutable_buffer;
using value_type = net::mutable_buffer;
class const_iterator;
@@ -335,8 +334,8 @@ class basic_multi_buffer<Allocator>::mutable_buffers_type::const_iterator
typename list_type::const_iterator it_;
public:
using value_type =
typename mutable_buffers_type::value_type;
using value_type = typename
mutable_buffers_type::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@@ -344,9 +343,7 @@ 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;
const_iterator(
@@ -468,6 +465,23 @@ basic_multi_buffer<Allocator>::
delete_list();
}
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer() noexcept(default_nothrow)
: max_(alloc_traits::max_size(this->get()))
, out_(list_.end())
{
}
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
std::size_t limit) noexcept(default_nothrow)
: max_(limit)
, out_(list_.end())
{
}
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
@@ -672,6 +686,8 @@ void
basic_multi_buffer<Allocator>::
reserve(std::size_t n)
{
// VFALCO The amount needs to be adjusted for
// the sizeof(element) plus padding
if(n > alloc_traits::max_size(this->get()))
BOOST_THROW_EXCEPTION(std::length_error(
"A basic_multi_buffer exceeded the allocator's maximum size"));
@@ -683,16 +699,17 @@ reserve(std::size_t n)
total += out_->size() - out_pos_;
if(n <= total)
return;
auto it = out_;
while(++it != list_.end())
for(auto it = out_;;)
{
if(++it == list_.end())
break;
total += it->size();
if(n <= total)
return;
}
}
BOOST_ASSERT(n > total);
(void)prepare(n - total);
(void)prepare(n - size());
}
template<class Allocator>
@@ -717,15 +734,29 @@ shrink_to_fit() noexcept
}
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
clear() noexcept
{
delete_list();
list_.clear();
out_ = list_.end();
in_size_ = 0;
in_pos_ = 0;
out_pos_ = 0;
out_end_ = 0;
}
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
prepare(size_type n) ->
mutable_buffers_type
{
if(in_size_ + n > max_)
if(in_size_ > max_ || n > (max_ - in_size_))
BOOST_THROW_EXCEPTION(std::length_error{
"A basic_multi_buffer exceeded its maximum size"});
"basic_multi_buffer too long"});
list_type reuse;
std::size_t total = in_size_;
// put all empty buffers on reuse list
@@ -943,22 +974,6 @@ copy_from(basic_multi_buffer<OtherAlloc> const& other)
prepare(other.size()), other.data()));
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
move_assign(basic_multi_buffer& other, std::false_type)
{
if(this->get() != other.get())
{
copy_from(other);
other.clear();
}
else
{
move_assign(other, std::true_type{});
}
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
@@ -983,6 +998,22 @@ move_assign(basic_multi_buffer& other, std::true_type) noexcept
other.out_end_ = 0;
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
move_assign(basic_multi_buffer& other, std::false_type)
{
if(this->get() != other.get())
{
copy_from(other);
other.clear();
}
else
{
move_assign(other, std::true_type{});
}
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
@@ -1093,20 +1124,6 @@ alloc(std::size_t n)
return alloc_traits::allocate(this->get(), n);
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::
clear() noexcept
{
delete_list();
list_.clear();
out_ = list_.end();
in_size_ = 0;
in_pos_ = 0;
out_pos_ = 0;
out_end_ = 0;
}
template<class Allocator>
void
basic_multi_buffer<Allocator>::

View File

@@ -40,7 +40,7 @@ namespace beast {
desired size. The behavior and implementation of this
container is most similar to `std::deque`.
Objects of this type meet the requirements of @b DynamicBuffer
Objects of this type meet the requirements of <em>DynamicBuffer</em>
and have the following additional properties:
@li A mutable buffer sequence representing the readable
@@ -90,8 +90,6 @@ class basic_multi_buffer
using const_iter = typename list_type::const_iterator;
using size_type = typename alloc_traits::size_type;
using const_buffer = net::const_buffer;
using mutable_buffer = net::mutable_buffer;
using pocma = typename
alloc_traits::propagate_on_container_move_assignment;
@@ -128,11 +126,7 @@ public:
@ref max_size will return the largest value which may
be passed to the allocator's `allocate` function.
*/
basic_multi_buffer() noexcept(default_nothrow)
: max_(alloc_traits::max_size(this->get()))
, out_(list_.end())
{
}
basic_multi_buffer() noexcept(default_nothrow);
/** Constructor
@@ -143,11 +137,7 @@ public:
*/
explicit
basic_multi_buffer(
std::size_t limit) noexcept(default_nothrow)
: max_(limit)
, out_(list_.end())
{
}
std::size_t limit) noexcept(default_nothrow);
/** Constructor
@@ -392,6 +382,23 @@ public:
void
shrink_to_fit() noexcept;
/** Deallocate all buffers and reduce capacity to zero.
This function deallocates all dynamically allocated
buffers, and reduces the capacity to zero without
affecting the maximum size. The readable and writable
bytes will be empty after the object is cleared.
Buffer sequences previously obtained using @ref data or
@ref prepare become invalid.
@par Exception Safety
No-throw guarantee.
*/
void
clear() noexcept;
/// Exchange two dynamic buffers
template<class Alloc>
friend
@@ -536,7 +543,6 @@ private:
void swap(basic_multi_buffer&, std::false_type) noexcept;
void delete_list() noexcept;
char* alloc(std::size_t n);
void clear() noexcept;
void debug_check() const;
};

View File

@@ -103,88 +103,16 @@ public:
}
};
//------------------------------------------------------------------------------
namespace test {
template<class DynamicBuffer>
void
write_buffer(DynamicBuffer& b, string_view s)
{
b.commit(net::buffer_copy(
b.prepare(s.size()), net::buffer(
s.data(), s.size())));
}
template<class ConstBufferSequence>
typename std::enable_if<
net::is_const_buffer_sequence<ConstBufferSequence>::value,
std::size_t>::type
buffer_count(ConstBufferSequence const& buffers)
std::size_t
buffers_length(
ConstBufferSequence const& buffers)
{
return std::distance(buffers.begin(), buffers.end());
return std::distance(
net::buffer_sequence_begin(buffers),
net::buffer_sequence_end(buffers));
}
template<class ConstBufferSequence>
typename std::enable_if<
net::is_const_buffer_sequence<ConstBufferSequence>::value,
std::size_t>::type
size_pre(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.begin(); it != buffers.end(); ++it)
{
typename ConstBufferSequence::const_iterator it0(std::move(it));
typename ConstBufferSequence::const_iterator it1(it0);
typename ConstBufferSequence::const_iterator it2;
it2 = it1;
n += net::buffer_size(*it2);
it = std::move(it2);
}
return n;
}
template<class ConstBufferSequence>
typename std::enable_if<
net::is_const_buffer_sequence<ConstBufferSequence>::value,
std::size_t>::type
size_post(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.begin(); it != buffers.end(); it++)
n += net::buffer_size(*it);
return n;
}
template<class ConstBufferSequence>
typename std::enable_if<
net::is_const_buffer_sequence<ConstBufferSequence>::value,
std::size_t>::type
size_rev_pre(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.end(); it != buffers.begin();)
n += net::buffer_size(*--it);
return n;
}
template<class ConstBufferSequence>
typename std::enable_if<
net::is_const_buffer_sequence<ConstBufferSequence>::value,
std::size_t>::type
size_rev_post(ConstBufferSequence const& buffers)
{
std::size_t n = 0;
for(auto it = buffers.end(); it != buffers.begin();)
{
it--;
n += net::buffer_size(*it);
}
return n;
}
} // test
//------------------------------------------------------------------------------
namespace detail {

View File

@@ -28,17 +28,6 @@ namespace beast {
class buffers_cat_test : public unit_test::suite
{
public:
template<class ConstBufferSequence>
static
std::size_t
buffers_length(
ConstBufferSequence const& buffers)
{
return std::distance(
net::buffer_sequence_begin(buffers),
net::buffer_sequence_end(buffers));
}
void
testDefaultIterators()
{

View File

@@ -69,7 +69,6 @@ public:
// in-place init
{
using namespace test;
buffers_suffix<buffers_cat_view<
net::const_buffer,
net::const_buffer>> cb(
@@ -106,8 +105,9 @@ public:
bool
eq(Buffers1 const& lhs, Buffers2 const& rhs)
{
using namespace test;
return buffers_to_string(lhs) == buffers_to_string(rhs);
return
buffers_to_string(lhs) ==
buffers_to_string(rhs);
}
void

View File

@@ -32,20 +32,8 @@ class multi_buffer_test : public beast::unit_test::suite
{
public:
BOOST_STATIC_ASSERT(
net::is_dynamic_buffer<
multi_buffer>::value);
BOOST_STATIC_ASSERT(
net::is_const_buffer_sequence<
multi_buffer::const_buffers_type>::value);
BOOST_STATIC_ASSERT(
net::is_mutable_buffer_sequence<
multi_buffer::mutable_data_type>::value);
BOOST_STATIC_ASSERT(
net::is_mutable_buffer_sequence<
multi_buffer::mutable_buffers_type>::value);
BOOST_STATIC_ASSERT(std::is_convertible<
multi_buffer::mutable_data_type,
multi_buffer::const_buffers_type>::value);
is_mutable_dynamic_buffer<multi_buffer>::value);
#if ! BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, < 50000) && \
! BOOST_WORKAROUND(BOOST_MSVC, < 1910)
BOOST_STATIC_ASSERT(std::is_trivially_copyable<
@@ -57,214 +45,19 @@ public:
template<class Alloc1, class Alloc2>
static
bool
eq(basic_multi_buffer<Alloc1> const& mb1,
eq( basic_multi_buffer<Alloc1> const& mb1,
basic_multi_buffer<Alloc2> const& mb2)
{
return buffers_to_string(mb1.data()) ==
buffers_to_string(mb2.data());
}
template<class ConstBufferSequence>
void
expect_size(std::size_t n, ConstBufferSequence const& buffers)
testDynamicBuffer()
{
BEAST_EXPECT(test::size_pre(buffers) == n);
BEAST_EXPECT(test::size_post(buffers) == n);
BEAST_EXPECT(test::size_rev_pre(buffers) == n);
BEAST_EXPECT(test::size_rev_post(buffers) == n);
}
template<class U, class V>
static
void
self_assign(U& u, V&& v)
{
u = std::forward<V>(v);
}
template<class DynamicBuffer>
void
testMutableData()
{
DynamicBuffer b;
DynamicBuffer const& cb = b;
ostream(b) << "Hello";
BOOST_STATIC_ASSERT(
net::is_const_buffer_sequence<
decltype(cb.data())>::value &&
! net::is_mutable_buffer_sequence<
decltype(cb.data())>::value);
BOOST_STATIC_ASSERT(
net::is_const_buffer_sequence<
decltype(cb.cdata())>::value &&
! net::is_mutable_buffer_sequence<
decltype(cb.cdata())>::value);
BOOST_STATIC_ASSERT(
net::is_mutable_buffer_sequence<
decltype(b.data())>::value);
std::for_each(
net::buffers_iterator<decltype(b.data())>::begin(b.data()),
net::buffers_iterator<decltype(b.data())>::end(b.data()),
[](char& c)
{
c = static_cast<char>(std::toupper(c));
});
BEAST_EXPECT(buffers_to_string(b.data()) == "HELLO");
BEAST_EXPECT(buffers_to_string(b.cdata()) == "HELLO");
}
void
testMatrix1()
{
using namespace test;
using net::buffer;
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == 12);
for(std::size_t i = 1; i < 12; ++i) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
std::size_t z = s.size() - (x + y);
{
multi_buffer b;
b.commit(buffer_copy(b.prepare(x), buffer(s.data(), x)));
b.commit(buffer_copy(b.prepare(y), buffer(s.data()+x, y)));
b.commit(buffer_copy(b.prepare(z), buffer(s.data()+x+y, z)));
BEAST_EXPECT(buffers_to_string(b.data()) == s);
{
multi_buffer mb2{b};
BEAST_EXPECT(eq(b, mb2));
}
{
multi_buffer mb2;
mb2 = b;
BEAST_EXPECT(eq(b, mb2));
}
{
multi_buffer mb2{std::move(b)};
BEAST_EXPECT(buffers_to_string(mb2.data()) == s);
expect_size(0, b.data());
b = std::move(mb2);
BEAST_EXPECT(buffers_to_string(b.data()) == s);
expect_size(0, mb2.data());
}
self_assign(b, b);
BEAST_EXPECT(buffers_to_string(b.data()) == s);
self_assign(b, std::move(b));
BEAST_EXPECT(buffers_to_string(b.data()) == s);
}
}}}
}
void
testMatrix2()
{
using namespace test;
using net::buffer;
using net::buffer_size;
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == 12);
for(std::size_t i = 1; i < 12; ++i) {
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 z = s.size() - (x + y);
std::size_t v = s.size() - (t + u);
{
multi_buffer b;
{
auto d = b.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = b.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = b.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
b.commit(buffer_copy(d, buffer(s.data(), x)));
}
BEAST_EXPECT(b.size() == x);
BEAST_EXPECT(buffer_size(b.data()) == b.size());
{
auto d = b.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = b.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = b.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
b.commit(buffer_copy(d, buffer(s.data()+x, y)));
}
b.commit(1);
BEAST_EXPECT(b.size() == x + y);
BEAST_EXPECT(buffer_size(b.data()) == b.size());
{
auto d = b.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = b.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = b.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
b.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
}
b.commit(2);
BEAST_EXPECT(b.size() == x + y + z);
BEAST_EXPECT(buffer_size(b.data()) == b.size());
BEAST_EXPECT(buffers_to_string(b.data()) == s);
b.consume(t);
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
BEAST_EXPECT(buffers_to_string(b.data()) == s.substr(t, std::string::npos));
b.consume(u);
BEAST_EXPECT(buffers_to_string(b.data()) == s.substr(t + u, std::string::npos));
b.consume(v);
BEAST_EXPECT(buffers_to_string(b.data()) == "");
b.consume(1);
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
}
}}}}}
}
void
testIterators()
{
using net::buffer_size;
multi_buffer b;
b.prepare(1);
b.commit(1);
b.prepare(2);
b.commit(2);
expect_size(3, b.data());
b.prepare(1);
expect_size(3, b.prepare(3));
b.commit(2);
multi_buffer b(30);
BEAST_EXPECT(b.max_size() == 30);
test_dynamic_buffer(*this, b);
}
void
@@ -297,6 +90,14 @@ public:
BEAST_EXPECT(b.get_allocator() == a1);
BEAST_EXPECT(b.get_allocator() != unequal_t{});
}
{
unequal_t a1;
basic_multi_buffer<unequal_t> b{500, a1};
BEAST_EXPECT(b.capacity() == 0);
BEAST_EXPECT(b.max_size() == 500);
BEAST_EXPECT(b.get_allocator() == a1);
BEAST_EXPECT(b.get_allocator() != unequal_t{});
}
}
// move construction
@@ -384,6 +185,18 @@ public:
BEAST_EXPECT(b1.capacity() == 0);
BEAST_EXPECT(buffers_to_string(b2.data()) == "Hello");
}
{
using na_t = test::test_allocator<char,
false, true, false, true, true>;
basic_multi_buffer<na_t> b1;
ostream(b1) << "Hello";
basic_multi_buffer<na_t> b2;
b2 = std::move(b1);
BEAST_EXPECT(b1.get_allocator() != b2.get_allocator());
BEAST_EXPECT(b1.size() == 0);
BEAST_EXPECT(b1.capacity() == 0);
BEAST_EXPECT(buffers_to_string(b2.data()) == "Hello");
}
{
// propagate_on_container_move_assignment : true
using pocma_t = test::test_allocator<char,
@@ -451,6 +264,34 @@ public:
BEAST_EXPECT(b.max_size() == 32);
}
// allocator max_size
{
basic_multi_buffer<equal_t> b;
auto a = b.get_allocator();
BOOST_STATIC_ASSERT(
! std::is_const<decltype(a)>::value);
a->max_size = 30;
try
{
b.prepare(1000);
fail("", __FILE__, __LINE__);
}
catch(std::length_error const&)
{
pass();
}
try
{
b.reserve(1000);
fail("", __FILE__, __LINE__);
}
catch(std::length_error const&)
{
pass();
}
}
// prepare
{
{
@@ -527,6 +368,23 @@ public:
// commit
{
{
multi_buffer b;
b.prepare(16);
b.commit(16);
auto const n =
b.capacity() - b.size();
b.prepare(n);
b.commit(n);
auto const size =
b.size();
auto const capacity =
b.capacity();
b.commit(1);
BEAST_EXPECT(b.size() == size);
BEAST_EXPECT(b.capacity() == capacity);
}
multi_buffer b;
b.prepare(1000);
BEAST_EXPECT(b.capacity() >= 1000);
@@ -589,6 +447,21 @@ public:
b.commit(20);
b.reserve(50);
BEAST_EXPECT(b.capacity() >= 50);
BEAST_EXPECT(b.size() > 1);
auto capacity = b.capacity();
b.reserve(b.size() - 1);
BEAST_EXPECT(b.capacity() == capacity);
b.reserve(b.capacity() + 1);
BEAST_EXPECT(b.capacity() > capacity);
capacity = b.capacity();
BEAST_EXPECT(buffers_length(
b.prepare(b.capacity() + 200)) > 1);
BEAST_EXPECT(b.capacity() > capacity);
b.reserve(b.capacity() + 2);
BEAST_EXPECT(b.capacity() > capacity);
capacity = b.capacity();
b.reserve(b.capacity());
BEAST_EXPECT(b.capacity() == capacity);
}
// shrink to fit
@@ -619,6 +492,23 @@ public:
}
}
// clear
{
multi_buffer b;
b.prepare(50);
BEAST_EXPECT(b.capacity() >= 50);
b.clear();
BEAST_EXPECT(b.size() == 0);
BEAST_EXPECT(b.capacity() == 0);
b.prepare(80);
b.commit(30);
BEAST_EXPECT(b.size() == 30);
BEAST_EXPECT(b.capacity() >= 80);
b.clear();
BEAST_EXPECT(b.size() == 0);
BEAST_EXPECT(b.capacity() == 0);
}
// swap
{
{
@@ -683,14 +573,158 @@ public:
}
}
void
testMatrix1()
{
using net::buffer_size;
string_view s = "Hello, world";
BEAST_EXPECT(s.size() == 12);
for(std::size_t i = 1; i < 12; ++i) {
for(std::size_t x = 1; x < 4; ++x) {
for(std::size_t y = 1; y < 4; ++y) {
std::size_t z = s.size() - (x + y);
{
multi_buffer b;
b.commit(net::buffer_copy(
b.prepare(x), net::buffer(s.data(), x)));
b.commit(net::buffer_copy(
b.prepare(y), net::buffer(s.data()+x, y)));
b.commit(net::buffer_copy(
b.prepare(z), net::buffer(s.data()+x+y, z)));
BEAST_EXPECT(buffers_to_string(b.data()) == s);
{
multi_buffer mb2{b};
BEAST_EXPECT(eq(b, mb2));
}
{
multi_buffer mb2;
mb2 = b;
BEAST_EXPECT(eq(b, mb2));
}
{
multi_buffer mb2{std::move(b)};
BEAST_EXPECT(buffers_to_string(mb2.data()) == s);
BEAST_EXPECT(b.size() == 0);
BEAST_EXPECT(buffer_size(b.data()) == 0);
b = std::move(mb2);
BEAST_EXPECT(buffers_to_string(b.data()) == s);
BEAST_EXPECT(mb2.size() == 0);
BEAST_EXPECT(buffer_size(mb2.data()) == 0);
}
}
}}}
}
void
testMatrix2()
{
using namespace test;
using net::buffer;
using net::buffer_size;
std::string const s = "Hello, world";
BEAST_EXPECT(s.size() == 12);
for(std::size_t i = 1; i < 12; ++i) {
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 z = s.size() - (x + y);
std::size_t v = s.size() - (t + u);
{
multi_buffer b;
{
auto d = b.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = b.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = b.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
b.commit(buffer_copy(d, buffer(s.data(), x)));
}
BEAST_EXPECT(b.size() == x);
BEAST_EXPECT(buffer_size(b.data()) == b.size());
{
auto d = b.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = b.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
}
{
auto d = b.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
b.commit(buffer_copy(d, buffer(s.data()+x, y)));
}
b.commit(1);
BEAST_EXPECT(b.size() == x + y);
BEAST_EXPECT(buffer_size(b.data()) == b.size());
{
auto d = b.prepare(x);
BEAST_EXPECT(buffer_size(d) == x);
}
{
auto d = b.prepare(y);
BEAST_EXPECT(buffer_size(d) == y);
}
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
{
auto d = b.prepare(z);
BEAST_EXPECT(buffer_size(d) == z);
b.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
}
b.commit(2);
BEAST_EXPECT(b.size() == x + y + z);
BEAST_EXPECT(buffer_size(b.data()) == b.size());
BEAST_EXPECT(buffers_to_string(b.data()) == s);
b.consume(t);
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
BEAST_EXPECT(buffers_to_string(b.data()) ==
s.substr(t, std::string::npos));
b.consume(u);
BEAST_EXPECT(buffers_to_string(b.data()) ==
s.substr(t + u, std::string::npos));
b.consume(v);
BEAST_EXPECT(buffers_to_string(b.data()).empty());
b.consume(1);
{
auto d = b.prepare(0);
BEAST_EXPECT(buffer_size(d) == 0);
}
}
}}}}}
}
void
run() override
{
testDynamicBuffer();
testMembers();
testMatrix1();
testMatrix2();
#if 0
testIterators();
testMembers();
testMutableData<multi_buffer>();
#endif
}
};

View File

@@ -87,7 +87,6 @@ public:
void
testStaticBuffer()
{
using namespace test;
using net::buffer;
using net::buffer_size;
char buf[12];
@@ -195,7 +194,6 @@ public:
void
testBuffer()
{
using namespace test;
string_view const s = "Hello, world!";
// static_buffer_base
@@ -234,9 +232,9 @@ public:
// cause memmove
{
static_buffer<10> b;
write_buffer(b, "12345");
ostream(b) << "12345";
b.consume(3);
write_buffer(b, "67890123");
ostream(b) << "67890123";
BEAST_EXPECT(buffers_to_string(b.data()) == "4567890123");
try
{