multi_buffer implementation change (API Change):

fix #440

WARNING

multi_buffer constructor now takes a maximum size instead of the
"allocation size". This is a breaking change. The allocation size
feature is removed. To update calling code, remove the allocation
size parameter from call sites.

* multi_buffer now uses a geometric growth algorithm for better performance.
This commit is contained in:
Vinnie Falco
2017-06-08 11:07:37 -07:00
parent 74c26a8869
commit 196d9c60fa
9 changed files with 235 additions and 270 deletions

View File

@ -10,6 +10,12 @@ Version 51
API Changes: API Changes:
* Tune up static_buffer * Tune up static_buffer
* multi_buffer implementation change
Actions Required:
* Call sites passing a number to multi_buffer's constructor
will need to be adjusted, see the corresponding commit message.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -26,12 +26,12 @@ read_size_helper(DynamicBuffer const& buffer, std::size_t max_size)
BOOST_ASSERT(max_size >= 1); BOOST_ASSERT(max_size >= 1);
auto const size = buffer.size(); auto const size = buffer.size();
auto const limit = buffer.max_size() - size; auto const limit = buffer.max_size() - size;
if(limit > 0) if(limit <= 0)
return std::min<std::size_t>( BOOST_THROW_EXCEPTION(std::length_error{
std::max<std::size_t>(512, buffer.capacity() - size), "dynamic buffer overflow"});
std::min<std::size_t>(max_size, limit)); return std::min<std::size_t>(
BOOST_THROW_EXCEPTION(std::length_error{ std::max<std::size_t>(512, buffer.capacity() - size),
"dynamic buffer overflow"}); std::min<std::size_t>(max_size, limit));
} }
} // detail } // detail

View File

@ -416,7 +416,7 @@ buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) ->
} }
if(n > 0) if(n > 0)
BOOST_THROW_EXCEPTION(std::length_error{ BOOST_THROW_EXCEPTION(std::length_error{
"no space"}); "buffer overflow"});
return mutable_buffers_type{*this}; return mutable_buffers_type{*this};
} }

View File

