From 594a92e51551796cd9b42cd66d3c18e690bedcfd Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 15 Dec 2018 18:48:32 -0800 Subject: [PATCH] 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 --- CHANGELOG.md | 1 + include/boost/beast/core/flat_buffer.hpp | 20 +- include/boost/beast/core/impl/flat_buffer.hpp | 40 +- .../boost/beast/core/impl/multi_buffer.hpp | 109 ++-- include/boost/beast/core/multi_buffer.hpp | 34 +- test/beast/core/buffer_test.hpp | 84 +--- test/beast/core/buffers_cat.cpp | 11 - test/beast/core/buffers_suffix.cpp | 6 +- test/beast/core/multi_buffer.cpp | 464 ++++++++++-------- test/beast/core/static_buffer.cpp | 6 +- 10 files changed, 386 insertions(+), 389 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad16645f..8362765d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/include/boost/beast/core/flat_buffer.hpp b/include/boost/beast/core/flat_buffer.hpp index 1227f97e..aad02e13 100644 --- a/include/boost/beast/core/flat_buffer.hpp +++ b/include/boost/beast/core/flat_buffer.hpp @@ -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(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 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. diff --git a/include/boost/beast/core/impl/flat_buffer.hpp b/include/boost/beast/core/impl/flat_buffer.hpp index c1a0f401..cd64fc7f 100644 --- a/include/boost/beast/core/impl/flat_buffer.hpp +++ b/include/boost/beast/core/impl/flat_buffer.hpp @@ -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 +void +basic_flat_buffer:: +clear() noexcept +{ + alloc_traits::deallocate( + this->get(), begin_, size()); + begin_ = nullptr; + in_ = nullptr; + out_ = nullptr; + last_ = nullptr; + end_ = nullptr; +} + //------------------------------------------------------------------------------ template @@ -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 @@ -495,20 +517,6 @@ alloc(std::size_t n) return alloc_traits::allocate(this->get(), n); } -template -void -basic_flat_buffer:: -clear() -{ - alloc_traits::deallocate( - this->get(), begin_, size()); - begin_ = nullptr; - in_ = nullptr; - out_ = nullptr; - last_ = nullptr; - end_ = nullptr; -} - } // beast } // boost diff --git a/include/boost/beast/core/impl/multi_buffer.hpp b/include/boost/beast/core/impl/multi_buffer.hpp index d1f8469f..dd18189c 100644 --- a/include/boost/beast/core/impl/multi_buffer.hpp +++ b/include/boost/beast/core/impl/multi_buffer.hpp @@ -148,10 +148,11 @@ class basic_multi_buffer::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::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::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:: delete_list(); } +template +basic_multi_buffer:: +basic_multi_buffer() noexcept(default_nothrow) + : max_(alloc_traits::max_size(this->get())) + , out_(list_.end()) +{ +} + +template +basic_multi_buffer:: +basic_multi_buffer( + std::size_t limit) noexcept(default_nothrow) + : max_(limit) + , out_(list_.end()) +{ +} + template basic_multi_buffer:: basic_multi_buffer( @@ -672,6 +686,8 @@ void basic_multi_buffer:: 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 @@ -717,15 +734,29 @@ shrink_to_fit() noexcept } } +template +void +basic_multi_buffer:: +clear() noexcept +{ + delete_list(); + list_.clear(); + out_ = list_.end(); + in_size_ = 0; + in_pos_ = 0; + out_pos_ = 0; + out_end_ = 0; +} + template auto basic_multi_buffer:: 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 const& other) prepare(other.size()), other.data())); } -template -void -basic_multi_buffer:: -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 void basic_multi_buffer:: @@ -983,6 +998,22 @@ move_assign(basic_multi_buffer& other, std::true_type) noexcept other.out_end_ = 0; } +template +void +basic_multi_buffer:: +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 void basic_multi_buffer:: @@ -1093,20 +1124,6 @@ alloc(std::size_t n) return alloc_traits::allocate(this->get(), n); } -template -void -basic_multi_buffer:: -clear() noexcept -{ - delete_list(); - list_.clear(); - out_ = list_.end(); - in_size_ = 0; - in_pos_ = 0; - out_pos_ = 0; - out_end_ = 0; -} - template void basic_multi_buffer:: diff --git a/include/boost/beast/core/multi_buffer.hpp b/include/boost/beast/core/multi_buffer.hpp index 13e432d9..1ef32867 100644 --- a/include/boost/beast/core/multi_buffer.hpp +++ b/include/boost/beast/core/multi_buffer.hpp @@ -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 DynamicBuffer 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 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; }; diff --git a/test/beast/core/buffer_test.hpp b/test/beast/core/buffer_test.hpp index 574d30c6..cdf8375f 100644 --- a/test/beast/core/buffer_test.hpp +++ b/test/beast/core/buffer_test.hpp @@ -103,88 +103,16 @@ public: } }; -//------------------------------------------------------------------------------ - -namespace test { - -template -void -write_buffer(DynamicBuffer& b, string_view s) -{ - b.commit(net::buffer_copy( - b.prepare(s.size()), net::buffer( - s.data(), s.size()))); -} - template -typename std::enable_if< - net::is_const_buffer_sequence::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 -typename std::enable_if< - net::is_const_buffer_sequence::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 -typename std::enable_if< - net::is_const_buffer_sequence::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 -typename std::enable_if< - net::is_const_buffer_sequence::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 -typename std::enable_if< - net::is_const_buffer_sequence::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 { diff --git a/test/beast/core/buffers_cat.cpp b/test/beast/core/buffers_cat.cpp index 266e60a9..78236353 100644 --- a/test/beast/core/buffers_cat.cpp +++ b/test/beast/core/buffers_cat.cpp @@ -28,17 +28,6 @@ namespace beast { class buffers_cat_test : public unit_test::suite { public: - template - static - std::size_t - buffers_length( - ConstBufferSequence const& buffers) - { - return std::distance( - net::buffer_sequence_begin(buffers), - net::buffer_sequence_end(buffers)); - } - void testDefaultIterators() { diff --git a/test/beast/core/buffers_suffix.cpp b/test/beast/core/buffers_suffix.cpp index 3a7c6d20..32e73f56 100644 --- a/test/beast/core/buffers_suffix.cpp +++ b/test/beast/core/buffers_suffix.cpp @@ -69,7 +69,6 @@ public: // in-place init { - using namespace test; buffers_suffix> 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 diff --git a/test/beast/core/multi_buffer.cpp b/test/beast/core/multi_buffer.cpp index d259a39f..2b3e1f96 100644 --- a/test/beast/core/multi_buffer.cpp +++ b/test/beast/core/multi_buffer.cpp @@ -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::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 static bool - eq(basic_multi_buffer const& mb1, + eq( basic_multi_buffer const& mb1, basic_multi_buffer const& mb2) { return buffers_to_string(mb1.data()) == buffers_to_string(mb2.data()); } - template 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 - static - void - self_assign(U& u, V&& v) - { - u = std::forward(v); - } - - template - 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::begin(b.data()), - net::buffers_iterator::end(b.data()), - [](char& c) - { - c = static_cast(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 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; + basic_multi_buffer b1; + ostream(b1) << "Hello"; + basic_multi_buffer 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 b; + auto a = b.get_allocator(); + BOOST_STATIC_ASSERT( + ! std::is_const::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(); +#endif } }; diff --git a/test/beast/core/static_buffer.cpp b/test/beast/core/static_buffer.cpp index df424b90..5b2d7eb1 100644 --- a/test/beast/core/static_buffer.cpp +++ b/test/beast/core/static_buffer.cpp @@ -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 {