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