@ -264,7 +264,9 @@ public:
}; };
template<class Allocator> template<class Allocator>
basic_multi_buffer<Allocator>::const_buffers_type::const_buffers_type( basic_multi_buffer<Allocator>::
const_buffers_type::
const_buffers_type(
basic_multi_buffer const& b) basic_multi_buffer const& b)
: b_(&b) : b_(&b)
{ {
@ -272,7 +274,9 @@ basic_multi_buffer<Allocator>::const_buffers_type::const_buffers_type(
template<class Allocator> template<class Allocator>
auto auto
basic_multi_buffer<Allocator>::const_buffers_type::begin() const -> basic_multi_buffer<Allocator>::
const_buffers_type::
begin() const ->
const_iterator const_iterator
{ {
return const_iterator{*b_, b_->list_.begin()}; return const_iterator{*b_, b_->list_.begin()};
@ -280,7 +284,9 @@ basic_multi_buffer<Allocator>::const_buffers_type::begin() const ->
template<class Allocator> template<class Allocator>
auto auto
basic_multi_buffer<Allocator>::const_buffers_type::end() const -> basic_multi_buffer<Allocator>::
const_buffers_type::
end() const ->
const_iterator const_iterator
{ {
return const_iterator{*b_, b_->out_ == return const_iterator{*b_, b_->out_ ==
@ -375,7 +381,9 @@ public:
}; };
template<class Allocator> template<class Allocator>
basic_multi_buffer<Allocator>::mutable_buffers_type::mutable_buffers_type( basic_multi_buffer<Allocator>::
mutable_buffers_type::
mutable_buffers_type(
basic_multi_buffer const& b) basic_multi_buffer const& b)
: b_(&b) : b_(&b)
{ {
@ -383,7 +391,9 @@ basic_multi_buffer<Allocator>::mutable_buffers_type::mutable_buffers_type(
template<class Allocator> template<class Allocator>
auto auto
basic_multi_buffer<Allocator>::mutable_buffers_type::begin() const -> basic_multi_buffer<Allocator>::
mutable_buffers_type::
begin() const ->
const_iterator const_iterator
{ {
return const_iterator{*b_, b_->out_}; return const_iterator{*b_, b_->out_};
@ -391,7 +401,9 @@ basic_multi_buffer<Allocator>::mutable_buffers_type::begin() const ->
template<class Allocator> template<class Allocator>
auto auto
basic_multi_buffer<Allocator>::mutable_buffers_type::end() const -> basic_multi_buffer<Allocator>::
mutable_buffers_type::
end() const ->
const_iterator const_iterator
{ {
return const_iterator{*b_, b_->list_.end()}; return const_iterator{*b_, b_->list_.end()};
@ -400,17 +412,25 @@ basic_multi_buffer<Allocator>::mutable_buffers_type::end() const ->
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<class Allocator> template<class Allocator>
basic_multi_buffer<Allocator>::~basic_multi_buffer() basic_multi_buffer<Allocator>::
~basic_multi_buffer()
{ {
delete_list(); delete_list();
} }
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer()
: out_(list_.end())
{
}
template<class Allocator> template<class Allocator>
basic_multi_buffer<Allocator>:: basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer&& other) basic_multi_buffer(basic_multi_buffer&& other)
: detail::empty_base_optimization<allocator_type>( : detail::empty_base_optimization<allocator_type>(
std::move(other.member())) std::move(other.member()))
, alloc_size_(other.alloc_size_) , max_(other.max_)
, in_size_(other.in_size_) , in_size_(other.in_size_)
, in_pos_(other.in_pos_) , in_pos_(other.in_pos_)
, out_pos_(other.out_pos_) , out_pos_(other.out_pos_)
@ -431,7 +451,7 @@ template<class Allocator>
basic_multi_buffer<Allocator>:: basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer&& other, basic_multi_buffer(basic_multi_buffer&& other,
allocator_type const& alloc) allocator_type const& alloc)
: basic_multi_buffer(other.alloc_size_, alloc) : basic_multi_buffer(other.max_, alloc)
{ {
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
if(this->member() != other.member()) if(this->member() != other.member())
@ -440,104 +460,126 @@ basic_multi_buffer(basic_multi_buffer&& other,
move_assign(other, std::true_type{}); move_assign(other, std::true_type{});
} }
template<class Allocator>
auto
basic_multi_buffer<Allocator>::operator=(
basic_multi_buffer&& other) -> basic_multi_buffer&
{
if(this == &other)
return *this;
// VFALCO If any memory allocated we could use it first?
clear();
alloc_size_ = other.alloc_size_;
move_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_move_assignment::value>{});
return *this;
}
template<class Allocator> template<class Allocator>
basic_multi_buffer<Allocator>:: basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer const& other) basic_multi_buffer(basic_multi_buffer const& other)
: basic_multi_buffer(other.alloc_size_, : basic_multi_buffer(other.max_,
alloc_traits::select_on_container_copy_construction(other.member())) alloc_traits::select_on_container_copy_construction(other.member()))
{ {
commit(boost::asio::buffer_copy(prepare(other.size()), other.data())); commit(boost::asio::buffer_copy(
prepare(other.size()), other.data()));
} }
template<class Allocator> template<class Allocator>
basic_multi_buffer<Allocator>:: basic_multi_buffer<Allocator>::
basic_multi_buffer(basic_multi_buffer const& other, basic_multi_buffer(basic_multi_buffer const& other,
allocator_type const& alloc) allocator_type const& alloc)
: basic_multi_buffer(other.alloc_size_, alloc) : basic_multi_buffer(other.max_, alloc)
{ {
commit(boost::asio::buffer_copy(prepare(other.size()), other.data())); commit(boost::asio::buffer_copy(
prepare(other.size()), other.data()));
}
template<class Allocator>
template<class OtherAlloc>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer<OtherAlloc> const& other)
: basic_multi_buffer(other.max_)
{
using boost::asio::buffer_copy;
commit(buffer_copy(prepare(other.size()), other.data()));
}
template<class Allocator>
template<class OtherAlloc>
basic_multi_buffer<Allocator>::
basic_multi_buffer(
basic_multi_buffer<OtherAlloc> const& other,
allocator_type const& alloc)
: basic_multi_buffer(other.max_, alloc)
{
using boost::asio::buffer_copy;
commit(buffer_copy(prepare(other.size()), other.data()));
}
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(std::size_t limit)
: max_(limit)
, out_(list_.end())
{
if(max_ <= 0)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid limit"});
}
template<class Allocator>
basic_multi_buffer<Allocator>::
basic_multi_buffer(std::size_t limit,
Allocator const& alloc)
: detail::empty_base_optimization<
allocator_type>(alloc)
, max_(limit)
, out_(list_.end())
{
if(max_ <= 0)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid limit"});
} }
template<class Allocator> template<class Allocator>
auto auto
basic_multi_buffer<Allocator>::operator=( basic_multi_buffer<Allocator>::
basic_multi_buffer const& other) -> operator=(basic_multi_buffer&& other) ->
basic_multi_buffer& basic_multi_buffer&
{
if(this == &other)
return *this;
// VFALCO If any memory allocated we could use it first?
clear();
max_ = other.max_;
move_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_move_assignment::value>{});
return *this;
}
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
operator=(basic_multi_buffer const& other) ->
basic_multi_buffer&
{ {
if(this == &other) if(this == &other)
return *this; return *this;
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
clear(); clear();
max_ = other.max_;
copy_assign(other, std::integral_constant<bool, copy_assign(other, std::integral_constant<bool,
alloc_traits::propagate_on_container_copy_assignment::value>{}); alloc_traits::propagate_on_container_copy_assignment::value>{});
commit(buffer_copy(prepare(other.size()), other.data())); commit(buffer_copy(prepare(other.size()), other.data()));
return *this; return *this;
} }
template<class Allocator>
template<class OtherAlloc>
basic_multi_buffer<Allocator>::basic_multi_buffer(
basic_multi_buffer<OtherAlloc> const& other)
: basic_multi_buffer(other.alloc_size_)
{
using boost::asio::buffer_copy;
commit(buffer_copy(prepare(other.size()), other.data()));
}
template<class Allocator>
template<class OtherAlloc>
basic_multi_buffer<Allocator>::basic_multi_buffer(
basic_multi_buffer<OtherAlloc> const& other,
allocator_type const& alloc)
: basic_multi_buffer(other.alloc_size_, alloc)
{
using boost::asio::buffer_copy;
commit(buffer_copy(prepare(other.size()), other.data()));
}
template<class Allocator> template<class Allocator>
template<class OtherAlloc> template<class OtherAlloc>
auto auto
basic_multi_buffer<Allocator>::operator=( basic_multi_buffer<Allocator>::
operator=(
basic_multi_buffer<OtherAlloc> const& other) -> basic_multi_buffer<OtherAlloc> const& other) ->
basic_multi_buffer& basic_multi_buffer&
{ {
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
clear(); clear();
max_ = other.max_;
commit(buffer_copy(prepare(other.size()), other.data())); commit(buffer_copy(prepare(other.size()), other.data()));
return *this; return *this;
} }
template<class Allocator>
basic_multi_buffer<Allocator>::basic_multi_buffer(
std::size_t alloc_size, Allocator const& alloc)
: detail::empty_base_optimization<allocator_type>(alloc)
, out_(list_.end())
, alloc_size_(alloc_size)
{
if(alloc_size <= 0)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid alloc_size"});
}
template<class Allocator> template<class Allocator>
std::size_t std::size_t
basic_multi_buffer<Allocator>::capacity() const basic_multi_buffer<Allocator>::
capacity() const
{ {
auto pos = out_; auto pos = out_;
if(pos == list_.end()) if(pos == list_.end())
@ -559,9 +601,13 @@ data() const ->
template<class Allocator> template<class Allocator>
auto auto
basic_multi_buffer<Allocator>::prepare(size_type n) -> basic_multi_buffer<Allocator>::
prepare(size_type n) ->
mutable_buffers_type mutable_buffers_type
{ {
if(in_size_ + n > max_)
BOOST_THROW_EXCEPTION(std::length_error{
"dynamic buffer overflow"});
list_type reuse; list_type reuse;
if(out_ != list_.end()) if(out_ != list_.end())
{ {
@ -570,7 +616,9 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
out_end_ = out_->size(); out_end_ = out_->size();
reuse.splice(reuse.end(), list_, reuse.splice(reuse.end(), list_,
std::next(out_), list_.end()); std::next(out_), list_.end());
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
} }
auto const avail = out_->size() - out_pos_; auto const avail = out_->size() - out_pos_;
if(n > avail) if(n > avail)
@ -583,7 +631,9 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
out_end_ = out_pos_ + n; out_end_ = out_pos_ + n;
n = 0; n = 0;
} }
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
} }
while(n > 0 && ! reuse.empty()) while(n > 0 && ! reuse.empty())
{ {
@ -600,11 +650,21 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
out_end_ = n; out_end_ = n;
n = 0; n = 0;
} }
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
} }
while(n > 0) while(n > 0)
{ {
auto const size = std::max(alloc_size_, n); static auto const growth_factor = 2.0f;
auto const size =
std::min<std::size_t>(
max_ - in_size_,
std::max<std::size_t>({
static_cast<std::size_t>(
in_size_ * growth_factor - in_size_),
1024,
n}));
auto& e = *reinterpret_cast<element*>(static_cast< auto& e = *reinterpret_cast<element*>(static_cast<
void*>(alloc_traits::allocate(this->member(), void*>(alloc_traits::allocate(this->member(),
sizeof(element) + size))); sizeof(element) + size)));
@ -622,7 +682,9 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
out_end_ = n; out_end_ = n;
n = 0; n = 0;
} }
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
} }
for(auto it = reuse.begin(); it != reuse.end();) for(auto it = reuse.begin(); it != reuse.end();)
{ {
@ -638,7 +700,8 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
template<class Allocator> template<class Allocator>
void void
basic_multi_buffer<Allocator>::commit(size_type n) basic_multi_buffer<Allocator>::
commit(size_type n)
{ {
if(list_.empty()) if(list_.empty())
return; return;
@ -654,14 +717,18 @@ basic_multi_buffer<Allocator>::commit(size_type n)
{ {
out_pos_ += n; out_pos_ += n;
in_size_ += n; in_size_ += n;
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
return; return;
} }
++out_; ++out_;
n -= avail; n -= avail;
out_pos_ = 0; out_pos_ = 0;
in_size_ += avail; in_size_ += avail;
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
} }
n = (std::min)(n, out_end_ - out_pos_); n = (std::min)(n, out_end_ - out_pos_);
@ -673,12 +740,15 @@ basic_multi_buffer<Allocator>::commit(size_type n)
out_pos_ = 0; out_pos_ = 0;
out_end_ = 0; out_end_ = 0;
} }
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
} }
template<class Allocator> template<class Allocator>
void void
basic_multi_buffer<Allocator>::consume(size_type n) basic_multi_buffer<Allocator>::
consume(size_type n)
{ {
if(list_.empty()) if(list_.empty())
return; return;
@ -692,7 +762,9 @@ basic_multi_buffer<Allocator>::consume(size_type n)
{ {
in_size_ -= n; in_size_ -= n;
in_pos_ += n; in_pos_ += n;
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
break; break;
} }
n -= avail; n -= avail;
@ -704,7 +776,9 @@ basic_multi_buffer<Allocator>::consume(size_type n)
alloc_traits::destroy(this->member(), &e); alloc_traits::destroy(this->member(), &e);
alloc_traits::deallocate(this->member(), alloc_traits::deallocate(this->member(),
reinterpret_cast<char*>(&e), len); reinterpret_cast<char*>(&e), len);
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
} }
else else
{ {
@ -731,7 +805,9 @@ basic_multi_buffer<Allocator>::consume(size_type n)
out_end_ = 0; out_end_ = 0;
} }
} }
//debug_check(); #if BEAST_MULTI_BUFFER_DEBUG_CHECK
debug_check();
#endif
break; break;
} }
} }
@ -792,7 +868,8 @@ move_assign(basic_multi_buffer& other, std::true_type)
template<class Allocator> template<class Allocator>
void void
basic_multi_buffer<Allocator>:: basic_multi_buffer<Allocator>::
copy_assign(basic_multi_buffer const& other, std::false_type) copy_assign(
basic_multi_buffer const& other, std::false_type)
{ {
beast::detail::ignore_unused(other); beast::detail::ignore_unused(other);
} }
@ -800,14 +877,16 @@ copy_assign(basic_multi_buffer const& other, std::false_type)
template<class Allocator> template<class Allocator>
void void
basic_multi_buffer<Allocator>:: basic_multi_buffer<Allocator>::
copy_assign(basic_multi_buffer const& other, std::true_type) copy_assign(
basic_multi_buffer const& other, std::true_type)
{ {
this->member() = other.member(); this->member() = other.member();
} }
template<class Allocator> template<class Allocator>
void void
basic_multi_buffer<Allocator>::delete_list() basic_multi_buffer<Allocator>::
delete_list()
{ {
for(auto iter = list_.begin(); iter != list_.end();) for(auto iter = list_.begin(); iter != list_.end();)
{ {
@ -821,7 +900,8 @@ basic_multi_buffer<Allocator>::delete_list()
template<class Allocator> template<class Allocator>
void void
basic_multi_buffer<Allocator>::debug_check() const basic_multi_buffer<Allocator>::
debug_check() const
{ {
#ifndef NDEBUG #ifndef NDEBUG
using boost::asio::buffer_size; using boost::asio::buffer_size;
@ -859,6 +939,7 @@ basic_multi_buffer<Allocator>::debug_check() const
#endif #endif
} }
#if 0
template<class Allocator> template<class Allocator>
std::size_t std::size_t
read_size_helper( read_size_helper(
@ -867,6 +948,11 @@ read_size_helper(
{ {
BOOST_ASSERT(max_size >= 1); BOOST_ASSERT(max_size >= 1);
auto const size = buffer.size(); auto const size = buffer.size();
auto const limit = buffer.max_size() - size;
if(limit <= 0)
BOOST_THROW_EXCEPTION(std::length_error{
"dynamic buffer overflow"});
auto const avail = std::min<std::size_t>( auto const avail = std::min<std::size_t>(
buffer.capacity() - size, max_size); buffer.capacity() - size, max_size);
if(avail > 0) if(avail > 0)
@ -875,6 +961,7 @@ read_size_helper(
std::min<std::size_t>(max_size, buffer.max_size() - size), std::min<std::size_t>(max_size, buffer.max_size() - size),
avail + buffer.alloc_size()); avail + buffer.alloc_size());
} }
#endif
} // beast } // beast

View File

@ -72,9 +72,10 @@ private:
typename std::iterator_traits<const_iterator>::iterator_category>::value, typename std::iterator_traits<const_iterator>::iterator_category>::value,
"BidirectionalIterator requirements not met"); "BidirectionalIterator requirements not met");
std::size_t max_ =
(std::numeric_limits<std::size_t>::max)();
list_type list_; // list of allocated buffers list_type list_; // list of allocated buffers
iterator out_; // element that contains out_pos_ iterator out_; // element that contains out_pos_
size_type alloc_size_; // min amount to allocate
size_type in_size_ = 0; // size of the input sequence size_type in_size_ = 0; // size of the input sequence
size_type in_pos_ = 0; // input offset in list_.front() size_type in_pos_ = 0; // input offset in list_.front()
size_type out_pos_ = 0; // output offset in *out_ size_type out_pos_ = 0; // output offset in *out_
@ -98,6 +99,9 @@ public:
/// Destructor. /// Destructor.
~basic_multi_buffer(); ~basic_multi_buffer();
/// Default constructor.
basic_multi_buffer();
/** Move constructor. /** Move constructor.
The new object will have the input sequence of The new object will have the input sequence of
@ -124,18 +128,6 @@ public:
basic_multi_buffer(basic_multi_buffer&&, basic_multi_buffer(basic_multi_buffer&&,
allocator_type const& alloc); allocator_type const& alloc);
/** Move assignment.
This object will have the input sequence of
the other stream buffer, and an empty output sequence.
@note After the move, the moved-from object will have
an empty input and output sequence, with no internal
buffers allocated.
*/
basic_multi_buffer&
operator=(basic_multi_buffer&&);
/** Copy constructor. /** Copy constructor.
This object will have a copy of the other stream This object will have a copy of the other stream
@ -154,13 +146,6 @@ public:
basic_multi_buffer(basic_multi_buffer const&, basic_multi_buffer(basic_multi_buffer const&,
allocator_type const& alloc); allocator_type const& alloc);
/** Copy assignment.
This object will have a copy of the other stream
buffer's input sequence, and an empty output sequence.
*/
basic_multi_buffer& operator=(basic_multi_buffer const&);
/** Copy constructor. /** Copy constructor.
This object will have a copy of the other stream This object will have a copy of the other stream
@ -181,6 +166,43 @@ public:
basic_multi_buffer(basic_multi_buffer<OtherAlloc> const&, basic_multi_buffer(basic_multi_buffer<OtherAlloc> const&,
allocator_type const& alloc); allocator_type const& alloc);
/** Constructor.
@param limit The maximum allowed sum of the input and
output sequence sizes.
*/
explicit
basic_multi_buffer(std::size_t limit);
/** Constructor.
@param limit The maximum allowed sum of the input and
output sequence sizes.
@param alloc The allocator to use.
*/
basic_multi_buffer(
std::size_t limit, Allocator const& alloc);
/** Move assignment.
This object will have the input sequence of
the other stream buffer, and an empty output sequence.
@note After the move, the moved-from object will have
an empty input and output sequence, with no internal
buffers allocated.
*/
basic_multi_buffer&
operator=(basic_multi_buffer&&);
/** Copy assignment.
This object will have a copy of the other stream
buffer's input sequence, and an empty output sequence.
*/
basic_multi_buffer& operator=(basic_multi_buffer const&);
/** Copy assignment. /** Copy assignment.
This object will have a copy of the other stream This object will have a copy of the other stream
@ -189,20 +211,6 @@ public:
template<class OtherAlloc> template<class OtherAlloc>
basic_multi_buffer& operator=(basic_multi_buffer<OtherAlloc> const&); basic_multi_buffer& operator=(basic_multi_buffer<OtherAlloc> const&);
/** Construct a stream buffer.
@param alloc_size The size of buffer to allocate. This is a
soft limit, calls to prepare for buffers exceeding this size
will allocate the larger size. The default allocation size
is 1KB (1024 bytes).
@param alloc The allocator to use. If this parameter is
unspecified, a default constructed allocator will be used.
*/
explicit
basic_multi_buffer(std::size_t alloc_size = 1024,
Allocator const& alloc = allocator_type{});
/// Returns a copy of the associated allocator. /// Returns a copy of the associated allocator.
allocator_type allocator_type
get_allocator() const get_allocator() const
@ -210,36 +218,6 @@ public:
return this->member(); return this->member();
} }
/** Returns the default allocation size.
This is the smallest size that the stream buffer will allocate.
The size of the allocation can influence capacity, which will
affect algorithms that use capacity to efficiently read from
streams.
*/
std::size_t
alloc_size() const
{
return alloc_size_;
}
/** Set the default allocation size.
This is the smallest size that the stream buffer will allocate.
The size of the allocation can influence capacity, which will
affect algorithms that use capacity to efficiently read from
streams.
@note This will not affect any already-existing allocations.
@param n The number of bytes.
*/
void
alloc_size(std::size_t n)
{
alloc_size_ = n;
}
/// Returns the size of the input sequence. /// Returns the size of the input sequence.
size_type size_type
size() const size() const
@ -251,7 +229,7 @@ public:
size_type size_type
max_size() const max_size() const
{ {
return (std::numeric_limits<std::size_t>::max)(); return max_;
} }
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation. /// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
@ -308,12 +286,14 @@ private:
debug_check() const; debug_check() const;
}; };
#if 0
/// Helper for boost::asio::read_until /// Helper for boost::asio::read_until
template<class Allocator> template<class Allocator>
std::size_t std::size_t
read_size_helper( read_size_helper(
basic_multi_buffer<Allocator> const& buffer, basic_multi_buffer<Allocator> const& buffer,
std::size_t max_size); std::size_t max_size);
#endif
/// A typical multi buffer /// A typical multi buffer
using multi_buffer = basic_multi_buffer<std::allocator<char>>; using multi_buffer = basic_multi_buffer<std::allocator<char>>;

