mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +02:00
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:
@@ -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:
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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>::
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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 {
|
||||
|
@@ -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()
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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
|
||||
{
|
||||
|
Reference in New Issue
Block a user