forked from boostorg/beast
Fix and refactor buffers_cat:
Elements of zero size are correctly skipped during iteration. * Tidy up tests * Increase code coverage * Remove move special members * Correct behavior for default constructed iterators
This commit is contained in:
@@ -5,6 +5,7 @@ Version 200
|
|||||||
* buffers_cat fixes and coverage
|
* buffers_cat fixes and coverage
|
||||||
* Refactor buffers_adaptor
|
* Refactor buffers_adaptor
|
||||||
* Refactor buffers_range
|
* Refactor buffers_range
|
||||||
|
* Fix and refactor buffers_cat
|
||||||
|
|
||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
|
@@ -46,15 +46,9 @@ public:
|
|||||||
/// Copy Constructor
|
/// Copy Constructor
|
||||||
buffers_cat_view(buffers_cat_view const&) = default;
|
buffers_cat_view(buffers_cat_view const&) = default;
|
||||||
|
|
||||||
/// Move Constructor
|
|
||||||
buffers_cat_view(buffers_cat_view&&) = default;
|
|
||||||
|
|
||||||
/// Copy Assignment
|
/// Copy Assignment
|
||||||
buffers_cat_view& operator=(buffers_cat_view const&) = default;
|
buffers_cat_view& operator=(buffers_cat_view const&) = default;
|
||||||
|
|
||||||
/// Move Assignment
|
|
||||||
buffers_cat_view& operator=(buffers_cat_view&&) = default;
|
|
||||||
|
|
||||||
/** Constructor
|
/** Constructor
|
||||||
|
|
||||||
@param buffers The list of buffer sequences to concatenate.
|
@param buffers The list of buffer sequences to concatenate.
|
||||||
|
@@ -35,6 +35,7 @@ struct buffers_cat_view_iterator_base
|
|||||||
net::mutable_buffer
|
net::mutable_buffer
|
||||||
operator*() const
|
operator*() const
|
||||||
{
|
{
|
||||||
|
// Dereferencing a one-past-the-end iterator
|
||||||
BOOST_THROW_EXCEPTION(std::logic_error{
|
BOOST_THROW_EXCEPTION(std::logic_error{
|
||||||
"invalid iterator"});
|
"invalid iterator"});
|
||||||
}
|
}
|
||||||
@@ -77,9 +78,7 @@ public:
|
|||||||
std::bidirectional_iterator_tag;
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
const_iterator() = default;
|
const_iterator() = default;
|
||||||
const_iterator(const_iterator&& other) = default;
|
|
||||||
const_iterator(const_iterator const& other) = default;
|
const_iterator(const_iterator const& other) = default;
|
||||||
const_iterator& operator=(const_iterator&& other) = default;
|
|
||||||
const_iterator& operator=(const_iterator const& other) = default;
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -103,11 +102,9 @@ public:
|
|||||||
const_iterator
|
const_iterator
|
||||||
operator++(int);
|
operator++(int);
|
||||||
|
|
||||||
// deprecated
|
|
||||||
const_iterator&
|
const_iterator&
|
||||||
operator--();
|
operator--();
|
||||||
|
|
||||||
// deprecated
|
|
||||||
const_iterator
|
const_iterator
|
||||||
operator--(int);
|
operator--(int);
|
||||||
|
|
||||||
@@ -115,53 +112,6 @@ private:
|
|||||||
const_iterator(
|
const_iterator(
|
||||||
detail::tuple<Bn...> const& bn, bool at_end);
|
detail::tuple<Bn...> const& bn, bool at_end);
|
||||||
|
|
||||||
template<std::size_t I>
|
|
||||||
void
|
|
||||||
next(C<I> const&)
|
|
||||||
{
|
|
||||||
if(net::buffer_size(
|
|
||||||
detail::get<I>(*bn_)) != 0)
|
|
||||||
{
|
|
||||||
it_.template emplace<I+1>(
|
|
||||||
net::buffer_sequence_begin(
|
|
||||||
detail::get<I>(*bn_)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
next(C<I+1>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
next(C<sizeof...(Bn)> const&)
|
|
||||||
{
|
|
||||||
// end
|
|
||||||
auto constexpr I = sizeof...(Bn);
|
|
||||||
it_.template emplace<I+1>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t I>
|
|
||||||
void
|
|
||||||
prev(C<I> const&)
|
|
||||||
{
|
|
||||||
if(net::buffer_size(
|
|
||||||
detail::get<I>(*bn_)) != 0)
|
|
||||||
{
|
|
||||||
it_.template emplace<I+1>(
|
|
||||||
net::buffer_sequence_end(
|
|
||||||
detail::get<I>(*bn_)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prev(C<I-1>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prev(C<0> const&)
|
|
||||||
{
|
|
||||||
auto constexpr I = 0;
|
|
||||||
it_.template emplace<I+1>(
|
|
||||||
net::buffer_sequence_end(
|
|
||||||
detail::get<I>(*bn_)));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dereference
|
struct dereference
|
||||||
{
|
{
|
||||||
const_iterator const& self;
|
const_iterator const& self;
|
||||||
@@ -190,15 +140,107 @@ private:
|
|||||||
void
|
void
|
||||||
operator()(mp11::mp_size_t<0>)
|
operator()(mp11::mp_size_t<0>)
|
||||||
{
|
{
|
||||||
|
// Incrementing a default-constructed iterator
|
||||||
BOOST_THROW_EXCEPTION(std::logic_error{
|
BOOST_THROW_EXCEPTION(std::logic_error{
|
||||||
"invalid iterator"});
|
"invalid iterator"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
operator()(mp11::mp_size_t<I>)
|
||||||
|
{
|
||||||
|
++self.it_.template get<I>();
|
||||||
|
next(mp11::mp_size_t<I>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
next(mp11::mp_size_t<I>)
|
||||||
|
{
|
||||||
|
auto& it = self.it_.template get<I>();
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if (it == net::buffer_sequence_end(
|
||||||
|
detail::get<I-1>(*self.bn_)))
|
||||||
|
break;
|
||||||
|
if(net::const_buffer(*it).size() > 0)
|
||||||
|
return;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
self.it_.template emplace<I+1>(
|
||||||
|
net::buffer_sequence_begin(
|
||||||
|
detail::get<I>(*self.bn_)));
|
||||||
|
next(mp11::mp_size_t<I+1>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(mp11::mp_size_t<sizeof...(Bn)>)
|
||||||
|
{
|
||||||
|
auto constexpr I = sizeof...(Bn);
|
||||||
|
++self.it_.template get<I>();
|
||||||
|
next(mp11::mp_size_t<I>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
next(mp11::mp_size_t<sizeof...(Bn)>)
|
||||||
|
{
|
||||||
|
auto constexpr I = sizeof...(Bn);
|
||||||
|
auto& it = self.it_.template get<I>();
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if (it == net::buffer_sequence_end(
|
||||||
|
detail::get<I-1>(*self.bn_)))
|
||||||
|
break;
|
||||||
|
if(net::const_buffer(*it).size() > 0)
|
||||||
|
return;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
// end
|
||||||
|
self.it_.template emplace<I+1>();
|
||||||
|
}
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void
|
void
|
||||||
operator()(mp11::mp_size_t<sizeof...(Bn) + 1>)
|
operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
|
||||||
{
|
{
|
||||||
(*this)(mp11::mp_size_t<0>{});
|
// Incrementing a one-past-the-end iterator
|
||||||
|
BOOST_THROW_EXCEPTION(std::logic_error{
|
||||||
|
"invalid iterator"});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct decrement
|
||||||
|
{
|
||||||
|
const_iterator& self;
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void
|
||||||
|
operator()(mp11::mp_size_t<0>)
|
||||||
|
{
|
||||||
|
// Decrementing a default-constructed iterator
|
||||||
|
BOOST_THROW_EXCEPTION(std::logic_error{
|
||||||
|
"invalid iterator"});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(mp11::mp_size_t<1>)
|
||||||
|
{
|
||||||
|
auto constexpr I = 1;
|
||||||
|
|
||||||
|
auto& it = self.it_.template get<I>();
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if(it == net::buffer_sequence_begin(
|
||||||
|
detail::get<I-1>(*self.bn_)))
|
||||||
|
{
|
||||||
|
// Decrementing an iterator to the beginning
|
||||||
|
BOOST_THROW_EXCEPTION(std::logic_error{
|
||||||
|
"invalid iterator"});
|
||||||
|
}
|
||||||
|
--it;
|
||||||
|
if(net::const_buffer(*it).size() > 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
@@ -206,53 +248,31 @@ private:
|
|||||||
operator()(mp11::mp_size_t<I>)
|
operator()(mp11::mp_size_t<I>)
|
||||||
{
|
{
|
||||||
auto& it = self.it_.template get<I>();
|
auto& it = self.it_.template get<I>();
|
||||||
if (++it == net::buffer_sequence_end(
|
for(;;)
|
||||||
detail::get<I - 1>(*self.bn_)))
|
{
|
||||||
self.next(C<I>());
|
if(it == net::buffer_sequence_begin(
|
||||||
|
detail::get<I-1>(*self.bn_)))
|
||||||
|
break;
|
||||||
|
--it;
|
||||||
|
if(net::const_buffer(*it).size() > 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.it_.template emplace<I-1>(
|
||||||
|
net::buffer_sequence_end(
|
||||||
|
detail::get<I-2>(*self.bn_)));
|
||||||
|
(*this)(mp11::mp_size_t<I-1>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
|
||||||
|
{
|
||||||
|
auto constexpr I = sizeof...(Bn)+1;
|
||||||
|
self.it_.template emplace<I-1>(
|
||||||
|
net::buffer_sequence_end(
|
||||||
|
detail::get<I-2>(*self.bn_)));
|
||||||
|
(*this)(mp11::mp_size_t<I-1>{});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
|
||||||
decrement(C<sizeof...(Bn)> const&)
|
|
||||||
{
|
|
||||||
auto constexpr I = sizeof...(Bn);
|
|
||||||
if(it_.index() == I+1)
|
|
||||||
prev(C<I-1>{});
|
|
||||||
decrement(C<I-1>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t I>
|
|
||||||
void
|
|
||||||
decrement(C<I> const&)
|
|
||||||
{
|
|
||||||
if(it_.index() == I+1)
|
|
||||||
{
|
|
||||||
if(it_.template get<I+1>() !=
|
|
||||||
net::buffer_sequence_begin(
|
|
||||||
detail::get<I>(*bn_)))
|
|
||||||
{
|
|
||||||
--it_.template get<I+1>();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prev(C<I-1>{});
|
|
||||||
}
|
|
||||||
decrement(C<I-1>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
decrement(C<0> const&)
|
|
||||||
{
|
|
||||||
auto constexpr I = 0;
|
|
||||||
if(it_.template get<I+1>() !=
|
|
||||||
net::buffer_sequence_begin(
|
|
||||||
detail::get<I>(*bn_)))
|
|
||||||
{
|
|
||||||
--it_.template get<I+1>();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BOOST_THROW_EXCEPTION(std::logic_error{
|
|
||||||
"invalid iterator"});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -265,9 +285,17 @@ const_iterator(
|
|||||||
: bn_(&bn)
|
: bn_(&bn)
|
||||||
{
|
{
|
||||||
if(! at_end)
|
if(! at_end)
|
||||||
next(C<0>{});
|
{
|
||||||
|
it_.template emplace<1>(
|
||||||
|
net::buffer_sequence_begin(
|
||||||
|
detail::get<0>(*bn_)));
|
||||||
|
increment{*this}.next(
|
||||||
|
mp11::mp_size_t<1>{});
|
||||||
|
}
|
||||||
else
|
else
|
||||||
next(C<sizeof...(Bn)>{});
|
{
|
||||||
|
it_.template emplace<sizeof...(Bn)+1>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class... Bn>
|
template<class... Bn>
|
||||||
@@ -276,20 +304,7 @@ buffers_cat_view<Bn...>::
|
|||||||
const_iterator::
|
const_iterator::
|
||||||
operator==(const_iterator const& other) const
|
operator==(const_iterator const& other) const
|
||||||
{
|
{
|
||||||
return
|
return bn_ == other.bn_ && it_ == other.it_;
|
||||||
(bn_ == nullptr) ?
|
|
||||||
(
|
|
||||||
other.bn_ == nullptr ||
|
|
||||||
other.it_.index() == sizeof...(Bn) + 1
|
|
||||||
):(
|
|
||||||
(other.bn_ == nullptr) ?
|
|
||||||
(
|
|
||||||
it_.index() == sizeof...(Bn) + 1
|
|
||||||
): (
|
|
||||||
bn_ == other.bn_ &&
|
|
||||||
it_ == other.it_
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class... Bn>
|
template<class... Bn>
|
||||||
@@ -338,7 +353,10 @@ const_iterator::
|
|||||||
operator--() ->
|
operator--() ->
|
||||||
const_iterator&
|
const_iterator&
|
||||||
{
|
{
|
||||||
decrement(C<sizeof...(Bn)>{});
|
mp11::mp_with_index<
|
||||||
|
sizeof...(Bn) + 2>(
|
||||||
|
it_.index(),
|
||||||
|
decrement{*this});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +383,6 @@ buffers_cat_view(Bn const&... bn)
|
|||||||
|
|
||||||
|
|
||||||
template<class... Bn>
|
template<class... Bn>
|
||||||
inline
|
|
||||||
auto
|
auto
|
||||||
buffers_cat_view<Bn...>::begin() const ->
|
buffers_cat_view<Bn...>::begin() const ->
|
||||||
const_iterator
|
const_iterator
|
||||||
@@ -374,7 +391,6 @@ buffers_cat_view<Bn...>::begin() const ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class... Bn>
|
template<class... Bn>
|
||||||
inline
|
|
||||||
auto
|
auto
|
||||||
buffers_cat_view<Bn...>::end() const->
|
buffers_cat_view<Bn...>::end() const->
|
||||||
const_iterator
|
const_iterator
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <boost/beast/core/buffers_cat.hpp>
|
#include <boost/beast/core/buffers_cat.hpp>
|
||||||
|
|
||||||
|
#include "buffer_test.hpp"
|
||||||
|
|
||||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
#include <boost/beast/core/buffers_prefix.hpp>
|
#include <boost/beast/core/buffers_prefix.hpp>
|
||||||
#include <boost/beast/core/buffers_suffix.hpp>
|
#include <boost/beast/core/buffers_suffix.hpp>
|
||||||
@@ -26,213 +28,17 @@ namespace beast {
|
|||||||
class buffers_cat_test : public unit_test::suite
|
class buffers_cat_test : public unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<class Iterator>
|
|
||||||
static
|
|
||||||
std::reverse_iterator<Iterator>
|
|
||||||
make_reverse_iterator(Iterator i)
|
|
||||||
{
|
|
||||||
return std::reverse_iterator<Iterator>(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
static
|
static
|
||||||
std::size_t
|
std::size_t
|
||||||
bsize1(ConstBufferSequence const& bs)
|
buffers_length(
|
||||||
|
ConstBufferSequence const& buffers)
|
||||||
{
|
{
|
||||||
using net::buffer_size;
|
return std::distance(
|
||||||
std::size_t n = 0;
|
net::buffer_sequence_begin(buffers),
|
||||||
for(auto it = bs.begin(); it != bs.end(); ++it)
|
net::buffer_sequence_end(buffers));
|
||||||
n += buffer_size(*it);
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
static
|
|
||||||
std::size_t
|
|
||||||
bsize2(ConstBufferSequence const& bs)
|
|
||||||
{
|
|
||||||
using net::buffer_size;
|
|
||||||
std::size_t n = 0;
|
|
||||||
for(auto it = bs.begin(); it != bs.end(); it++)
|
|
||||||
n += buffer_size(*it);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
static
|
|
||||||
std::size_t
|
|
||||||
bsize3(ConstBufferSequence const& bs)
|
|
||||||
{
|
|
||||||
using net::buffer_size;
|
|
||||||
std::size_t n = 0;
|
|
||||||
for(auto it = bs.end(); it != bs.begin();)
|
|
||||||
n += buffer_size(*--it);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
static
|
|
||||||
std::size_t
|
|
||||||
bsize4(ConstBufferSequence const& bs)
|
|
||||||
{
|
|
||||||
using net::buffer_size;
|
|
||||||
std::size_t n = 0;
|
|
||||||
for(auto it = bs.end(); it != bs.begin();)
|
|
||||||
{
|
|
||||||
it--;
|
|
||||||
n += buffer_size(*it);
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testBufferCat()
|
|
||||||
{
|
|
||||||
using net::buffer_size;
|
|
||||||
using net::const_buffer;
|
|
||||||
char buf[10];
|
|
||||||
std::list<const_buffer> b1;
|
|
||||||
std::vector<const_buffer> b2{
|
|
||||||
const_buffer{buf+0, 1},
|
|
||||||
const_buffer{buf+1, 2}};
|
|
||||||
std::list<const_buffer> b3;
|
|
||||||
std::array<const_buffer, 3> b4{{
|
|
||||||
const_buffer{buf+3, 1},
|
|
||||||
const_buffer{buf+4, 2},
|
|
||||||
const_buffer{buf+6, 3}}};
|
|
||||||
std::list<const_buffer> b5{
|
|
||||||
const_buffer{buf+9, 1}};
|
|
||||||
std::list<const_buffer> b6;
|
|
||||||
auto bs = buffers_cat(
|
|
||||||
b1, b2, b3, b4, b5, b6);
|
|
||||||
BEAST_EXPECT(buffer_size(bs) == 10);
|
|
||||||
BEAST_EXPECT(bsize1(bs) == 10);
|
|
||||||
BEAST_EXPECT(bsize2(bs) == 10);
|
|
||||||
BEAST_EXPECT(bsize3(bs) == 10);
|
|
||||||
BEAST_EXPECT(bsize4(bs) == 10);
|
|
||||||
std::vector<const_buffer> v;
|
|
||||||
for(auto iter = make_reverse_iterator(bs.end());
|
|
||||||
iter != make_reverse_iterator(bs.begin()); ++iter)
|
|
||||||
v.emplace_back(*iter);
|
|
||||||
BEAST_EXPECT(buffer_size(bs) == 10);
|
|
||||||
decltype(bs) bs2(bs);
|
|
||||||
auto bs3(std::move(bs));
|
|
||||||
{
|
|
||||||
net::streambuf sb1, sb2;
|
|
||||||
BEAST_EXPECT(buffer_size(buffers_cat(
|
|
||||||
sb1.prepare(5), sb2.prepare(7))) == 12);
|
|
||||||
sb1.commit(5);
|
|
||||||
sb2.commit(7);
|
|
||||||
BEAST_EXPECT(buffer_size(buffers_cat(
|
|
||||||
sb1.data(), sb2.data())) == 12);
|
|
||||||
}
|
|
||||||
for(auto it = bs.begin(); it != bs.end(); ++it)
|
|
||||||
{
|
|
||||||
decltype(bs)::const_iterator copy;
|
|
||||||
copy = it;
|
|
||||||
BEAST_EXPECT(copy == it);
|
|
||||||
auto copy2 = copy;
|
|
||||||
BEAST_EXPECT(copy2 == it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testIterators()
|
|
||||||
{
|
|
||||||
using net::buffer_size;
|
|
||||||
using net::const_buffer;
|
|
||||||
char buf[9];
|
|
||||||
std::vector<const_buffer> b1{
|
|
||||||
const_buffer{buf+0, 1},
|
|
||||||
const_buffer{buf+1, 2}};
|
|
||||||
std::array<const_buffer, 3> b2{{
|
|
||||||
const_buffer{buf+3, 1},
|
|
||||||
const_buffer{buf+4, 2},
|
|
||||||
const_buffer{buf+6, 3}}};
|
|
||||||
auto bs = buffers_cat(b1, b2);
|
|
||||||
for(int n = 0;
|
|
||||||
n <= std::distance(bs.begin(), bs.end()); ++n)
|
|
||||||
{
|
|
||||||
auto it = std::next(bs.begin(), n);
|
|
||||||
decltype(it) it2(std::move(it));
|
|
||||||
it = std::move(it2);
|
|
||||||
auto pit = ⁢
|
|
||||||
it = std::move(*pit);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::size_t n = 0;
|
|
||||||
for(auto it = bs.begin(); n < 100; ++it)
|
|
||||||
++n;
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
catch(std::exception const&)
|
|
||||||
{
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrement iterator
|
|
||||||
/* VFALCO
|
|
||||||
This causes a mysterious "uninitialized variable"
|
|
||||||
warning related to this function (see comment)
|
|
||||||
https://code.woboq.org/qt5/include/c++/6.3.1/bits/stl_iterator.h.html#159
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
auto const rbegin =
|
|
||||||
make_reverse_iterator(bs.end());
|
|
||||||
auto const rend =
|
|
||||||
make_reverse_iterator(bs.begin());
|
|
||||||
std::size_t n = 0;
|
|
||||||
for(auto it = rbegin; it != rend; ++it)
|
|
||||||
n += buffer_size(*it);
|
|
||||||
BEAST_EXPECT(n == 9);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::size_t n = 0;
|
|
||||||
for(auto it = bs.end(); n < 100; --it)
|
|
||||||
++n;
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
catch(std::exception const&)
|
|
||||||
{
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
buffer_size(*bs.end());
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
catch(std::exception const&)
|
|
||||||
{
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
auto bs2 = bs;
|
|
||||||
BEAST_EXPECT(bs.begin() != bs2.begin());
|
|
||||||
BEAST_EXPECT(bs.end() != bs2.end());
|
|
||||||
decltype(bs)::const_iterator it;
|
|
||||||
decltype(bs2)::const_iterator it2;
|
|
||||||
BEAST_EXPECT(it == it2);
|
|
||||||
|
|
||||||
// decrement begin() should throw
|
|
||||||
try
|
|
||||||
{
|
|
||||||
--bs.begin();
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
catch(std::logic_error const&)
|
|
||||||
{
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
testDefaultIterators()
|
testDefaultIterators()
|
||||||
{
|
{
|
||||||
@@ -275,6 +81,209 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testBufferSequence()
|
||||||
|
{
|
||||||
|
string_view s = "Hello, world!";
|
||||||
|
net::const_buffer b1(s.data(), 6);
|
||||||
|
net::const_buffer b2(
|
||||||
|
s.data() + b1.size(), s.size() - b1.size());
|
||||||
|
test_buffer_sequence(
|
||||||
|
*this, buffers_cat(b1, b2));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F>
|
||||||
|
void
|
||||||
|
checkException(F&& f)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
f();
|
||||||
|
fail("missing exception", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
catch(std::logic_error const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
fail("wrong exception", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testExceptions()
|
||||||
|
{
|
||||||
|
net::const_buffer b1{"He", 2};
|
||||||
|
net::const_buffer b2{"llo,", 4};
|
||||||
|
net::const_buffer b3{" world!", 7};
|
||||||
|
|
||||||
|
auto const b = beast::buffers_cat(b1, b2, b3);
|
||||||
|
|
||||||
|
// Dereferencing a default-constructed iterator
|
||||||
|
checkException(
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
*(decltype(b)::const_iterator{});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Incrementing a default-constructed iterator
|
||||||
|
checkException(
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
++(decltype(b)::const_iterator{});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Decrementing a default-constructed iterator
|
||||||
|
checkException(
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
--(decltype(b)::const_iterator{});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Decrementing an iterator to the beginning
|
||||||
|
checkException(
|
||||||
|
[&b]
|
||||||
|
{
|
||||||
|
--b.begin();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dereferencing an iterator to the end
|
||||||
|
checkException(
|
||||||
|
[&b]
|
||||||
|
{
|
||||||
|
*b.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Incrementing an iterator to the end
|
||||||
|
checkException(
|
||||||
|
[&b]
|
||||||
|
{
|
||||||
|
++b.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testEmpty()
|
||||||
|
{
|
||||||
|
using net::buffer_size;
|
||||||
|
|
||||||
|
struct empty_sequence
|
||||||
|
{
|
||||||
|
using value_type = net::const_buffer;
|
||||||
|
using const_iterator = value_type const*;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
begin() const noexcept
|
||||||
|
{
|
||||||
|
return &v_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
end() const noexcept
|
||||||
|
{
|
||||||
|
return begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
value_type v_;
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
net::const_buffer b0{};
|
||||||
|
net::const_buffer b1{"He", 2};
|
||||||
|
net::const_buffer b2{"llo,", 4};
|
||||||
|
net::const_buffer b3{" world!", 7};
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(b0, b0);
|
||||||
|
BEAST_EXPECT(buffer_size(b) == 0);
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(b0, b0, b0, b0);
|
||||||
|
BEAST_EXPECT(buffer_size(b) == 0);
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(b1, b2, b3);
|
||||||
|
BEAST_EXPECT(beast::buffers_to_string(b) == "Hello, world!");
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 3);
|
||||||
|
test_buffer_sequence(*this, b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(b0, b1, b2, b3);
|
||||||
|
BEAST_EXPECT(beast::buffers_to_string(b) == "Hello, world!");
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 3);
|
||||||
|
test_buffer_sequence(*this, b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(b1, b0, b2, b3);
|
||||||
|
BEAST_EXPECT(beast::buffers_to_string(b) == "Hello, world!");
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 3);
|
||||||
|
test_buffer_sequence(*this, b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(b1, b2, b0, b3);
|
||||||
|
BEAST_EXPECT(beast::buffers_to_string(b) == "Hello, world!");
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 3);
|
||||||
|
test_buffer_sequence(*this, b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(b1, b2, b3, b0);
|
||||||
|
BEAST_EXPECT(beast::buffers_to_string(b) == "Hello, world!");
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 3);
|
||||||
|
test_buffer_sequence(*this, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto e1 = net::const_buffer{};
|
||||||
|
auto b1 = std::array<net::const_buffer, 3>{{
|
||||||
|
e1,
|
||||||
|
net::const_buffer{"He", 2},
|
||||||
|
net::const_buffer{"l", 1} }};
|
||||||
|
auto b2 = std::array<net::const_buffer, 3>{{
|
||||||
|
net::const_buffer{"lo", 2},
|
||||||
|
e1,
|
||||||
|
net::const_buffer{", ", 2} }};
|
||||||
|
auto b3 = std::array<net::const_buffer, 3>{{
|
||||||
|
net::const_buffer{"w", 1},
|
||||||
|
net::const_buffer{"orld!", 5},
|
||||||
|
e1 }};
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(
|
||||||
|
e1, b1, e1, b2, e1, b3, e1);
|
||||||
|
BEAST_EXPECT(beast::buffers_to_string(b) == "Hello, world!");
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto e1 = net::const_buffer{};
|
||||||
|
auto e2 = empty_sequence{};
|
||||||
|
auto b1 = std::array<net::const_buffer, 3>{{
|
||||||
|
e1,
|
||||||
|
net::const_buffer{"He", 2},
|
||||||
|
net::const_buffer{"l", 1} }};
|
||||||
|
auto b2 = std::array<net::const_buffer, 3>{{
|
||||||
|
net::const_buffer{"lo", 2},
|
||||||
|
e1,
|
||||||
|
net::const_buffer{", ", 2} }};
|
||||||
|
auto b3 = std::array<net::const_buffer, 3>{
|
||||||
|
net::const_buffer{"w", 1},
|
||||||
|
net::const_buffer{"orld!", 5},
|
||||||
|
e1
|
||||||
|
};
|
||||||
|
{
|
||||||
|
auto const b = beast::buffers_cat(
|
||||||
|
e2, b1, e2, b2, e2, b3, e2);
|
||||||
|
BEAST_EXPECT(beast::buffers_to_string(b) == "Hello, world!");
|
||||||
|
BEAST_EXPECT(buffers_length(b) == 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testGccWarning1()
|
testGccWarning1()
|
||||||
{
|
{
|
||||||
@@ -307,70 +316,20 @@ public:
|
|||||||
char out[64];
|
char out[64];
|
||||||
const_buffer buffers("Hello, world!", 13);
|
const_buffer buffers("Hello, world!", 13);
|
||||||
std::size_t i = 3;
|
std::size_t i = 3;
|
||||||
buffers_suffix<const_buffer> cb{buffers};
|
buffers_suffix<net::const_buffer> cb{buffers};
|
||||||
cb.consume(i);
|
cb.consume(i);
|
||||||
buffer_copy(
|
net::buffer_copy(
|
||||||
buffer(out),
|
net::buffer(out),
|
||||||
buffers_cat(buffers_prefix(i, buffers), cb));
|
buffers_cat(buffers_prefix(i, buffers), cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
test_empty_buffer_sequences()
|
|
||||||
{
|
|
||||||
using net::buffer_size;
|
|
||||||
using net::const_buffer;
|
|
||||||
std::vector<const_buffer> v1;
|
|
||||||
std::vector<const_buffer> v2;
|
|
||||||
BEAST_EXPECT(buffer_size(buffers_cat(v1, v2)) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
using net::const_buffer;
|
testBufferSequence();
|
||||||
using net::const_buffer;
|
testExceptions();
|
||||||
using net::mutable_buffer;
|
testEmpty();
|
||||||
struct user_defined : mutable_buffer
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check is_all_const_buffer_sequence
|
|
||||||
BOOST_STATIC_ASSERT(
|
|
||||||
detail::is_all_const_buffer_sequence<const_buffer>::value);
|
|
||||||
BOOST_STATIC_ASSERT(
|
|
||||||
detail::is_all_const_buffer_sequence<const_buffer, const_buffer>::value);
|
|
||||||
BOOST_STATIC_ASSERT(
|
|
||||||
detail::is_all_const_buffer_sequence<mutable_buffer, mutable_buffer>::value);
|
|
||||||
BOOST_STATIC_ASSERT(
|
|
||||||
detail::is_all_const_buffer_sequence<const_buffer, mutable_buffer>::value);
|
|
||||||
BOOST_STATIC_ASSERT(
|
|
||||||
! detail::is_all_const_buffer_sequence<const_buffer, mutable_buffer, int>::value);
|
|
||||||
|
|
||||||
// Ensure that concatenating mutable buffer
|
|
||||||
// sequences results in a mutable buffer sequence
|
|
||||||
BOOST_STATIC_ASSERT(std::is_same<
|
|
||||||
mutable_buffer,
|
|
||||||
decltype(buffers_cat(
|
|
||||||
std::declval<mutable_buffer>(),
|
|
||||||
std::declval<mutable_buffer>(),
|
|
||||||
std::declval<std::vector<mutable_buffer>>()
|
|
||||||
))::value_type>::value);
|
|
||||||
|
|
||||||
// Ensure that concatenating mixed buffer
|
|
||||||
// sequences results in a const buffer sequence.
|
|
||||||
BOOST_STATIC_ASSERT(std::is_same<
|
|
||||||
const_buffer,
|
|
||||||
decltype(buffers_cat(
|
|
||||||
std::declval<mutable_buffer>(),
|
|
||||||
std::declval<user_defined>(),
|
|
||||||
std::declval<const_buffer>()
|
|
||||||
))::value_type>::value);
|
|
||||||
|
|
||||||
testBufferCat();
|
|
||||||
testIterators();
|
|
||||||
testDefaultIterators();
|
|
||||||
testGccWarning1();
|
testGccWarning1();
|
||||||
testGccWarning2();
|
testGccWarning2();
|
||||||
test_empty_buffer_sequences();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user