mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
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:
@ -10,6 +10,12 @@ Version 51
|
||||
API Changes:
|
||||
|
||||
* 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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -26,12 +26,12 @@ read_size_helper(DynamicBuffer const& buffer, std::size_t max_size)
|
||||
BOOST_ASSERT(max_size >= 1);
|
||||
auto const size = buffer.size();
|
||||
auto const limit = buffer.max_size() - size;
|
||||
if(limit > 0)
|
||||
return std::min<std::size_t>(
|
||||
std::max<std::size_t>(512, buffer.capacity() - size),
|
||||
std::min<std::size_t>(max_size, limit));
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"dynamic buffer overflow"});
|
||||
if(limit <= 0)
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"dynamic buffer overflow"});
|
||||
return std::min<std::size_t>(
|
||||
std::max<std::size_t>(512, buffer.capacity() - size),
|
||||
std::min<std::size_t>(max_size, limit));
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
@ -416,7 +416,7 @@ buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) ->
|
||||
}
|
||||
if(n > 0)
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"no space"});
|
||||
"buffer overflow"});
|
||||
return mutable_buffers_type{*this};
|
||||
}
|
||||
|
||||
|
@ -264,7 +264,9 @@ public:
|
||||
};
|
||||
|
||||
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)
|
||||
: b_(&b)
|
||||
{
|
||||
@ -272,7 +274,9 @@ basic_multi_buffer<Allocator>::const_buffers_type::const_buffers_type(
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::const_buffers_type::begin() const ->
|
||||
basic_multi_buffer<Allocator>::
|
||||
const_buffers_type::
|
||||
begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->list_.begin()};
|
||||
@ -280,7 +284,9 @@ basic_multi_buffer<Allocator>::const_buffers_type::begin() const ->
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::const_buffers_type::end() const ->
|
||||
basic_multi_buffer<Allocator>::
|
||||
const_buffers_type::
|
||||
end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->out_ ==
|
||||
@ -375,7 +381,9 @@ public:
|
||||
};
|
||||
|
||||
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)
|
||||
: b_(&b)
|
||||
{
|
||||
@ -383,7 +391,9 @@ basic_multi_buffer<Allocator>::mutable_buffers_type::mutable_buffers_type(
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::mutable_buffers_type::begin() const ->
|
||||
basic_multi_buffer<Allocator>::
|
||||
mutable_buffers_type::
|
||||
begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->out_};
|
||||
@ -391,7 +401,9 @@ basic_multi_buffer<Allocator>::mutable_buffers_type::begin() const ->
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::mutable_buffers_type::end() const ->
|
||||
basic_multi_buffer<Allocator>::
|
||||
mutable_buffers_type::
|
||||
end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->list_.end()};
|
||||
@ -400,17 +412,25 @@ basic_multi_buffer<Allocator>::mutable_buffers_type::end() const ->
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::~basic_multi_buffer()
|
||||
basic_multi_buffer<Allocator>::
|
||||
~basic_multi_buffer()
|
||||
{
|
||||
delete_list();
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer()
|
||||
: out_(list_.end())
|
||||
{
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer&& other)
|
||||
: detail::empty_base_optimization<allocator_type>(
|
||||
std::move(other.member()))
|
||||
, alloc_size_(other.alloc_size_)
|
||||
, max_(other.max_)
|
||||
, in_size_(other.in_size_)
|
||||
, in_pos_(other.in_pos_)
|
||||
, out_pos_(other.out_pos_)
|
||||
@ -431,7 +451,7 @@ template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer&& other,
|
||||
allocator_type const& alloc)
|
||||
: basic_multi_buffer(other.alloc_size_, alloc)
|
||||
: basic_multi_buffer(other.max_, alloc)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
if(this->member() != other.member())
|
||||
@ -440,104 +460,126 @@ basic_multi_buffer(basic_multi_buffer&& other,
|
||||
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>
|
||||
basic_multi_buffer<Allocator>::
|
||||
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()))
|
||||
{
|
||||
commit(boost::asio::buffer_copy(prepare(other.size()), other.data()));
|
||||
commit(boost::asio::buffer_copy(
|
||||
prepare(other.size()), other.data()));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer const& other,
|
||||
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>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::operator=(
|
||||
basic_multi_buffer const& other) ->
|
||||
basic_multi_buffer&
|
||||
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();
|
||||
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)
|
||||
return *this;
|
||||
using boost::asio::buffer_copy;
|
||||
clear();
|
||||
max_ = other.max_;
|
||||
copy_assign(other, std::integral_constant<bool,
|
||||
alloc_traits::propagate_on_container_copy_assignment::value>{});
|
||||
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||
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 OtherAlloc>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::operator=(
|
||||
basic_multi_buffer<Allocator>::
|
||||
operator=(
|
||||
basic_multi_buffer<OtherAlloc> const& other) ->
|
||||
basic_multi_buffer&
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
clear();
|
||||
max_ = other.max_;
|
||||
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||
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>
|
||||
std::size_t
|
||||
basic_multi_buffer<Allocator>::capacity() const
|
||||
basic_multi_buffer<Allocator>::
|
||||
capacity() const
|
||||
{
|
||||
auto pos = out_;
|
||||
if(pos == list_.end())
|
||||
@ -559,9 +601,13 @@ data() const ->
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::prepare(size_type n) ->
|
||||
basic_multi_buffer<Allocator>::
|
||||
prepare(size_type n) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
if(in_size_ + n > max_)
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"dynamic buffer overflow"});
|
||||
list_type reuse;
|
||||
if(out_ != list_.end())
|
||||
{
|
||||
@ -570,7 +616,9 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
|
||||
out_end_ = out_->size();
|
||||
reuse.splice(reuse.end(), list_,
|
||||
std::next(out_), list_.end());
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
}
|
||||
auto const avail = out_->size() - out_pos_;
|
||||
if(n > avail)
|
||||
@ -583,7 +631,9 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
|
||||
out_end_ = out_pos_ + n;
|
||||
n = 0;
|
||||
}
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
}
|
||||
while(n > 0 && ! reuse.empty())
|
||||
{
|
||||
@ -600,11 +650,21 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
|
||||
out_end_ = n;
|
||||
n = 0;
|
||||
}
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
}
|
||||
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<
|
||||
void*>(alloc_traits::allocate(this->member(),
|
||||
sizeof(element) + size)));
|
||||
@ -622,7 +682,9 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
|
||||
out_end_ = n;
|
||||
n = 0;
|
||||
}
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
}
|
||||
for(auto it = reuse.begin(); it != reuse.end();)
|
||||
{
|
||||
@ -638,7 +700,8 @@ basic_multi_buffer<Allocator>::prepare(size_type n) ->
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::commit(size_type n)
|
||||
basic_multi_buffer<Allocator>::
|
||||
commit(size_type n)
|
||||
{
|
||||
if(list_.empty())
|
||||
return;
|
||||
@ -654,14 +717,18 @@ basic_multi_buffer<Allocator>::commit(size_type n)
|
||||
{
|
||||
out_pos_ += n;
|
||||
in_size_ += n;
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
++out_;
|
||||
n -= avail;
|
||||
out_pos_ = 0;
|
||||
in_size_ += avail;
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
n = (std::min)(n, out_end_ - out_pos_);
|
||||
@ -673,12 +740,15 @@ basic_multi_buffer<Allocator>::commit(size_type n)
|
||||
out_pos_ = 0;
|
||||
out_end_ = 0;
|
||||
}
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::consume(size_type n)
|
||||
basic_multi_buffer<Allocator>::
|
||||
consume(size_type n)
|
||||
{
|
||||
if(list_.empty())
|
||||
return;
|
||||
@ -692,7 +762,9 @@ basic_multi_buffer<Allocator>::consume(size_type n)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
n -= avail;
|
||||
@ -704,7 +776,9 @@ basic_multi_buffer<Allocator>::consume(size_type n)
|
||||
alloc_traits::destroy(this->member(), &e);
|
||||
alloc_traits::deallocate(this->member(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -731,7 +805,9 @@ basic_multi_buffer<Allocator>::consume(size_type n)
|
||||
out_end_ = 0;
|
||||
}
|
||||
}
|
||||
//debug_check();
|
||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
debug_check();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -792,7 +868,8 @@ move_assign(basic_multi_buffer& other, std::true_type)
|
||||
template<class Allocator>
|
||||
void
|
||||
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);
|
||||
}
|
||||
@ -800,14 +877,16 @@ copy_assign(basic_multi_buffer const& other, std::false_type)
|
||||
template<class Allocator>
|
||||
void
|
||||
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();
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::delete_list()
|
||||
basic_multi_buffer<Allocator>::
|
||||
delete_list()
|
||||
{
|
||||
for(auto iter = list_.begin(); iter != list_.end();)
|
||||
{
|
||||
@ -821,7 +900,8 @@ basic_multi_buffer<Allocator>::delete_list()
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::debug_check() const
|
||||
basic_multi_buffer<Allocator>::
|
||||
debug_check() const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
using boost::asio::buffer_size;
|
||||
@ -859,6 +939,7 @@ basic_multi_buffer<Allocator>::debug_check() const
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<class Allocator>
|
||||
std::size_t
|
||||
read_size_helper(
|
||||
@ -867,6 +948,11 @@ read_size_helper(
|
||||
{
|
||||
BOOST_ASSERT(max_size >= 1);
|
||||
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>(
|
||||
buffer.capacity() - size, max_size);
|
||||
if(avail > 0)
|
||||
@ -875,6 +961,7 @@ read_size_helper(
|
||||
std::min<std::size_t>(max_size, buffer.max_size() - size),
|
||||
avail + buffer.alloc_size());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
|
@ -72,9 +72,10 @@ private:
|
||||
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
||||
"BidirectionalIterator requirements not met");
|
||||
|
||||
std::size_t max_ =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
list_type list_; // list of allocated buffers
|
||||
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_pos_ = 0; // input offset in list_.front()
|
||||
size_type out_pos_ = 0; // output offset in *out_
|
||||
@ -98,6 +99,9 @@ public:
|
||||
/// Destructor.
|
||||
~basic_multi_buffer();
|
||||
|
||||
/// Default constructor.
|
||||
basic_multi_buffer();
|
||||
|
||||
/** Move constructor.
|
||||
|
||||
The new object will have the input sequence of
|
||||
@ -124,18 +128,6 @@ public:
|
||||
basic_multi_buffer(basic_multi_buffer&&,
|
||||
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.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
@ -154,13 +146,6 @@ public:
|
||||
basic_multi_buffer(basic_multi_buffer const&,
|
||||
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.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
@ -181,6 +166,43 @@ public:
|
||||
basic_multi_buffer(basic_multi_buffer<OtherAlloc> const&,
|
||||
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.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
@ -189,20 +211,6 @@ public:
|
||||
template<class OtherAlloc>
|
||||
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.
|
||||
allocator_type
|
||||
get_allocator() const
|
||||
@ -210,36 +218,6 @@ public:
|
||||
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.
|
||||
size_type
|
||||
size() const
|
||||
@ -251,7 +229,7 @@ public:
|
||||
size_type
|
||||
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.
|
||||
@ -308,12 +286,14 @@ private:
|
||||
debug_check() const;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/// Helper for boost::asio::read_until
|
||||
template<class Allocator>
|
||||
std::size_t
|
||||
read_size_helper(
|
||||
basic_multi_buffer<Allocator> const& buffer,
|
||||
std::size_t max_size);
|
||||
#endif
|
||||
|
||||
/// A typical multi buffer
|
||||
using multi_buffer = basic_multi_buffer<std::allocator<char>>;
|
||||
|
@ -161,7 +161,7 @@ public:
|
||||
}
|
||||
{
|
||||
using sb_type = beast::multi_buffer;
|
||||
sb_type b(2);
|
||||
sb_type b;
|
||||
b.prepare(3);
|
||||
buffers_adapter<
|
||||
sb_type::mutable_buffers_type> ba(b.prepare(8));
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
for(std::size_t y = 1; y < 4; ++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(y), buffer(s.data()+x, y)));
|
||||
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()
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
@ -184,7 +146,7 @@ public:
|
||||
std::size_t z = s.size() - (x + y);
|
||||
std::size_t v = s.size() - (t + u);
|
||||
{
|
||||
multi_buffer b(i);
|
||||
multi_buffer b;//(i);
|
||||
{
|
||||
auto d = b.prepare(z);
|
||||
BEAST_EXPECT(buffer_size(d) == z);
|
||||
@ -267,7 +229,7 @@ public:
|
||||
void testIterators()
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
multi_buffer b(1);
|
||||
multi_buffer b;
|
||||
b.prepare(1);
|
||||
b.commit(1);
|
||||
b.prepare(2);
|
||||
@ -276,72 +238,6 @@ public:
|
||||
b.prepare(1);
|
||||
expect_size(3, b.prepare(3));
|
||||
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
|
||||
@ -350,12 +246,8 @@ public:
|
||||
|
||||
testSpecialMembers();
|
||||
testAllocator();
|
||||
testPrepare();
|
||||
testCommit();
|
||||
testConsume();
|
||||
testMatrix();
|
||||
testIterators();
|
||||
testCapacity();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
|
||||
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
|
||||
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef";
|
||||
multi_buffer b(512);
|
||||
multi_buffer b;
|
||||
ostream(b) << s;
|
||||
BEAST_EXPECT(boost::lexical_cast<std::string>(
|
||||
buffers(b.data())) == s);
|
||||
|
@ -379,7 +379,7 @@ public:
|
||||
consuming_buffers<
|
||||
boost::asio::const_buffers_1> cb{
|
||||
boost::asio::const_buffers_1(s.data(), n)};
|
||||
multi_buffer b{size};
|
||||
multi_buffer b;
|
||||
while(n)
|
||||
{
|
||||
auto const amount = (std::min)(n, size);
|
||||
|
Reference in New Issue
Block a user