View File

@ -161,7 +161,7 @@ public:
} }
{ {
using sb_type = beast::multi_buffer; using sb_type = beast::multi_buffer;
sb_type b(2); sb_type b;
b.prepare(3); b.prepare(3);
buffers_adapter< buffers_adapter<
sb_type::mutable_buffers_type> ba(b.prepare(8)); sb_type::mutable_buffers_type> ba(b.prepare(8));

View File

@ -72,7 +72,7 @@ public:
for(std::size_t y = 1; y < 4; ++y) { for(std::size_t y = 1; y < 4; ++y) {
std::size_t z = s.size() - (x + y); std::size_t z = s.size() - (x + y);
{ {
multi_buffer b(i); multi_buffer b;//(i);
b.commit(buffer_copy(b.prepare(x), buffer(s.data(), x))); 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(y), buffer(s.data()+x, y)));
b.commit(buffer_copy(b.prepare(z), buffer(s.data()+x+y, z))); b.commit(buffer_copy(b.prepare(z), buffer(s.data()+x+y, z)));
@ -132,44 +132,6 @@ public:
} }
} }
void
testPrepare()
{
using boost::asio::buffer_size;
{
multi_buffer b(2);
BEAST_EXPECT(buffer_size(b.prepare(5)) == 5);
BEAST_EXPECT(buffer_size(b.prepare(8)) == 8);
BEAST_EXPECT(buffer_size(b.prepare(7)) == 7);
}
{
multi_buffer b(2);
b.prepare(2);
BEAST_EXPECT(test::buffer_count(b.prepare(5)) == 2);
BEAST_EXPECT(test::buffer_count(b.prepare(8)) == 3);
BEAST_EXPECT(test::buffer_count(b.prepare(4)) == 2);
}
}
void testCommit()
{
multi_buffer b(2);
b.prepare(2);
b.prepare(5);
b.commit(1);
expect_size(1, b.data());
}
void testConsume()
{
multi_buffer b(1);
expect_size(5, b.prepare(5));
b.commit(3);
expect_size(3, b.data());
b.consume(1);
expect_size(2, b.data());
}
void testMatrix() void testMatrix()
{ {
using boost::asio::buffer; using boost::asio::buffer;
@ -184,7 +146,7 @@ public:
std::size_t z = s.size() - (x + y); std::size_t z = s.size() - (x + y);
std::size_t v = s.size() - (t + u); std::size_t v = s.size() - (t + u);
{ {
multi_buffer b(i); multi_buffer b;//(i);
{ {
auto d = b.prepare(z); auto d = b.prepare(z);
BEAST_EXPECT(buffer_size(d) == z); BEAST_EXPECT(buffer_size(d) == z);
@ -267,7 +229,7 @@ public:
void testIterators() void testIterators()
{ {
using boost::asio::buffer_size; using boost::asio::buffer_size;
multi_buffer b(1); multi_buffer b;
b.prepare(1); b.prepare(1);
b.commit(1); b.commit(1);
b.prepare(2); b.prepare(2);
@ -276,72 +238,6 @@ public:
b.prepare(1); b.prepare(1);
expect_size(3, b.prepare(3)); expect_size(3, b.prepare(3));
b.commit(2); b.commit(2);
BEAST_EXPECT(test::buffer_count(b.data()) == 4);
}
void testCapacity()
{
using beast::detail::read_size_helper;
using boost::asio::buffer_size;
{
multi_buffer b{10};
BEAST_EXPECT(b.alloc_size() == 10);
BEAST_EXPECT(read_size_helper(b, 1) == 1);
BEAST_EXPECT(read_size_helper(b, 10) == 10);
BEAST_EXPECT(read_size_helper(b, 20) == 10);
BEAST_EXPECT(read_size_helper(b, 1000) == 10);
b.prepare(3);
b.commit(3);
BEAST_EXPECT(read_size_helper(b, 10) == 7);
BEAST_EXPECT(read_size_helper(b, 1000) == 7);
}
{
multi_buffer b(1000);
BEAST_EXPECT(b.alloc_size() == 1000);
BEAST_EXPECT(read_size_helper(b, 1) == 1);
BEAST_EXPECT(read_size_helper(b, 1000) == 1000);
BEAST_EXPECT(read_size_helper(b, 2000) == 1000);
b.prepare(3);
BEAST_EXPECT(read_size_helper(b, 1) == 1);
BEAST_EXPECT(read_size_helper(b, 1000) == 1000);
BEAST_EXPECT(read_size_helper(b, 2000) == 1000);
b.commit(3);
BEAST_EXPECT(read_size_helper(b, 1) == 1);
BEAST_EXPECT(read_size_helper(b, 1000) == 997);
BEAST_EXPECT(read_size_helper(b, 2000) == 997);
b.consume(2);
BEAST_EXPECT(read_size_helper(b, 1) == 1);
BEAST_EXPECT(read_size_helper(b, 1000) == 997);
BEAST_EXPECT(read_size_helper(b, 2000) == 997);
}
{
multi_buffer b{2};
BEAST_EXPECT(b.alloc_size() == 2);
BEAST_EXPECT(test::buffer_count(b.prepare(2)) == 1);
BEAST_EXPECT(test::buffer_count(b.prepare(3)) == 2);
BEAST_EXPECT(buffer_size(b.prepare(5)) == 5);
BEAST_EXPECT(read_size_helper(b, 10) == 6);
}
{
auto avail =
[](multi_buffer const& b)
{
return b.capacity() - b.size();
};
multi_buffer b{100};
BEAST_EXPECT(b.alloc_size() == 100);
BEAST_EXPECT(avail(b) == 0);
b.prepare(100);
BEAST_EXPECT(avail(b) == 100);
b.commit(100);
BEAST_EXPECT(avail(b) == 0);
b.consume(100);
BEAST_EXPECT(avail(b) == 0);
b.alloc_size(200);
BEAST_EXPECT(b.alloc_size() == 200);
b.prepare(1);
BEAST_EXPECT(avail(b) == 200);
}
} }
void run() override void run() override
@ -350,12 +246,8 @@ public:
testSpecialMembers(); testSpecialMembers();
testAllocator(); testAllocator();
testPrepare();
testCommit();
testConsume();
testMatrix(); testMatrix();
testIterators(); testIterators();
testCapacity();
} }
}; };

View File

@ -40,7 +40,7 @@ public:
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"; "0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef";
multi_buffer b(512); multi_buffer b;
ostream(b) << s; ostream(b) << s;
BEAST_EXPECT(boost::lexical_cast<std::string>( BEAST_EXPECT(boost::lexical_cast<std::string>(
buffers(b.data())) == s); buffers(b.data())) == s);

View File

@ -379,7 +379,7 @@ public:
consuming_buffers< consuming_buffers<
boost::asio::const_buffers_1> cb{ boost::asio::const_buffers_1> cb{
boost::asio::const_buffers_1(s.data(), n)}; boost::asio::const_buffers_1(s.data(), n)};
multi_buffer b{size}; multi_buffer b;
while(n) while(n)
{ {
auto const amount = (std::min)(n, size); auto const amount = (std::min)(n, size);