Tidy up buffers_prefix and tests

This commit is contained in:
Vinnie Falco
2018-12-12 06:37:40 -08:00
parent f0cbf8276e
commit d0183da6d0
3 changed files with 257 additions and 211 deletions

View File

@@ -27,35 +27,27 @@ namespace beast {
a shorter subset of the original list of buffers starting
with the first byte of the original sequence.
@tparam BufferSequence The buffer sequence to adapt.
@tparam ConstBufferSequence The buffer sequence to adapt.
*/
template<class BufferSequence>
template<class ConstBufferSequence>
class buffers_prefix_view
{
using buffers_type = typename
std::decay<BufferSequence>::type;
using iter_type = typename
detail::buffer_sequence_iterator<buffers_type>::type;
detail::buffer_sequence_iterator<
ConstBufferSequence>::type;
BufferSequence bs_;
ConstBufferSequence bs_;
std::size_t size_;
std::size_t remain_;
iter_type end_;
template<class Deduced>
buffers_prefix_view(
Deduced&& other, std::size_t dist)
: bs_(std::forward<Deduced>(other).bs_)
, size_(other.size_)
, remain_(other.remain_)
, end_(std::next(bs_.begin(), dist))
{
}
void
setup(std::size_t size);
buffers_prefix_view(
buffers_prefix_view const& other,
std::size_t dist);
public:
/// The type for each element in the list of buffers.
using value_type = typename std::conditional<
@@ -74,22 +66,16 @@ public:
#endif
/// Move Constructor
buffers_prefix_view(buffers_prefix_view&&);
/// Copy Constructor
buffers_prefix_view(buffers_prefix_view const&);
/// Move Assignment
buffers_prefix_view& operator=(buffers_prefix_view&&);
/// Copy Assignment
buffers_prefix_view& operator=(buffers_prefix_view const&);
/** Construct a buffer sequence prefix.
@param size The maximum number of bytes in the prefix.
If this is larger than the size of passed, buffers,
If this is larger than the size of passed buffers,
the resulting sequence will represent the entire
input sequence.
@@ -100,16 +86,16 @@ public:
*/
buffers_prefix_view(
std::size_t size,
BufferSequence const& buffers);
ConstBufferSequence const& buffers);
/** Construct a buffer sequence prefix in-place.
@param size The maximum number of bytes in the prefix.
If this is larger than the size of passed, buffers,
If this is larger than the size of passed buffers,
the resulting sequence will represent the entire
input sequence.
@param args Arguments forwarded to the contained buffers constructor.
@param args Arguments forwarded to the contained buffer's constructor.
*/
template<class... Args>
buffers_prefix_view(
@@ -124,64 +110,29 @@ public:
/// Returns an iterator to one past the last buffer in the sequence
const_iterator
end() const;
#if ! BOOST_BEAST_DOXYGEN
template<class Buffers>
friend
std::size_t
buffer_size(buffers_prefix_view<Buffers> const& buffers);
#endif
};
#ifndef BOOST_BEAST_DOXYGEN
BOOST_BEAST_DECL
std::size_t
buffer_size(buffers_prefix_view<
net::const_buffer> const& buffers);
BOOST_BEAST_DECL
std::size_t
buffer_size(buffers_prefix_view<
net::mutable_buffer> const& buffers);
#endif
//------------------------------------------------------------------------------
/** Returns a prefix of a constant buffer.
The returned buffer points to the same memory as the passed
buffer, but with a size that is equal to or smaller.
@param size The maximum size of the returned buffer in bytes. If
this is greater than or equal to the size of the passed buffer,
the result will have the same size as the original buffer.
@param buffer The buffer to return a prefix for. The
underlying memory is not modified, and ownership of the
memory is not transferred.
@return A constant buffer that represents the prefix of
the original buffer.
@par Exception Safety
No-throw guarantee.
*/
inline
net::const_buffer
buffers_prefix(std::size_t size,
net::const_buffer buffer) noexcept
{
return {buffer.data(), std::min<
std::size_t>(size, buffer.size())};
}
/** Returns a prefix of a mutable buffer.
The returned buffer points to the same memory as the passed
buffer, but with a size that is equal to or smaller.
@param size The maximum size of the returned buffer in bytes. If
this is greater than or equal to the size of the passed buffer,
the result will have the same size as the original buffer.
@param buffer The buffer to return a prefix for. The
underlying memory is not modified, and ownership of the
memory is not transferred.
@return A mutable buffer that represents the prefix of
the original buffer.
*/
inline
net::mutable_buffer
buffers_prefix(std::size_t size,
net::mutable_buffer buffer) noexcept
{
return {buffer.data(), std::min<
std::size_t>(size, buffer.size())};
}
/** Returns a prefix of a constant or mutable buffer sequence.
The returned buffer sequence points to the same memory as the
@@ -202,30 +153,16 @@ buffers_prefix(std::size_t size,
@return A constant buffer sequence that represents the prefix
of the original buffer sequence. If the original buffer sequence
also meets the requirements of <em>MutableBufferSequence</em>,
also meets the requirements of <em>MutableConstBufferSequence</em>,
then the returned value will also be a mutable buffer sequence.
@note This function does not participate in overload resolution
if `buffers` is convertible to either `net::const_buffer` or
`net::mutable_buffer`.
*/
template<class ConstBufferSequence>
#if BOOST_BEAST_DOXYGEN
buffers_prefix_view<ConstBufferSequence>
#else
inline
typename std::enable_if<
! std::is_convertible<ConstBufferSequence,
net::const_buffer>::value &&
! std::is_convertible<ConstBufferSequence,
net::mutable_buffer>::value,
buffers_prefix_view<ConstBufferSequence>>::type
#endif
buffers_prefix(std::size_t size, ConstBufferSequence const& buffers)
buffers_prefix(
std::size_t size, ConstBufferSequence const& buffers)
{
static_assert(
net::is_const_buffer_sequence<ConstBufferSequence>::value ||
net::is_mutable_buffer_sequence<ConstBufferSequence>::value,
net::is_const_buffer_sequence<ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
return buffers_prefix_view<ConstBufferSequence>(size, buffers);
}
@@ -240,12 +177,12 @@ buffers_prefix(std::size_t size, ConstBufferSequence const& buffers)
mutable, the returned buffer sequence will also be mutable.
Otherwise, the returned buffer sequence will be constant.
*/
template<class BufferSequence>
template<class ConstBufferSequence>
typename std::conditional<
net::is_mutable_buffer_sequence<BufferSequence>::value,
net::is_mutable_buffer_sequence<ConstBufferSequence>::value,
net::mutable_buffer,
net::const_buffer>::type
buffers_front(BufferSequence const& buffers)
buffers_front(ConstBufferSequence const& buffers)
{
auto const first =
net::buffer_sequence_begin(buffers);

View File

@@ -7,8 +7,8 @@
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_PREFIX_IPP
#define BOOST_BEAST_IMPL_BUFFERS_PREFIX_IPP
#ifndef BOOST_BEAST_IMPL_BUFFERS_PREFIX_HPP
#define BOOST_BEAST_IMPL_BUFFERS_PREFIX_HPP
#include <algorithm>
#include <cstdint>
@@ -20,32 +20,10 @@
namespace boost {
namespace beast {
namespace detail {
inline
net::const_buffer
buffers_prefix(std::size_t size,
net::const_buffer buffer)
template<class Buffers>
class buffers_prefix_view<Buffers>::const_iterator
{
return {buffer.data(),
(std::min)(size, buffer.size())};
}
inline
net::mutable_buffer
buffers_prefix(std::size_t size,
net::mutable_buffer buffer)
{
return {buffer.data(),
(std::min)(size, buffer.size())};
}
} // detail
template<class BufferSequence>
class buffers_prefix_view<BufferSequence>::const_iterator
{
friend class buffers_prefix_view<BufferSequence>;
friend class buffers_prefix_view<Buffers>;
buffers_prefix_view const* b_ = nullptr;
std::size_t remain_;
@@ -65,9 +43,7 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
@@ -98,7 +74,7 @@ public:
reference
operator*() const
{
return detail::buffers_prefix(remain_, *it_);
return beast::buffers_prefix(remain_, *it_);
}
pointer
@@ -154,9 +130,9 @@ private:
//------------------------------------------------------------------------------
template<class BufferSequence>
template<class Buffers>
void
buffers_prefix_view<BufferSequence>::
buffers_prefix_view<Buffers>::
setup(std::size_t size)
{
size_ = 0;
@@ -166,10 +142,14 @@ setup(std::size_t size)
while(end_ != last)
{
auto const len =
net::buffer_size(*end_++);
net::const_buffer(*end_++).size();
if(len >= size)
{
size_ += size;
// by design, this subtraction can wrap
BOOST_STATIC_ASSERT(std::is_unsigned<
decltype(remain_)>::value);
remain_ = size - len;
break;
}
@@ -178,18 +158,20 @@ setup(std::size_t size)
}
}
template<class BufferSequence>
buffers_prefix_view<BufferSequence>::
buffers_prefix_view(buffers_prefix_view&& other)
: buffers_prefix_view(std::move(other),
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_))
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
buffers_prefix_view const& other,
std::size_t dist)
: bs_(other.bs_)
, size_(other.size_)
, remain_(other.remain_)
, end_(std::next(bs_.begin(), dist))
{
}
template<class BufferSequence>
buffers_prefix_view<BufferSequence>::
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(buffers_prefix_view const& other)
: buffers_prefix_view(other,
std::distance<iter_type>(
@@ -198,27 +180,9 @@ buffers_prefix_view(buffers_prefix_view const& other)
{
}
template<class BufferSequence>
template<class Buffers>
auto
buffers_prefix_view<BufferSequence>::
operator=(buffers_prefix_view&& other) ->
buffers_prefix_view&
{
auto const dist = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = std::move(other.bs_);
size_ = other.size_;
remain_ = other.remain_;
end_ = std::next(
net::buffer_sequence_begin(bs_),
dist);
return *this;
}
template<class BufferSequence>
auto
buffers_prefix_view<BufferSequence>::
buffers_prefix_view<Buffers>::
operator=(buffers_prefix_view const& other) ->
buffers_prefix_view&
{
@@ -234,43 +198,138 @@ operator=(buffers_prefix_view const& other) ->
return *this;
}
template<class BufferSequence>
buffers_prefix_view<BufferSequence>::
buffers_prefix_view(std::size_t size,
BufferSequence const& bs)
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
std::size_t size,
Buffers const& bs)
: bs_(bs)
{
setup(size);
}
template<class BufferSequence>
template<class Buffers>
template<class... Args>
buffers_prefix_view<BufferSequence>::
buffers_prefix_view(std::size_t size,
boost::in_place_init_t, Args&&... args)
buffers_prefix_view<Buffers>::
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: bs_(std::forward<Args>(args)...)
{
setup(size);
}
template<class BufferSequence>
inline
template<class Buffers>
auto
buffers_prefix_view<BufferSequence>::begin() const ->
buffers_prefix_view<Buffers>::begin() const ->
const_iterator
{
return const_iterator{*this, std::false_type{}};
}
template<class BufferSequence>
inline
template<class Buffers>
auto
buffers_prefix_view<BufferSequence>::end() const ->
buffers_prefix_view<Buffers>::end() const ->
const_iterator
{
return const_iterator{*this, std::true_type{}};
}
template<class Buffers>
std::size_t
buffer_size(buffers_prefix_view<
Buffers> const& buffers)
{
return buffers.size_;
}
//------------------------------------------------------------------------------
template<>
class buffers_prefix_view<net::const_buffer>
: public net::const_buffer
{
public:
using net::const_buffer::const_buffer;
buffers_prefix_view(buffers_prefix_view const&) = default;
buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
buffers_prefix_view(
std::size_t size,
net::const_buffer buffer)
: net::const_buffer(
buffer.data(),
std::min<std::size_t>(size, buffer.size())
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
, buffer.get_debug_check()
#endif
)
{
}
template<class... Args>
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: buffers_prefix_view(size,
net::const_buffer(
std::forward<Args>(args)...))
{
}
};
std::size_t
buffer_size(buffers_prefix_view<
net::const_buffer> const& buffers)
{
return buffers.size();
}
//------------------------------------------------------------------------------
template<>
class buffers_prefix_view<net::mutable_buffer>
: public net::mutable_buffer
{
public:
using net::mutable_buffer::mutable_buffer;
buffers_prefix_view(buffers_prefix_view const&) = default;
buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
buffers_prefix_view(
std::size_t size,
net::mutable_buffer buffer)
: net::mutable_buffer(
buffer.data(),
std::min<std::size_t>(size, buffer.size())
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
, buffer.get_debug_check()
#endif
)
{
}
template<class... Args>
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: buffers_prefix_view(size,
net::mutable_buffer(
std::forward<Args>(args)...))
{
}
};
std::size_t
buffer_size(buffers_prefix_view<
net::mutable_buffer> const& buffers)
{
return buffers.size();
}
} // beast
} // boost

View File

@@ -20,21 +20,6 @@
namespace boost {
namespace beast {
BOOST_STATIC_ASSERT(
std::is_same<net::const_buffer, decltype(
buffers_prefix(0,
std::declval<net::const_buffer>()))>::value);
BOOST_STATIC_ASSERT(
net::is_const_buffer_sequence<decltype(
buffers_prefix(0,
std::declval<net::const_buffer>()))>::value);
BOOST_STATIC_ASSERT(
std::is_same<net::mutable_buffer, decltype(
buffers_prefix(0,
std::declval<net::mutable_buffer>()))>::value);
class buffers_prefix_test : public beast::unit_test::suite
{
public:
@@ -43,10 +28,9 @@ public:
std::size_t
bsize1(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);
n += net::buffer_size(*it);
return n;
}
@@ -55,10 +39,9 @@ public:
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);
n += net::buffer_size(*it);
return n;
}
@@ -67,10 +50,9 @@ public:
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);
n += net::buffer_size(*--it);
return n;
}
@@ -79,12 +61,11 @@ public:
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);
n += net::buffer_size(*it);
}
return n;
}
@@ -121,26 +102,27 @@ public:
void testEmptyBuffers()
{
using net::buffer_copy;
using net::buffer_size;
using net::mutable_buffer;
auto pb0 = buffers_prefix(0, mutable_buffer{});
BEAST_EXPECT(buffer_size(pb0) == 0);
auto pb1 = buffers_prefix(1, mutable_buffer{});
BEAST_EXPECT(buffer_size(pb1) == 0);
BEAST_EXPECT(buffer_copy(pb0, pb1) == 0);
auto pb0 = buffers_prefix(0, net::mutable_buffer{});
BEAST_EXPECT(buffer_size(pb0) == 0);
auto pb1 = buffers_prefix(1, net::mutable_buffer{});
BEAST_EXPECT(buffer_size(pb1) == 0);
BEAST_EXPECT(net::buffer_copy(pb0, pb1) == 0);
#if 0
using pb_type = decltype(pb0);
buffers_suffix<pb_type> cb(pb0);
BEAST_EXPECT(buffer_size(cb) == 0);
BEAST_EXPECT(buffer_copy(cb, pb1) == 0);
BEAST_EXPECT(net::buffer_copy(cb, pb1) == 0);
cb.consume(1);
BEAST_EXPECT(buffer_size(cb) == 0);
BEAST_EXPECT(buffer_copy(cb, pb1) == 0);
BEAST_EXPECT(net::buffer_copy(cb, pb1) == 0);
auto pbc = buffers_prefix(2, cb);
BEAST_EXPECT(buffer_size(pbc) == 0);
BEAST_EXPECT(buffer_copy(pbc, cb) == 0);
BEAST_EXPECT(net::buffer_copy(pbc, cb) == 0);
#endif
}
void testIterator()
@@ -157,6 +139,73 @@ public:
BEAST_EXPECT(bsize2(pb) == 2);
BEAST_EXPECT(bsize3(pb) == 2);
BEAST_EXPECT(bsize4(pb) == 2);
// default ctor is one past the end
decltype(pb)::const_iterator it;
BEAST_EXPECT(pb.end() == it);
BEAST_EXPECT(it == pb.end());
decltype(pb)::const_iterator it2;
BEAST_EXPECT(it == it2);
BEAST_EXPECT(it2 == it);
it = pb.end();
it2 = pb.end();
BEAST_EXPECT(it == it2);
BEAST_EXPECT(it2 == it);
decltype(pb)::const_iterator it3(it2);
BEAST_EXPECT(it3 == it2);
it = pb.begin();
BEAST_EXPECT(it != it3);
it = it3;
BEAST_EXPECT(it == it3);
}
void testInPlaceInit()
{
{
class test_buffers
{
net::const_buffer cb_;
public:
using const_iterator =
net::const_buffer const*;
explicit
test_buffers(std::true_type)
{
}
const_iterator
begin() const
{
return &cb_;
}
const_iterator
end() const
{
return begin() + 1;
}
};
buffers_prefix_view<test_buffers> v(
2, boost::in_place_init, std::true_type{});
BEAST_EXPECT(buffer_size(v) == 0);
}
{
char c[2];
c[0] = 0;
c[1] = 0;
buffers_prefix_view<net::const_buffer> v(
2, boost::in_place_init, c, sizeof(c));
BEAST_EXPECT(buffer_size(v) == 2);
}
{
char c[2];
buffers_prefix_view<net::mutable_buffer> v(
2, boost::in_place_init, c, sizeof(c));
BEAST_EXPECT(buffer_size(v) == 2);
}
}
void run() override
@@ -165,6 +214,7 @@ public:
testMatrix<net::mutable_buffer>();
testEmptyBuffers();
testIterator();
testInPlaceInit();
}
};