mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
multi_buffer improvements:
fix #1345 * Revise documentation * Add reserve() member * Add max_size() member * Add shrink_to_fit() member * Respect Allocator max_size * Specify exception safety
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
Version 198:
|
||||
|
||||
* flat_buffer improvements
|
||||
* multi_buffer improvements
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -446,17 +446,20 @@ basic_multi_buffer<Allocator>::
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(Allocator const& alloc) noexcept
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
basic_multi_buffer(
|
||||
Allocator const& alloc) noexcept
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), alloc)
|
||||
, max_(alloc_traits::max_size(this->get()))
|
||||
, out_(list_.end())
|
||||
{
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(std::size_t limit,
|
||||
Allocator const& alloc) noexcept
|
||||
basic_multi_buffer(
|
||||
std::size_t limit,
|
||||
Allocator const& alloc) noexcept
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
, max_(limit)
|
||||
@ -466,9 +469,10 @@ basic_multi_buffer(std::size_t limit,
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer&& other) noexcept
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), std::move(other.get()))
|
||||
basic_multi_buffer(
|
||||
basic_multi_buffer&& other) noexcept
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), std::move(other.get()))
|
||||
, max_(other.max_)
|
||||
, in_size_(boost::exchange(other.in_size_, 0))
|
||||
, in_pos_(boost::exchange(other.in_pos_, 0))
|
||||
@ -484,8 +488,9 @@ basic_multi_buffer(basic_multi_buffer&& other) noexcept
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer&& other,
|
||||
Allocator const& alloc)
|
||||
basic_multi_buffer(
|
||||
basic_multi_buffer&& other,
|
||||
Allocator const& alloc)
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
, max_(other.max_)
|
||||
@ -494,7 +499,7 @@ basic_multi_buffer(basic_multi_buffer&& other,
|
||||
{
|
||||
out_ = list_.end();
|
||||
copy_from(other);
|
||||
other.reset();
|
||||
other.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -516,11 +521,12 @@ basic_multi_buffer(basic_multi_buffer&& other,
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer const& other)
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), alloc_traits::
|
||||
select_on_container_copy_construction(
|
||||
other.get()))
|
||||
basic_multi_buffer(
|
||||
basic_multi_buffer const& other)
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), alloc_traits::
|
||||
select_on_container_copy_construction(
|
||||
other.get()))
|
||||
, max_(other.max_)
|
||||
, out_(list_.end())
|
||||
{
|
||||
@ -529,10 +535,11 @@ basic_multi_buffer(basic_multi_buffer const& other)
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer const& other,
|
||||
Allocator const& alloc)
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
basic_multi_buffer(
|
||||
basic_multi_buffer const& other,
|
||||
Allocator const& alloc)
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), alloc)
|
||||
, max_(other.max_)
|
||||
, out_(list_.end())
|
||||
{
|
||||
@ -571,10 +578,9 @@ operator=(basic_multi_buffer&& other) ->
|
||||
{
|
||||
if(this == &other)
|
||||
return *this;
|
||||
reset();
|
||||
clear();
|
||||
max_ = other.max_;
|
||||
move_assign(other, std::integral_constant<bool,
|
||||
alloc_traits::propagate_on_container_move_assignment::value>{});
|
||||
move_assign(other, pocma{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -586,8 +592,7 @@ basic_multi_buffer&
|
||||
{
|
||||
if(this == &other)
|
||||
return *this;
|
||||
copy_assign(other, std::integral_constant<bool,
|
||||
alloc_traits::propagate_on_container_copy_assignment::value>{});
|
||||
copy_assign(other, pocca{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -599,8 +604,7 @@ operator=(
|
||||
basic_multi_buffer<OtherAlloc> const& other) ->
|
||||
basic_multi_buffer&
|
||||
{
|
||||
reset();
|
||||
max_ = other.max_;
|
||||
clear();
|
||||
copy_from(other);
|
||||
return *this;
|
||||
}
|
||||
@ -639,6 +643,56 @@ data() noexcept ->
|
||||
return mutable_data_type(*this);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
reserve(std::size_t n)
|
||||
{
|
||||
if(n > alloc_traits::max_size(this->get()))
|
||||
BOOST_THROW_EXCEPTION(std::length_error(
|
||||
"A basic_multi_buffer exceeded the allocator's maximum size"));
|
||||
std::size_t total = in_size_;
|
||||
if(n <= total)
|
||||
return;
|
||||
if(out_ != list_.end())
|
||||
{
|
||||
total += out_->size() - out_pos_;
|
||||
if(n <= total)
|
||||
return;
|
||||
auto it = out_;
|
||||
while(++it != list_.end())
|
||||
{
|
||||
total += it->size();
|
||||
if(n <= total)
|
||||
return;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(n > total);
|
||||
(void)prepare(n - total);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
shrink_to_fit() noexcept
|
||||
{
|
||||
if( out_ != list_.end() &&
|
||||
out_ != list_.iterator_to(list_.back()))
|
||||
{
|
||||
list_type extra;
|
||||
extra.splice(extra.end(), list_,
|
||||
std::next(out_), list_.end());
|
||||
for(auto it = extra.begin(); it != extra.end();)
|
||||
{
|
||||
auto& e = *it++;
|
||||
auto const len = sizeof(e) + e.size();
|
||||
e.~element();
|
||||
alloc_traits::deallocate(this->get(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
@ -647,7 +701,7 @@ prepare(size_type n) ->
|
||||
{
|
||||
if(in_size_ + n > max_)
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"dynamic buffer overflow"});
|
||||
"A basic_multi_buffer exceeded its maximum size"});
|
||||
list_type reuse;
|
||||
std::size_t total = in_size_;
|
||||
// put all empty buffers on reuse list
|
||||
@ -707,7 +761,7 @@ prepare(size_type n) ->
|
||||
auto& e = *it++;
|
||||
reuse.erase(list_.iterator_to(e));
|
||||
auto const len = sizeof(e) + e.size();
|
||||
alloc_traits::destroy(this->get(), &e);
|
||||
e.~element();
|
||||
alloc_traits::deallocate(this->get(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
}
|
||||
@ -722,10 +776,8 @@ prepare(size_type n) ->
|
||||
in_size_ * growth_factor - in_size_),
|
||||
512,
|
||||
n}));
|
||||
auto& e = *reinterpret_cast<element*>(static_cast<
|
||||
void*>(alloc_traits::allocate(this->get(),
|
||||
sizeof(element) + size)));
|
||||
alloc_traits::construct(this->get(), &e, size);
|
||||
auto &e = *::new(alloc(
|
||||
sizeof(element) + size)) element(size);
|
||||
list_.push_back(e);
|
||||
if(out_ == list_.end())
|
||||
out_ = list_.iterator_to(e);
|
||||
@ -813,7 +865,7 @@ consume(size_type n) noexcept
|
||||
auto& e = list_.front();
|
||||
list_.erase(list_.iterator_to(e));
|
||||
auto const len = sizeof(e) + e.size();
|
||||
alloc_traits::destroy(this->get(), &e);
|
||||
e.~element();
|
||||
alloc_traits::deallocate(this->get(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||
@ -854,45 +906,17 @@ consume(size_type n) noexcept
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
template<class OtherAlloc>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
reset() noexcept
|
||||
copy_from(basic_multi_buffer<OtherAlloc> const& other)
|
||||
{
|
||||
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>::
|
||||
delete_list() noexcept
|
||||
{
|
||||
for(auto iter = list_.begin(); iter != list_.end();)
|
||||
{
|
||||
auto& e = *iter++;
|
||||
auto const len = sizeof(e) + e.size();
|
||||
alloc_traits::destroy(this->get(), &e);
|
||||
alloc_traits::deallocate(this->get(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
copy_from(DynamicBuffer const& buffer)
|
||||
{
|
||||
if(buffer.size() == 0)
|
||||
clear();
|
||||
max_ = other.max_;
|
||||
if(other.size() == 0)
|
||||
return;
|
||||
using net::buffer_copy;
|
||||
commit(buffer_copy(
|
||||
prepare(buffer.size()), buffer.data()));
|
||||
commit(net::buffer_copy(
|
||||
prepare(other.size()), other.data()));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
@ -903,7 +927,7 @@ move_assign(basic_multi_buffer& other, std::false_type)
|
||||
if(this->get() != other.get())
|
||||
{
|
||||
copy_from(other);
|
||||
other.reset();
|
||||
other.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -926,6 +950,7 @@ move_assign(basic_multi_buffer& other, std::true_type) noexcept
|
||||
in_pos_ = other.in_pos_;
|
||||
out_pos_ = other.out_pos_;
|
||||
out_end_ = other.out_end_;
|
||||
max_ = other.max_;
|
||||
|
||||
other.in_size_ = 0;
|
||||
other.out_ = other.list_.end();
|
||||
@ -940,8 +965,6 @@ basic_multi_buffer<Allocator>::
|
||||
copy_assign(
|
||||
basic_multi_buffer const& other, std::false_type)
|
||||
{
|
||||
reset();
|
||||
max_ = other.max_;
|
||||
copy_from(other);
|
||||
}
|
||||
|
||||
@ -951,8 +974,7 @@ basic_multi_buffer<Allocator>::
|
||||
copy_assign(
|
||||
basic_multi_buffer const& other, std::true_type)
|
||||
{
|
||||
reset();
|
||||
max_ = other.max_;
|
||||
clear();
|
||||
this->get() = other.get();
|
||||
copy_from(other);
|
||||
}
|
||||
@ -1021,6 +1043,46 @@ swap(
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
delete_list() noexcept
|
||||
{
|
||||
for(auto it = list_.begin(); it != list_.end();)
|
||||
{
|
||||
auto& e = *it++;
|
||||
auto const len = sizeof(e) + e.size();
|
||||
e.~element();
|
||||
alloc_traits::deallocate(this->get(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
char*
|
||||
basic_multi_buffer<Allocator>::
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
if(n > alloc_traits::max_size(this->get()))
|
||||
BOOST_THROW_EXCEPTION(std::length_error(
|
||||
"A basic_multi_buffer exceeded the allocator's maximum size"));
|
||||
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>::
|
||||
|
@ -43,16 +43,16 @@ namespace beast {
|
||||
Objects of this type meet the requirements of @b DynamicBuffer
|
||||
and have the following additional properties:
|
||||
|
||||
@li The buffer sequence representing the readable bytes
|
||||
returned by @ref data is mutable.
|
||||
@li A mutable buffer sequence representing the readable
|
||||
bytes is returned by @ref data when `this` is non-const.
|
||||
|
||||
@li Buffer sequences representing the readable and writable
|
||||
bytes, returned by @ref data and @ref prepare, may have
|
||||
length greater than one.
|
||||
|
||||
@li A configurable maximum buffer size may be set upon
|
||||
construction. Attempts to exceed the buffer size will throw
|
||||
`std::length_error`.
|
||||
@li A configurable maximum size may be set upon construction
|
||||
and adjusted afterwards. Calls to @ref prepare that would
|
||||
exceed this size will throw `std::length_error`.
|
||||
|
||||
@li Sequences previously obtained using @ref data remain
|
||||
valid after calls to @ref prepare or @ref commit.
|
||||
@ -71,6 +71,9 @@ class basic_multi_buffer
|
||||
detail::allocator_traits<Allocator>::
|
||||
template rebind_alloc<char>;
|
||||
|
||||
static bool constexpr default_nothrow =
|
||||
std::is_nothrow_default_constructible<Allocator>::value;
|
||||
|
||||
// Storage for the list of buffers representing the input
|
||||
// and output sequences. The allocation for each element
|
||||
// contains `element` followed by raw storage bytes.
|
||||
@ -89,6 +92,12 @@ class basic_multi_buffer
|
||||
using const_buffer = net::const_buffer;
|
||||
using mutable_buffer = net::mutable_buffer;
|
||||
|
||||
using pocma = typename
|
||||
alloc_traits::propagate_on_container_move_assignment;
|
||||
|
||||
using pocca = typename
|
||||
alloc_traits::propagate_on_container_copy_assignment;
|
||||
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<iter>::iterator_category>::value,
|
||||
"BidirectionalIterator requirements not met");
|
||||
@ -97,8 +106,7 @@ class basic_multi_buffer
|
||||
typename std::iterator_traits<const_iter>::iterator_category>::value,
|
||||
"BidirectionalIterator requirements not met");
|
||||
|
||||
std::size_t max_ =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
std::size_t max_;
|
||||
list_type list_; // list of allocated buffers
|
||||
iter out_; // element that contains out_pos_
|
||||
size_type in_size_ = 0; // size of the input sequence
|
||||
@ -115,24 +123,26 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, @ref capacity will return zero.
|
||||
After construction, @ref capacity will return zero, and
|
||||
@ref max_size will return the largest value which may
|
||||
be passed to the allocator's `allocate` function.
|
||||
*/
|
||||
basic_multi_buffer() noexcept(
|
||||
std::is_nothrow_default_constructible<Allocator>::value)
|
||||
:
|
||||
out_(list_.end())
|
||||
basic_multi_buffer() noexcept(default_nothrow)
|
||||
: max_(alloc_traits::max_size(this->get()))
|
||||
, out_(list_.end())
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, @ref capacity will return zero.
|
||||
After construction, @ref capacity will return zero, and
|
||||
@ref max_size will return the specified value of `limit`.
|
||||
|
||||
@param limit The setting for @ref max_size.
|
||||
@param limit The desired maximum size.
|
||||
*/
|
||||
explicit
|
||||
basic_multi_buffer(std::size_t limit) noexcept(
|
||||
std::is_nothrow_default_constructible<Allocator>::value)
|
||||
basic_multi_buffer(
|
||||
std::size_t limit) noexcept(default_nothrow)
|
||||
: max_(limit)
|
||||
, out_(list_.end())
|
||||
{
|
||||
@ -140,87 +150,116 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, @ref capacity will return zero.
|
||||
After construction, @ref capacity will return zero, and
|
||||
@ref max_size will return the largest value which may
|
||||
be passed to the allocator's `allocate` function.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
@param alloc The allocator to use for the object.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
explicit
|
||||
basic_multi_buffer(Allocator const& alloc) noexcept;
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, @ref capacity will return zero.
|
||||
After construction, @ref capacity will return zero, and
|
||||
@ref max_size will return the specified value of `limit`.
|
||||
|
||||
@param limit The setting for @ref max_size.
|
||||
@param limit The desired maximum size.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
@param alloc The allocator to use for the object.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
basic_multi_buffer(
|
||||
std::size_t limit, Allocator const& alloc) noexcept;
|
||||
|
||||
/** Move Constructor
|
||||
|
||||
Constructs the container with the contents of other
|
||||
using move semantics. After the move, other is
|
||||
guaranteed to be empty.
|
||||
The container is constructed with the contents of `other`
|
||||
using move semantics. The maximum size will be the same
|
||||
as the moved-from object.
|
||||
|
||||
Buffer sequences previously obtained using @ref data
|
||||
or @ref prepare are not invalidated after the move.
|
||||
Buffer sequences previously obtained from `other` using
|
||||
@ref data or @ref prepare remain valid after the move.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
@param other The object to move from. After the move, the
|
||||
moved-from object will have zero capacity, zero readable
|
||||
bytes, and zero writable bytes.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
basic_multi_buffer(basic_multi_buffer&& other) noexcept;
|
||||
|
||||
/** Move Constructor
|
||||
|
||||
Using alloc as the allocator for the new container, the
|
||||
contents of other are moved. If `alloc != other.get_allocator()`,
|
||||
this results in a copy. After the move, other is
|
||||
guaranteed to be empty.
|
||||
Using `alloc` as the allocator for the new container, the
|
||||
contents of `other` are moved. If `alloc != other.get_allocator()`,
|
||||
this results in a copy. The maximum size will be the same
|
||||
as the moved-from object.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
Buffer sequences previously obtained from `other` using
|
||||
@ref data or @ref prepare become invalid after the move.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
the moved-from object will have zero capacity, zero readable
|
||||
bytes, and zero writable bytes.
|
||||
|
||||
@param alloc The allocator to use for the newly
|
||||
constructed object.
|
||||
@param alloc The allocator to use for the object.
|
||||
|
||||
@throws std::length_error if `other.size()` exceeds the
|
||||
maximum allocation size of `alloc`.
|
||||
*/
|
||||
basic_multi_buffer(basic_multi_buffer&& other,
|
||||
basic_multi_buffer(
|
||||
basic_multi_buffer&& other,
|
||||
Allocator const& alloc);
|
||||
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
allocator and contents of other, and zero writable bytes.
|
||||
This container is constructed with the contents of `other`
|
||||
using copy semantics. The maximum size will be the same
|
||||
as the copied object.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@throws std::length_error if `other.size()` exceeds the
|
||||
maximum allocation size of the allocator.
|
||||
*/
|
||||
basic_multi_buffer(basic_multi_buffer const& other);
|
||||
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
specified allocator, a copy of the contents of other,
|
||||
and zero writable bytes.
|
||||
This container is constructed with the contents of `other`
|
||||
using copy semantics and the specified allocator. The maximum
|
||||
size will be the same as the copied object.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
@param alloc The allocator to use for the object.
|
||||
|
||||
@throws std::length_error if `other.size()` exceeds the
|
||||
maximum allocation size of `alloc`.
|
||||
*/
|
||||
basic_multi_buffer(basic_multi_buffer const& other,
|
||||
Allocator const& alloc);
|
||||
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
contents of other, and zero writable bytes.
|
||||
This container is constructed with the contents of `other`
|
||||
using copy semantics. The maximum size will be the same
|
||||
as the copied object.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@throws std::length_error if `other.size()` exceeds the
|
||||
maximum allocation size of the allocator.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_multi_buffer(basic_multi_buffer<
|
||||
@ -228,52 +267,66 @@ public:
|
||||
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
specified allocator, a copy of the contents of other,
|
||||
and zero writable bytes.
|
||||
This container is constructed with the contents of `other`
|
||||
using copy semantics. The maximum size will be the same
|
||||
as the copied object.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
@param alloc The allocator to use for the object.
|
||||
|
||||
@throws std::length_error if `other.size()` exceeds the
|
||||
maximum allocation size of `alloc`.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_multi_buffer(basic_multi_buffer<
|
||||
OtherAlloc> const& other, allocator_type const& alloc);
|
||||
basic_multi_buffer(
|
||||
basic_multi_buffer<OtherAlloc> const& other,
|
||||
allocator_type const& alloc);
|
||||
|
||||
/** Move Assignment
|
||||
|
||||
Assigns the container with the contents of other
|
||||
using move semantics. After the move, other is
|
||||
guaranteed to be empty. The previous contents of
|
||||
this container are deleted.
|
||||
The container is assigned with the contents of `other`
|
||||
using move semantics. The maximum size will be the same
|
||||
as the moved-from object.
|
||||
|
||||
Buffer sequences previously obtained using @ref data
|
||||
or @ref prepare are not invalidated after the move.
|
||||
Buffer sequences previously obtained from `other` using
|
||||
@ref data or @ref prepare remain valid after the move.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
the moved-from object will have zero capacity, zero readable
|
||||
bytes, and zero writable bytes.
|
||||
*/
|
||||
basic_multi_buffer&
|
||||
operator=(basic_multi_buffer&& other);
|
||||
|
||||
/** Copy Assignment
|
||||
|
||||
The assigned object will have a copy of the allocator
|
||||
and contents of other, and zero writable bytes. The
|
||||
previous contents of this container are deleted.
|
||||
The container is assigned with the contents of `other`
|
||||
using copy semantics. The maximum size will be the same
|
||||
as the copied object.
|
||||
|
||||
After the copy, `this` will have zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@throws std::length_error if `other.size()` exceeds the
|
||||
maximum allocation size of the allocator.
|
||||
*/
|
||||
basic_multi_buffer& operator=(basic_multi_buffer const& other);
|
||||
basic_multi_buffer& operator=(
|
||||
basic_multi_buffer const& other);
|
||||
|
||||
/** Copy assignment
|
||||
/** Copy Assignment
|
||||
|
||||
The assigned object will have a copy of the contents
|
||||
of other, and zero writable bytes. The previous contents
|
||||
of this container are deleted.
|
||||
The container is assigned with the contents of `other`
|
||||
using copy semantics. The maximum size will be the same
|
||||
as the copied object.
|
||||
|
||||
After the copy, `this` will have zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@throws std::length_error if `other.size()` exceeds the
|
||||
maximum allocation size of the allocator.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_multi_buffer& operator=(
|
||||
@ -286,6 +339,66 @@ public:
|
||||
return this->get();
|
||||
}
|
||||
|
||||
/** Set the maximum allowed capacity
|
||||
|
||||
This function changes the currently configured upper limit
|
||||
on capacity to the specified value.
|
||||
|
||||
@param n The maximum number of bytes ever allowed for capacity.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
void
|
||||
max_size(std::size_t n) noexcept
|
||||
{
|
||||
max_ = n;
|
||||
}
|
||||
|
||||
/** Guarantee a minimum capacity
|
||||
|
||||
This function adjusts the internal storage (if necessary)
|
||||
to guarantee space for at least `n` bytes.
|
||||
|
||||
Buffer sequences previously obtained using @ref data remain
|
||||
valid, while buffer sequences previously obtained using
|
||||
@ref prepare become invalid.
|
||||
|
||||
@param n The minimum number of byte for the new capacity.
|
||||
If this value is greater than the maximum size, then the
|
||||
maximum size will be adjusted upwards to this value.
|
||||
|
||||
@throws std::length_error if n is larger than the maximum
|
||||
allocation size of the allocator.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
Strong guarantee.
|
||||
*/
|
||||
void
|
||||
reserve(std::size_t n);
|
||||
|
||||
/** Reallocate the buffer to fit the readable bytes exactly.
|
||||
|
||||
Buffer sequences previously obtained using @ref data or
|
||||
@ref prepare become invalid.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
void
|
||||
shrink_to_fit() noexcept;
|
||||
|
||||
/// Exchange two dynamic buffers
|
||||
template<class Alloc>
|
||||
friend
|
||||
void
|
||||
swap(
|
||||
basic_multi_buffer<Alloc>& lhs,
|
||||
basic_multi_buffer<Alloc>& rhs) noexcept;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#if BOOST_BEAST_DOXYGEN
|
||||
@ -354,6 +467,10 @@ public:
|
||||
sequence.
|
||||
|
||||
@throws std::length_error if `size() + n` exceeds `max_size()`.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
Strong guarantee.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(size_type n);
|
||||
@ -372,6 +489,10 @@ public:
|
||||
@param n The number of bytes to append. If this number
|
||||
is greater than the number of writable bytes, all
|
||||
writable bytes are appended.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
void
|
||||
commit(size_type n) noexcept;
|
||||
@ -386,27 +507,20 @@ public:
|
||||
@param n The number of bytes to remove. If this number
|
||||
is greater than the number of readable bytes, all
|
||||
readable bytes are removed.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
void
|
||||
consume(size_type n) noexcept;
|
||||
|
||||
/// Exchange two dynamic buffers
|
||||
template<class Alloc>
|
||||
friend
|
||||
void
|
||||
swap(
|
||||
basic_multi_buffer<Alloc>& lhs,
|
||||
basic_multi_buffer<Alloc>& rhs) noexcept;
|
||||
|
||||
private:
|
||||
template<class OtherAlloc>
|
||||
friend class basic_multi_buffer;
|
||||
|
||||
void reset() noexcept;
|
||||
void delete_list() noexcept;
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void copy_from(DynamicBuffer const& other);
|
||||
template<class OtherAlloc>
|
||||
void copy_from(basic_multi_buffer<OtherAlloc> const&);
|
||||
void move_assign(basic_multi_buffer& other, std::false_type);
|
||||
void move_assign(basic_multi_buffer& other, std::true_type) noexcept;
|
||||
void copy_assign(basic_multi_buffer const& other, std::false_type);
|
||||
@ -414,6 +528,9 @@ private:
|
||||
void swap(basic_multi_buffer&) noexcept;
|
||||
void swap(basic_multi_buffer&, std::true_type) noexcept;
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -442,6 +442,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// max_size
|
||||
{
|
||||
multi_buffer b{10};
|
||||
BEAST_EXPECT(b.max_size() == 10);
|
||||
b.max_size(32);
|
||||
BEAST_EXPECT(b.max_size() == 32);
|
||||
}
|
||||
|
||||
// prepare
|
||||
{
|
||||
{
|
||||
@ -570,6 +578,46 @@ public:
|
||||
BEAST_EXPECT(b.size() == 0);
|
||||
}
|
||||
|
||||
// reserve
|
||||
{
|
||||
multi_buffer b;
|
||||
BEAST_EXPECT(b.capacity() == 0);
|
||||
b.reserve(50);
|
||||
BEAST_EXPECT(b.capacity() >= 50);
|
||||
b.prepare(20);
|
||||
b.commit(20);
|
||||
b.reserve(50);
|
||||
BEAST_EXPECT(b.capacity() >= 50);
|
||||
}
|
||||
|
||||
// shrink to fit
|
||||
{
|
||||
{
|
||||
multi_buffer b;
|
||||
BEAST_EXPECT(b.capacity() == 0);
|
||||
b.prepare(50);
|
||||
BEAST_EXPECT(b.capacity() >= 50);
|
||||
b.commit(50);
|
||||
BEAST_EXPECT(b.capacity() >= 50);
|
||||
b.prepare(75);
|
||||
BEAST_EXPECT(b.capacity() >= 125);
|
||||
b.shrink_to_fit();
|
||||
BEAST_EXPECT(b.capacity() >= b.size());
|
||||
}
|
||||
{
|
||||
multi_buffer b;
|
||||
b.prepare(2000);
|
||||
BEAST_EXPECT(b.capacity() == 2000);
|
||||
b.commit(1800);
|
||||
BEAST_EXPECT(b.size() == 1800);
|
||||
BEAST_EXPECT(b.capacity() == 2000);
|
||||
b.prepare(5000);
|
||||
BEAST_EXPECT(b.capacity() == 6800);
|
||||
b.shrink_to_fit();
|
||||
BEAST_EXPECT(b.capacity() == 2000);
|
||||
}
|
||||
}
|
||||
|
||||
// swap
|
||||
{
|
||||
{
|
||||
|
Reference in New Issue
Block a user