forked from boostorg/beast
@@ -2,6 +2,7 @@ Version 54:
|
|||||||
|
|
||||||
* static_buffer coverage
|
* static_buffer coverage
|
||||||
* flat_buffer coverage
|
* flat_buffer coverage
|
||||||
|
* multi_buffer coverage
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -425,6 +425,34 @@ basic_multi_buffer()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
basic_multi_buffer(std::size_t limit)
|
||||||
|
: max_(limit)
|
||||||
|
, out_(list_.end())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
basic_multi_buffer(Allocator const& alloc)
|
||||||
|
: detail::empty_base_optimization<
|
||||||
|
allocator_type>(alloc)
|
||||||
|
, out_(list_.end())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
basic_multi_buffer(basic_multi_buffer&& other)
|
basic_multi_buffer(basic_multi_buffer&& other)
|
||||||
@@ -450,34 +478,54 @@ 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&& other,
|
basic_multi_buffer(basic_multi_buffer&& other,
|
||||||
allocator_type const& alloc)
|
Allocator const& alloc)
|
||||||
: basic_multi_buffer(other.max_, alloc)
|
: detail::empty_base_optimization<allocator_type>(alloc)
|
||||||
|
, max_(other.max_)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_copy;
|
|
||||||
if(this->member() != other.member())
|
if(this->member() != other.member())
|
||||||
commit(buffer_copy(prepare(other.size()), other.data()));
|
{
|
||||||
|
out_ = list_.end();
|
||||||
|
copy_from(other);
|
||||||
|
other.reset();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
move_assign(other, std::true_type{});
|
{
|
||||||
|
auto const at_end =
|
||||||
|
other.out_ == other.list_.end();
|
||||||
|
list_ = std::move(other.list_);
|
||||||
|
out_ = at_end ? list_.end() : other.out_;
|
||||||
|
in_size_ = other.in_size_;
|
||||||
|
in_pos_ = other.in_pos_;
|
||||||
|
out_pos_ = other.out_pos_;
|
||||||
|
out_end_ = other.out_end_;
|
||||||
|
other.in_size_ = 0;
|
||||||
|
other.out_ = other.list_.end();
|
||||||
|
other.in_pos_ = 0;
|
||||||
|
other.out_pos_ = 0;
|
||||||
|
other.out_end_ = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
basic_multi_buffer(basic_multi_buffer const& other)
|
basic_multi_buffer(basic_multi_buffer const& other)
|
||||||
: basic_multi_buffer(other.max_,
|
: detail::empty_base_optimization<allocator_type>(
|
||||||
alloc_traits::select_on_container_copy_construction(other.member()))
|
alloc_traits::select_on_container_copy_construction(other.member()))
|
||||||
|
, max_(other.max_)
|
||||||
|
, out_(list_.end())
|
||||||
{
|
{
|
||||||
commit(boost::asio::buffer_copy(
|
copy_from(other);
|
||||||
prepare(other.size()), other.data()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
basic_multi_buffer(basic_multi_buffer const& other,
|
basic_multi_buffer(basic_multi_buffer const& other,
|
||||||
allocator_type const& alloc)
|
Allocator const& alloc)
|
||||||
: basic_multi_buffer(other.max_, alloc)
|
: detail::empty_base_optimization<allocator_type>(alloc)
|
||||||
|
, max_(other.max_)
|
||||||
|
, out_(list_.end())
|
||||||
{
|
{
|
||||||
commit(boost::asio::buffer_copy(
|
copy_from(other);
|
||||||
prepare(other.size()), other.data()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
@@ -485,10 +533,9 @@ template<class OtherAlloc>
|
|||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
basic_multi_buffer(
|
basic_multi_buffer(
|
||||||
basic_multi_buffer<OtherAlloc> const& other)
|
basic_multi_buffer<OtherAlloc> const& other)
|
||||||
: basic_multi_buffer(other.max_)
|
: out_(list_.end())
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_copy;
|
copy_from(other);
|
||||||
commit(buffer_copy(prepare(other.size()), other.data()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
@@ -497,35 +544,11 @@ basic_multi_buffer<Allocator>::
|
|||||||
basic_multi_buffer(
|
basic_multi_buffer(
|
||||||
basic_multi_buffer<OtherAlloc> const& other,
|
basic_multi_buffer<OtherAlloc> const& other,
|
||||||
allocator_type const& alloc)
|
allocator_type const& alloc)
|
||||||
: basic_multi_buffer(other.max_, alloc)
|
: detail::empty_base_optimization<allocator_type>(alloc)
|
||||||
{
|
, max_(other.max_)
|
||||||
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())
|
, out_(list_.end())
|
||||||
{
|
{
|
||||||
if(max_ <= 0)
|
copy_from(other);
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
|
||||||
"invalid limit"});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Allocator>
|
|
||||||
basic_multi_buffer<Allocator>::
|
|
||||||
basic_multi_buffer(std::size_t limit,
|
|
||||||
Allocator const& alloc)
|
|
||||||
: detail::empty_base_optimization<
|
|
||||||
allocator_type>(alloc)
|
|
||||||
, max_(limit)
|
|
||||||
, out_(list_.end())
|
|
||||||
{
|
|
||||||
if(max_ <= 0)
|
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
|
||||||
"invalid limit"});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
@@ -536,11 +559,10 @@ operator=(basic_multi_buffer&& other) ->
|
|||||||
{
|
{
|
||||||
if(this == &other)
|
if(this == &other)
|
||||||
return *this;
|
return *this;
|
||||||
// VFALCO If any memory allocated we could use it first?
|
reset();
|
||||||
clear();
|
|
||||||
max_ = other.max_;
|
max_ = other.max_;
|
||||||
move_assign(other, std::integral_constant<bool,
|
move_assign(other, typename
|
||||||
alloc_traits::propagate_on_container_move_assignment::value>{});
|
alloc_traits::propagate_on_container_move_assignment{});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,12 +574,8 @@ basic_multi_buffer&
|
|||||||
{
|
{
|
||||||
if(this == &other)
|
if(this == &other)
|
||||||
return *this;
|
return *this;
|
||||||
using boost::asio::buffer_copy;
|
copy_assign(other, typename
|
||||||
clear();
|
alloc_traits::propagate_on_container_copy_assignment{});
|
||||||
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,10 +587,9 @@ operator=(
|
|||||||
basic_multi_buffer<OtherAlloc> const& other) ->
|
basic_multi_buffer<OtherAlloc> const& other) ->
|
||||||
basic_multi_buffer&
|
basic_multi_buffer&
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_copy;
|
reset();
|
||||||
clear();
|
|
||||||
max_ = other.max_;
|
max_ = other.max_;
|
||||||
commit(buffer_copy(prepare(other.size()), other.data()));
|
copy_from(other);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,8 +626,11 @@ prepare(size_type n) ->
|
|||||||
BOOST_THROW_EXCEPTION(std::length_error{
|
BOOST_THROW_EXCEPTION(std::length_error{
|
||||||
"dynamic buffer overflow"});
|
"dynamic buffer overflow"});
|
||||||
list_type reuse;
|
list_type reuse;
|
||||||
|
std::size_t total = in_size_;
|
||||||
|
// put all empty buffers on reuse list
|
||||||
if(out_ != list_.end())
|
if(out_ != list_.end())
|
||||||
{
|
{
|
||||||
|
total += out_->size() - out_pos_;
|
||||||
if(out_ != list_.iterator_to(list_.back()))
|
if(out_ != list_.iterator_to(list_.back()))
|
||||||
{
|
{
|
||||||
out_end_ = out_->size();
|
out_end_ = out_->size();
|
||||||
@@ -635,11 +655,13 @@ prepare(size_type n) ->
|
|||||||
debug_check();
|
debug_check();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
// get space from reuse buffers
|
||||||
while(n > 0 && ! reuse.empty())
|
while(n > 0 && ! reuse.empty())
|
||||||
{
|
{
|
||||||
auto& e = reuse.front();
|
auto& e = reuse.front();
|
||||||
reuse.erase(reuse.iterator_to(e));
|
reuse.erase(reuse.iterator_to(e));
|
||||||
list_.push_back(e);
|
list_.push_back(e);
|
||||||
|
total += e.size();
|
||||||
if(n > e.size())
|
if(n > e.size())
|
||||||
{
|
{
|
||||||
out_end_ = e.size();
|
out_end_ = e.size();
|
||||||
@@ -654,16 +676,23 @@ prepare(size_type n) ->
|
|||||||
debug_check();
|
debug_check();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
while(n > 0)
|
BOOST_ASSERT(total <= max_);
|
||||||
|
for(auto it = reuse.begin(); it != reuse.end();)
|
||||||
|
{
|
||||||
|
auto& e = *it++;
|
||||||
|
reuse.erase(list_.iterator_to(e));
|
||||||
|
delete_element(e);
|
||||||
|
}
|
||||||
|
if(n > 0)
|
||||||
{
|
{
|
||||||
static auto const growth_factor = 2.0f;
|
static auto const growth_factor = 2.0f;
|
||||||
auto const size =
|
auto const size =
|
||||||
std::min<std::size_t>(
|
std::min<std::size_t>(
|
||||||
max_ - in_size_,
|
max_ - total,
|
||||||
std::max<std::size_t>({
|
std::max<std::size_t>({
|
||||||
static_cast<std::size_t>(
|
static_cast<std::size_t>(
|
||||||
in_size_ * growth_factor - in_size_),
|
in_size_ * growth_factor - in_size_),
|
||||||
1024,
|
512,
|
||||||
n}));
|
n}));
|
||||||
auto& e = *reinterpret_cast<element*>(static_cast<
|
auto& e = *reinterpret_cast<element*>(static_cast<
|
||||||
void*>(alloc_traits::allocate(this->member(),
|
void*>(alloc_traits::allocate(this->member(),
|
||||||
@@ -672,29 +701,11 @@ prepare(size_type n) ->
|
|||||||
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);
|
||||||
if(n >= e.size())
|
out_end_ = n;
|
||||||
{
|
|
||||||
out_end_ = e.size();
|
|
||||||
n -= e.size();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out_end_ = n;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||||
debug_check();
|
debug_check();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
for(auto it = reuse.begin(); it != reuse.end();)
|
|
||||||
{
|
|
||||||
auto& e = *it++;
|
|
||||||
reuse.erase(list_.iterator_to(e));
|
|
||||||
auto const len = e.size() + sizeof(e);
|
|
||||||
alloc_traits::destroy(this->member(), &e);
|
|
||||||
alloc_traits::deallocate(this->member(),
|
|
||||||
reinterpret_cast<char*>(&e), len);
|
|
||||||
}
|
|
||||||
return mutable_buffers_type(*this);
|
return mutable_buffers_type(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,12 +763,12 @@ consume(size_type n)
|
|||||||
{
|
{
|
||||||
if(list_.empty())
|
if(list_.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if(list_.begin() != out_)
|
if(list_.begin() != out_)
|
||||||
{
|
{
|
||||||
auto const avail = list_.front().size() - in_pos_;
|
auto const avail =
|
||||||
|
list_.front().size() - in_pos_;
|
||||||
if(n < avail)
|
if(n < avail)
|
||||||
{
|
{
|
||||||
in_size_ -= n;
|
in_size_ -= n;
|
||||||
@@ -772,10 +783,7 @@ consume(size_type n)
|
|||||||
in_pos_ = 0;
|
in_pos_ = 0;
|
||||||
auto& e = list_.front();
|
auto& e = list_.front();
|
||||||
list_.erase(list_.iterator_to(e));
|
list_.erase(list_.iterator_to(e));
|
||||||
auto const len = e.size() + sizeof(e);
|
delete_element(e);
|
||||||
alloc_traits::destroy(this->member(), &e);
|
|
||||||
alloc_traits::deallocate(this->member(),
|
|
||||||
reinterpret_cast<char*>(&e), len);
|
|
||||||
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
#if BEAST_MULTI_BUFFER_DEBUG_CHECK
|
||||||
debug_check();
|
debug_check();
|
||||||
#endif
|
#endif
|
||||||
@@ -814,13 +822,36 @@ consume(size_type n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
|
inline
|
||||||
void
|
void
|
||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
clear()
|
delete_element(element& e)
|
||||||
|
{
|
||||||
|
auto const len = sizeof(e) + e.size();
|
||||||
|
alloc_traits::destroy(this->member(), &e);
|
||||||
|
alloc_traits::deallocate(this->member(),
|
||||||
|
reinterpret_cast<char*>(&e), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
delete_list()
|
||||||
|
{
|
||||||
|
for(auto iter = list_.begin(); iter != list_.end();)
|
||||||
|
delete_element(*iter++);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
reset()
|
||||||
{
|
{
|
||||||
delete_list();
|
delete_list();
|
||||||
list_.clear();
|
list_.clear();
|
||||||
out_ = list_.begin();
|
out_ = list_.end();
|
||||||
in_size_ = 0;
|
in_size_ = 0;
|
||||||
in_pos_ = 0;
|
in_pos_ = 0;
|
||||||
out_pos_ = 0;
|
out_pos_ = 0;
|
||||||
@@ -828,21 +859,38 @@ clear()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
|
template<class DynamicBuffer>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
copy_from(DynamicBuffer const& buffer)
|
||||||
|
{
|
||||||
|
if(buffer.size() == 0)
|
||||||
|
return;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
commit(buffer_copy(
|
||||||
|
prepare(buffer.size()), buffer.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
void
|
void
|
||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
move_assign(basic_multi_buffer& other, std::false_type)
|
move_assign(basic_multi_buffer& other, std::false_type)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_copy;
|
|
||||||
if(this->member() != other.member())
|
if(this->member() != other.member())
|
||||||
{
|
{
|
||||||
commit(buffer_copy(prepare(other.size()), other.data()));
|
copy_from(other);
|
||||||
other.clear();
|
other.reset();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
move_assign(other, std::true_type{});
|
move_assign(other, std::true_type{});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
|
inline
|
||||||
void
|
void
|
||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
move_assign(basic_multi_buffer& other, std::true_type)
|
move_assign(basic_multi_buffer& other, std::true_type)
|
||||||
@@ -866,36 +914,95 @@ move_assign(basic_multi_buffer& other, std::true_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
|
inline
|
||||||
void
|
void
|
||||||
basic_multi_buffer<Allocator>::
|
basic_multi_buffer<Allocator>::
|
||||||
copy_assign(
|
copy_assign(
|
||||||
basic_multi_buffer const& other, std::false_type)
|
basic_multi_buffer const& other, std::false_type)
|
||||||
{
|
{
|
||||||
beast::detail::ignore_unused(other);
|
reset();
|
||||||
|
max_ = other.max_;
|
||||||
|
copy_from(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
|
inline
|
||||||
void
|
void
|
||||||
basic_multi_buffer<Allocator>::
|
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();
|
||||||
|
max_ = other.max_;
|
||||||
this->member() = other.member();
|
this->member() = other.member();
|
||||||
|
copy_from(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
swap(basic_multi_buffer& other)
|
||||||
|
{
|
||||||
|
swap(other, typename
|
||||||
|
alloc_traits::propagate_on_container_swap{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
swap(basic_multi_buffer& other, std::true_type)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
auto const at_end0 =
|
||||||
|
out_ == list_.end();
|
||||||
|
auto const at_end1 =
|
||||||
|
other.out_ == other.list_.end();
|
||||||
|
swap(this->member(), other.member());
|
||||||
|
swap(list_, other.list_);
|
||||||
|
swap(out_, other.out_);
|
||||||
|
if(at_end1)
|
||||||
|
out_ = list_.end();
|
||||||
|
if(at_end0)
|
||||||
|
other.out_ = other.list_.end();
|
||||||
|
swap(in_size_, other.in_size_);
|
||||||
|
swap(in_pos_, other.in_pos_);
|
||||||
|
swap(out_pos_, other.out_pos_);
|
||||||
|
swap(out_end_, other.out_end_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_multi_buffer<Allocator>::
|
||||||
|
swap(basic_multi_buffer& other, std::false_type)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(this->member() == other.member());
|
||||||
|
using std::swap;
|
||||||
|
auto const at_end0 =
|
||||||
|
out_ == list_.end();
|
||||||
|
auto const at_end1 =
|
||||||
|
other.out_ == other.list_.end();
|
||||||
|
swap(list_, other.list_);
|
||||||
|
swap(out_, other.out_);
|
||||||
|
if(at_end1)
|
||||||
|
out_ = list_.end();
|
||||||
|
if(at_end0)
|
||||||
|
other.out_ = other.list_.end();
|
||||||
|
swap(in_size_, other.in_size_);
|
||||||
|
swap(in_pos_, other.in_pos_);
|
||||||
|
swap(out_pos_, other.out_pos_);
|
||||||
|
swap(out_end_, other.out_end_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_multi_buffer<Allocator>::
|
swap(
|
||||||
delete_list()
|
basic_multi_buffer<Allocator>& lhs,
|
||||||
|
basic_multi_buffer<Allocator>& rhs)
|
||||||
{
|
{
|
||||||
for(auto iter = list_.begin(); iter != list_.end();)
|
lhs.swap(rhs);
|
||||||
{
|
|
||||||
auto& e = *iter++;
|
|
||||||
auto const n = e.size() + sizeof(e);
|
|
||||||
alloc_traits::destroy(this->member(), &e);
|
|
||||||
alloc_traits::deallocate(this->member(),
|
|
||||||
reinterpret_cast<char*>(&e), n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
@@ -939,30 +1046,6 @@ debug_check() const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
template<class Allocator>
|
|
||||||
std::size_t
|
|
||||||
read_size_helper(
|
|
||||||
basic_multi_buffer<Allocator> 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)
|
|
||||||
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)
|
|
||||||
return avail; // avoid allocation
|
|
||||||
return std::min<std::size_t>(
|
|
||||||
std::min<std::size_t>(max_size, buffer.max_size() - size),
|
|
||||||
avail + buffer.alloc_size());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -96,120 +96,121 @@ public:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor
|
||||||
~basic_multi_buffer();
|
~basic_multi_buffer();
|
||||||
|
|
||||||
/// Default constructor.
|
/** Constructor
|
||||||
|
|
||||||
|
Upon construction, capacity will be zero.
|
||||||
|
*/
|
||||||
basic_multi_buffer();
|
basic_multi_buffer();
|
||||||
|
|
||||||
/** Move constructor.
|
|
||||||
|
|
||||||
The new 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(basic_multi_buffer&&);
|
|
||||||
|
|
||||||
/** Move constructor.
|
|
||||||
|
|
||||||
The new 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.
|
|
||||||
|
|
||||||
@param alloc The allocator to associate with the
|
|
||||||
stream buffer.
|
|
||||||
*/
|
|
||||||
basic_multi_buffer(basic_multi_buffer&&,
|
|
||||||
allocator_type const& alloc);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
*/
|
|
||||||
basic_multi_buffer(basic_multi_buffer const&);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
|
|
||||||
@param alloc The allocator to associate with the
|
|
||||||
stream buffer.
|
|
||||||
*/
|
|
||||||
basic_multi_buffer(basic_multi_buffer const&,
|
|
||||||
allocator_type const& alloc);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
*/
|
|
||||||
template<class OtherAlloc>
|
|
||||||
basic_multi_buffer(basic_multi_buffer<OtherAlloc> const&);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
|
|
||||||
@param alloc The allocator to associate with the
|
|
||||||
stream buffer.
|
|
||||||
*/
|
|
||||||
template<class OtherAlloc>
|
|
||||||
basic_multi_buffer(basic_multi_buffer<OtherAlloc> const&,
|
|
||||||
allocator_type const& alloc);
|
|
||||||
|
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
|
|
||||||
@param limit The maximum allowed sum of the input and
|
@param limit The setting for @ref max_size.
|
||||||
output sequence sizes.
|
|
||||||
*/
|
*/
|
||||||
explicit
|
explicit
|
||||||
basic_multi_buffer(std::size_t limit);
|
basic_multi_buffer(std::size_t limit);
|
||||||
|
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
|
|
||||||
@param limit The maximum allowed sum of the input and
|
@param alloc The allocator to use.
|
||||||
output sequence sizes.
|
*/
|
||||||
|
basic_multi_buffer(Allocator const& alloc);
|
||||||
|
|
||||||
|
/** Constructor.
|
||||||
|
|
||||||
|
@param limit The setting for @ref max_size.
|
||||||
|
|
||||||
@param alloc The allocator to use.
|
@param alloc The allocator to use.
|
||||||
*/
|
*/
|
||||||
basic_multi_buffer(
|
basic_multi_buffer(
|
||||||
std::size_t limit, Allocator const& alloc);
|
std::size_t limit, Allocator const& alloc);
|
||||||
|
|
||||||
/** Move assignment.
|
/** Move constructor
|
||||||
|
|
||||||
This object will have the input sequence of
|
After the move, `*this` will have an empty output sequence.
|
||||||
the other stream buffer, and an empty output sequence.
|
|
||||||
|
|
||||||
@note After the move, the moved-from object will have
|
@param other The object to move from. After the move,
|
||||||
an empty input and output sequence, with no internal
|
The object's state will be as if constructed using
|
||||||
buffers allocated.
|
its current allocator and limit.
|
||||||
*/
|
*/
|
||||||
basic_multi_buffer&
|
basic_multi_buffer(basic_multi_buffer&& other);
|
||||||
operator=(basic_multi_buffer&&);
|
|
||||||
|
|
||||||
/** Copy assignment.
|
/** Move constructor
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
After the move, `*this` will have an empty output sequence.
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
|
@param other The object to move from. After the move,
|
||||||
|
The object's state will be as if constructed using
|
||||||
|
its current allocator and limit.
|
||||||
|
|
||||||
|
@param alloc The allocator to use.
|
||||||
*/
|
*/
|
||||||
basic_multi_buffer& operator=(basic_multi_buffer const&);
|
basic_multi_buffer(basic_multi_buffer&& other,
|
||||||
|
Allocator const& alloc);
|
||||||
|
|
||||||
/** Copy assignment.
|
/** Copy constructor.
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
@param other The object to copy from.
|
||||||
buffer's input sequence, and an empty output sequence.
|
*/
|
||||||
|
basic_multi_buffer(basic_multi_buffer const& other);
|
||||||
|
|
||||||
|
/** Copy constructor
|
||||||
|
|
||||||
|
@param other The object to copy from.
|
||||||
|
|
||||||
|
@param alloc The allocator to use.
|
||||||
|
*/
|
||||||
|
basic_multi_buffer(basic_multi_buffer const& other,
|
||||||
|
Allocator const& alloc);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
@param other The object to copy from.
|
||||||
*/
|
*/
|
||||||
template<class OtherAlloc>
|
template<class OtherAlloc>
|
||||||
basic_multi_buffer& operator=(basic_multi_buffer<OtherAlloc> const&);
|
basic_multi_buffer(basic_multi_buffer<
|
||||||
|
OtherAlloc> const& other);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
@param other The object to copy from.
|
||||||
|
|
||||||
|
@param alloc The allocator to use.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_multi_buffer(basic_multi_buffer<
|
||||||
|
OtherAlloc> const& other, allocator_type const& alloc);
|
||||||
|
|
||||||
|
/** Move assignment
|
||||||
|
|
||||||
|
After the move, `*this` will have an empty output sequence.
|
||||||
|
|
||||||
|
@param other The object to move from. After the move,
|
||||||
|
The object's state will be as if constructed using
|
||||||
|
its current allocator and limit.
|
||||||
|
*/
|
||||||
|
basic_multi_buffer&
|
||||||
|
operator=(basic_multi_buffer&& other);
|
||||||
|
|
||||||
|
/** Copy assignment
|
||||||
|
|
||||||
|
After the copy, `*this` will have an empty output sequence.
|
||||||
|
|
||||||
|
@param other The object to copy from.
|
||||||
|
*/
|
||||||
|
basic_multi_buffer& operator=(basic_multi_buffer const& other);
|
||||||
|
|
||||||
|
/** Copy assignment
|
||||||
|
|
||||||
|
After the copy, `*this` will have an empty output sequence.
|
||||||
|
|
||||||
|
@param other The object to copy from.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_multi_buffer& operator=(
|
||||||
|
basic_multi_buffer<OtherAlloc> const& other);
|
||||||
|
|
||||||
/// Returns a copy of the associated allocator.
|
/// Returns a copy of the associated allocator.
|
||||||
allocator_type
|
allocator_type
|
||||||
@@ -263,9 +264,29 @@ public:
|
|||||||
void
|
void
|
||||||
consume(size_type n);
|
consume(size_type n);
|
||||||
|
|
||||||
private:
|
template<class Alloc>
|
||||||
|
friend
|
||||||
void
|
void
|
||||||
clear();
|
swap(
|
||||||
|
basic_multi_buffer<Alloc>& lhs,
|
||||||
|
basic_multi_buffer<Alloc>& rhs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<class OtherAlloc>
|
||||||
|
friend class basic_multi_buffer;
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_element(element& e);
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_list();
|
||||||
|
|
||||||
|
void
|
||||||
|
reset();
|
||||||
|
|
||||||
|
template<class DynamicBuffer>
|
||||||
|
void
|
||||||
|
copy_from(DynamicBuffer const& other);
|
||||||
|
|
||||||
void
|
void
|
||||||
move_assign(basic_multi_buffer& other, std::false_type);
|
move_assign(basic_multi_buffer& other, std::false_type);
|
||||||
@@ -280,21 +301,18 @@ private:
|
|||||||
copy_assign(basic_multi_buffer const& other, std::true_type);
|
copy_assign(basic_multi_buffer const& other, std::true_type);
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_list();
|
swap(basic_multi_buffer&);
|
||||||
|
|
||||||
|
void
|
||||||
|
swap(basic_multi_buffer&, std::true_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
swap(basic_multi_buffer&, std::false_type);
|
||||||
|
|
||||||
void
|
void
|
||||||
debug_check() const;
|
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
|
/// A typical multi buffer
|
||||||
using multi_buffer = basic_multi_buffer<std::allocator<char>>;
|
using multi_buffer = basic_multi_buffer<std::allocator<char>>;
|
||||||
|
|
||||||
|
@@ -9,7 +9,9 @@
|
|||||||
#include <beast/core/multi_buffer.hpp>
|
#include <beast/core/multi_buffer.hpp>
|
||||||
|
|
||||||
#include "buffer_test.hpp"
|
#include "buffer_test.hpp"
|
||||||
|
|
||||||
#include <beast/core/ostream.hpp>
|
#include <beast/core/ostream.hpp>
|
||||||
|
#include <beast/core/string_view.hpp>
|
||||||
#include <beast/core/type_traits.hpp>
|
#include <beast/core/type_traits.hpp>
|
||||||
#include <beast/test/test_allocator.hpp>
|
#include <beast/test/test_allocator.hpp>
|
||||||
#include <beast/unit_test/suite.hpp>
|
#include <beast/unit_test/suite.hpp>
|
||||||
@@ -26,22 +28,14 @@ BOOST_STATIC_ASSERT(is_dynamic_buffer<multi_buffer>::value);
|
|||||||
class multi_buffer_test : public beast::unit_test::suite
|
class multi_buffer_test : public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<class ConstBufferSequence>
|
|
||||||
static
|
|
||||||
std::string
|
|
||||||
to_string(ConstBufferSequence const& bs)
|
|
||||||
{
|
|
||||||
return boost::lexical_cast<
|
|
||||||
std::string>(buffers(bs));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Alloc1, class Alloc2>
|
template<class Alloc1, class Alloc2>
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
eq(basic_multi_buffer<Alloc1> const& sb1,
|
eq(basic_multi_buffer<Alloc1> const& mb1,
|
||||||
basic_multi_buffer<Alloc2> const& sb2)
|
basic_multi_buffer<Alloc2> const& mb2)
|
||||||
{
|
{
|
||||||
return to_string(sb1.data()) == to_string(sb2.data());
|
return test::to_string(mb1.data()) ==
|
||||||
|
test::to_string(mb2.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
@@ -62,8 +56,10 @@ public:
|
|||||||
u = std::forward<V>(v);
|
u = std::forward<V>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testSpecialMembers()
|
void
|
||||||
|
testMatrix1()
|
||||||
{
|
{
|
||||||
|
using namespace test;
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
std::string const s = "Hello, world";
|
std::string const s = "Hello, world";
|
||||||
BEAST_EXPECT(s.size() == 12);
|
BEAST_EXPECT(s.size() == 12);
|
||||||
@@ -72,27 +68,27 @@ public:
|
|||||||
for(std::size_t y = 1; y < 4; ++y) {
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
std::size_t z = s.size() - (x + y);
|
std::size_t z = s.size() - (x + y);
|
||||||
{
|
{
|
||||||
multi_buffer b;//(i);
|
multi_buffer b;
|
||||||
b.commit(buffer_copy(b.prepare(x), buffer(s.data(), x)));
|
b.commit(buffer_copy(b.prepare(x), buffer(s.data(), x)));
|
||||||
b.commit(buffer_copy(b.prepare(y), buffer(s.data()+x, y)));
|
b.commit(buffer_copy(b.prepare(y), buffer(s.data()+x, y)));
|
||||||
b.commit(buffer_copy(b.prepare(z), buffer(s.data()+x+y, z)));
|
b.commit(buffer_copy(b.prepare(z), buffer(s.data()+x+y, z)));
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
{
|
{
|
||||||
multi_buffer sb2(b);
|
multi_buffer mb2{b};
|
||||||
BEAST_EXPECT(eq(b, sb2));
|
BEAST_EXPECT(eq(b, mb2));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
multi_buffer sb2;
|
multi_buffer mb2;
|
||||||
sb2 = b;
|
mb2 = b;
|
||||||
BEAST_EXPECT(eq(b, sb2));
|
BEAST_EXPECT(eq(b, mb2));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
multi_buffer sb2(std::move(b));
|
multi_buffer mb2{std::move(b)};
|
||||||
BEAST_EXPECT(to_string(sb2.data()) == s);
|
BEAST_EXPECT(to_string(mb2.data()) == s);
|
||||||
expect_size(0, b.data());
|
expect_size(0, b.data());
|
||||||
b = std::move(sb2);
|
b = std::move(mb2);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
expect_size(0, sb2.data());
|
expect_size(0, mb2.data());
|
||||||
}
|
}
|
||||||
self_assign(b, b);
|
self_assign(b, b);
|
||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
@@ -100,40 +96,12 @@ public:
|
|||||||
BEAST_EXPECT(to_string(b.data()) == s);
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
}
|
}
|
||||||
}}}
|
}}}
|
||||||
try
|
|
||||||
{
|
|
||||||
multi_buffer sb0(0);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
catch(std::exception const&)
|
|
||||||
{
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testAllocator()
|
testMatrix2()
|
||||||
{
|
|
||||||
using test::test_allocator;
|
|
||||||
// VFALCO This needs work
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
test_allocator<char, false, false, false, false, false>;
|
|
||||||
using type = basic_multi_buffer<alloc_type>;
|
|
||||||
type b;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
test_allocator<char, false, false, false, false, false>;
|
|
||||||
using type = basic_multi_buffer<alloc_type>;
|
|
||||||
type b;
|
|
||||||
type b2(b);
|
|
||||||
type b3(b, alloc_type{});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testMatrix()
|
|
||||||
{
|
{
|
||||||
|
using namespace test;
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
std::string const s = "Hello, world";
|
std::string const s = "Hello, world";
|
||||||
@@ -146,7 +114,7 @@ public:
|
|||||||
std::size_t z = s.size() - (x + y);
|
std::size_t z = s.size() - (x + y);
|
||||||
std::size_t v = s.size() - (t + u);
|
std::size_t v = s.size() - (t + u);
|
||||||
{
|
{
|
||||||
multi_buffer b;//(i);
|
multi_buffer b;
|
||||||
{
|
{
|
||||||
auto d = b.prepare(z);
|
auto d = b.prepare(z);
|
||||||
BEAST_EXPECT(buffer_size(d) == z);
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
@@ -226,7 +194,8 @@ public:
|
|||||||
}}}}}
|
}}}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void testIterators()
|
void
|
||||||
|
testIterators()
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
@@ -240,14 +209,384 @@ public:
|
|||||||
b.commit(2);
|
b.commit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
void
|
||||||
|
testMembers()
|
||||||
|
{
|
||||||
|
using namespace test;
|
||||||
|
|
||||||
|
// compare equal
|
||||||
|
using equal_t = test::test_allocator<char,
|
||||||
|
true, true, true, true, true>;
|
||||||
|
|
||||||
|
// compare not equal
|
||||||
|
using unequal_t = test::test_allocator<char,
|
||||||
|
false, true, true, true, true>;
|
||||||
|
|
||||||
|
// construction
|
||||||
|
{
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
BEAST_EXPECT(b.capacity() == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
multi_buffer b{500};
|
||||||
|
BEAST_EXPECT(b.capacity() == 0);
|
||||||
|
BEAST_EXPECT(b.max_size() == 500);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
unequal_t a1;
|
||||||
|
basic_multi_buffer<unequal_t> b{a1};
|
||||||
|
BEAST_EXPECT(b.get_allocator() == a1);
|
||||||
|
BEAST_EXPECT(b.get_allocator() != unequal_t{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// move construction
|
||||||
|
{
|
||||||
|
{
|
||||||
|
basic_multi_buffer<equal_t> b1{30};
|
||||||
|
BEAST_EXPECT(b1.get_allocator()->nmove == 0);
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<equal_t> b2{std::move(b1)};
|
||||||
|
BEAST_EXPECT(b2.get_allocator()->nmove == 1);
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(b1.capacity() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(b1.max_size() == b2.max_size());
|
||||||
|
}
|
||||||
|
// allocators equal
|
||||||
|
{
|
||||||
|
basic_multi_buffer<equal_t> b1{30};
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
equal_t a;
|
||||||
|
basic_multi_buffer<equal_t> b2{std::move(b1), a};
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(b1.capacity() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(b1.max_size() == b2.max_size());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// allocators unequal
|
||||||
|
basic_multi_buffer<unequal_t> b1{30};
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
unequal_t a;
|
||||||
|
basic_multi_buffer<unequal_t> b2{std::move(b1), a};
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(b1.capacity() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(b1.max_size() == b2.max_size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy construction
|
||||||
|
{
|
||||||
|
{
|
||||||
|
basic_multi_buffer<equal_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<equal_t> b2{b1};
|
||||||
|
BEAST_EXPECT(b1.get_allocator() == b2.get_allocator());
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
basic_multi_buffer<unequal_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
unequal_t a;
|
||||||
|
basic_multi_buffer<unequal_t> b2(b1, a);
|
||||||
|
BEAST_EXPECT(b1.get_allocator() != b2.get_allocator());
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
basic_multi_buffer<equal_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<unequal_t> b2(b1);
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
basic_multi_buffer<unequal_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
equal_t a;
|
||||||
|
basic_multi_buffer<equal_t> b2(b1, a);
|
||||||
|
BEAST_EXPECT(b2.get_allocator() == a);
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// move assignment
|
||||||
|
{
|
||||||
|
{
|
||||||
|
multi_buffer b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
multi_buffer b2;
|
||||||
|
b2 = std::move(b1);
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(b1.capacity() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// propagate_on_container_move_assignment : true
|
||||||
|
using pocma_t = test::test_allocator<char,
|
||||||
|
true, true, true, true, true>;
|
||||||
|
basic_multi_buffer<pocma_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<pocma_t> b2;
|
||||||
|
b2 = std::move(b1);
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// propagate_on_container_move_assignment : false
|
||||||
|
using pocma_t = test::test_allocator<char,
|
||||||
|
true, true, false, true, true>;
|
||||||
|
basic_multi_buffer<pocma_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<pocma_t> b2;
|
||||||
|
b2 = std::move(b1);
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy assignment
|
||||||
|
{
|
||||||
|
{
|
||||||
|
multi_buffer b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
multi_buffer b2;
|
||||||
|
b2 = b1;
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
basic_multi_buffer<equal_t> b3;
|
||||||
|
b3 = b2;
|
||||||
|
BEAST_EXPECT(to_string(b3.data()) == "Hello");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// propagate_on_container_copy_assignment : true
|
||||||
|
using pocca_t = test::test_allocator<char,
|
||||||
|
true, true, true, true, true>;
|
||||||
|
basic_multi_buffer<pocca_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<pocca_t> b2;
|
||||||
|
b2 = b1;
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// propagate_on_container_copy_assignment : false
|
||||||
|
using pocca_t = test::test_allocator<char,
|
||||||
|
true, false, true, true, true>;
|
||||||
|
basic_multi_buffer<pocca_t> b1;
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<pocca_t> b2;
|
||||||
|
b2 = b1;
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare
|
||||||
|
{
|
||||||
|
{
|
||||||
|
multi_buffer b{100};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
b.prepare(b.max_size() + 1);
|
||||||
|
fail("", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
catch(std::length_error const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
string_view const s = "Hello, world!";
|
||||||
|
multi_buffer b1{64};
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(b1.max_size() == 64);
|
||||||
|
BEAST_EXPECT(b1.capacity() == 0);
|
||||||
|
ostream(b1) << s;
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == s);
|
||||||
|
{
|
||||||
|
multi_buffer b2{b1};
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s);
|
||||||
|
b2.consume(7);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s.substr(7));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
multi_buffer b2{64};
|
||||||
|
b2 = b1;
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s);
|
||||||
|
b2.consume(7);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s.substr(7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.commit(1);
|
||||||
|
BEAST_EXPECT(b.size() == 1);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.size() == 1);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(1500);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.commit(1);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(2000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 2000);
|
||||||
|
b.commit(2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(2000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 2000);
|
||||||
|
b.prepare(4000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 4000);
|
||||||
|
b.prepare(50);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// commit
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.commit(1000);
|
||||||
|
BEAST_EXPECT(b.size() == 1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.consume(1000);
|
||||||
|
BEAST_EXPECT(b.size() == 0);
|
||||||
|
BEAST_EXPECT(b.capacity() == 0);
|
||||||
|
b.prepare(1000);
|
||||||
|
b.commit(650);
|
||||||
|
BEAST_EXPECT(b.size() == 650);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1650);
|
||||||
|
b.commit(100);
|
||||||
|
BEAST_EXPECT(b.size() == 750);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 2000);
|
||||||
|
b.commit(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume
|
||||||
|
{
|
||||||
|
multi_buffer b;
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.commit(1000);
|
||||||
|
BEAST_EXPECT(b.size() == 1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 1000);
|
||||||
|
b.prepare(1000);
|
||||||
|
BEAST_EXPECT(b.capacity() >= 2000);
|
||||||
|
b.commit(750);
|
||||||
|
BEAST_EXPECT(b.size() == 1750);
|
||||||
|
b.consume(500);
|
||||||
|
BEAST_EXPECT(b.size() == 1250);
|
||||||
|
b.consume(500);
|
||||||
|
BEAST_EXPECT(b.size() == 750);
|
||||||
|
b.prepare(250);
|
||||||
|
b.consume(750);
|
||||||
|
BEAST_EXPECT(b.size() == 0);
|
||||||
|
b.prepare(1000);
|
||||||
|
b.commit(800);
|
||||||
|
BEAST_EXPECT(b.size() == 800);
|
||||||
|
b.prepare(1000);
|
||||||
|
b.commit(600);
|
||||||
|
BEAST_EXPECT(b.size() == 1400);
|
||||||
|
b.consume(1400);
|
||||||
|
BEAST_EXPECT(b.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// propagate_on_container_swap : true
|
||||||
|
using pocs_t = test::test_allocator<char,
|
||||||
|
false, true, true, true, true>;
|
||||||
|
pocs_t a1, a2;
|
||||||
|
BEAST_EXPECT(a1 != a2);
|
||||||
|
basic_multi_buffer<pocs_t> b1{a1};
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<pocs_t> b2{a2};
|
||||||
|
BEAST_EXPECT(b1.get_allocator() == a1);
|
||||||
|
BEAST_EXPECT(b2.get_allocator() == a2);
|
||||||
|
swap(b1, b2);
|
||||||
|
BEAST_EXPECT(b1.get_allocator() == a2);
|
||||||
|
BEAST_EXPECT(b2.get_allocator() == a1);
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
swap(b1, b2);
|
||||||
|
BEAST_EXPECT(b1.get_allocator() == a1);
|
||||||
|
BEAST_EXPECT(b2.get_allocator() == a2);
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(b2.size() == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// propagate_on_container_swap : false
|
||||||
|
using pocs_t = test::test_allocator<char,
|
||||||
|
true, true, true, false, true>;
|
||||||
|
pocs_t a1, a2;
|
||||||
|
BEAST_EXPECT(a1 == a2);
|
||||||
|
BEAST_EXPECT(a1.id() != a2.id());
|
||||||
|
basic_multi_buffer<pocs_t> b1{a1};
|
||||||
|
ostream(b1) << "Hello";
|
||||||
|
basic_multi_buffer<pocs_t> b2{a2};
|
||||||
|
BEAST_EXPECT(b1.get_allocator() == a1);
|
||||||
|
BEAST_EXPECT(b2.get_allocator() == a2);
|
||||||
|
swap(b1, b2);
|
||||||
|
BEAST_EXPECT(b1.get_allocator().id() == a1.id());
|
||||||
|
BEAST_EXPECT(b2.get_allocator().id() == a2.id());
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == "Hello");
|
||||||
|
swap(b1, b2);
|
||||||
|
BEAST_EXPECT(b1.get_allocator().id() == a1.id());
|
||||||
|
BEAST_EXPECT(b2.get_allocator().id() == a2.id());
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == "Hello");
|
||||||
|
BEAST_EXPECT(b2.size() == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read_size_helper
|
||||||
|
{
|
||||||
|
using detail::read_size_helper;
|
||||||
|
multi_buffer b{10};
|
||||||
|
BEAST_EXPECT(read_size_helper(b, 512) == 10);
|
||||||
|
b.prepare(4);
|
||||||
|
b.commit(4);
|
||||||
|
BEAST_EXPECT(read_size_helper(b, 512) == 6);
|
||||||
|
b.consume(2);
|
||||||
|
BEAST_EXPECT(read_size_helper(b, 512) == 8);
|
||||||
|
b.prepare(8);
|
||||||
|
b.commit(8);
|
||||||
|
BEAST_EXPECT(read_size_helper(b, 512) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
run() override
|
||||||
{
|
{
|
||||||
test::check_read_size_helper<multi_buffer>();
|
test::check_read_size_helper<multi_buffer>();
|
||||||
|
|
||||||
testSpecialMembers();
|
testMatrix1();
|
||||||
testAllocator();
|
testMatrix2();
|
||||||
testMatrix();
|
|
||||||
testIterators();
|
testIterators();
|
||||||
|
testMembers();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user