Use variant in buffers_cat_view

This commit is contained in:
Vinnie Falco
2017-11-26 09:55:31 -08:00
parent 332c2fe0cb
commit b59d0a5cd5
3 changed files with 237 additions and 288 deletions

View File

@@ -5,6 +5,7 @@ Version 146:
* Documentation tidying * Documentation tidying
* Fix typo in examples documentation * Fix typo in examples documentation
* Add detail::aligned_union and tidy up * Add detail::aligned_union and tidy up
* Use variant in buffers_cat_view
API Changes: API Changes:

View File

@@ -36,7 +36,7 @@ class variant
template<std::size_t I> template<std::size_t I>
using type = typename std::tuple_element< using type = typename std::tuple_element<
I , std::tuple<TN...>>::type; I, std::tuple<TN...>>::type;
template<std::size_t I> template<std::size_t I>
using C = std::integral_constant<std::size_t, I>; using C = std::integral_constant<std::size_t, I>;
@@ -46,8 +46,15 @@ public:
~variant() ~variant()
{ {
if(i_) destroy(C<0>{});
destroy(C<0>{}); }
bool
operator==(variant const& other) const
{
if(i_ != other.i_)
return false;
return equal(other, C<0>{});
} }
// 0 = empty // 0 = empty
@@ -61,6 +68,7 @@ public:
variant(variant&& other) variant(variant&& other)
{ {
i_ = other.move(&buf_, C<0>{}); i_ = other.move(&buf_, C<0>{});
other.i_ = 0;
} }
variant(variant const& other) variant(variant const& other)
@@ -71,17 +79,22 @@ public:
// moved-from object becomes empty // moved-from object becomes empty
variant& operator=(variant&& other) variant& operator=(variant&& other)
{ {
if(i_ != 0) if(this != &other)
{
destroy(C<0>{}); destroy(C<0>{});
i_ = other.move(&buf_, C<0>{}); i_ = other.move(&buf_, C<0>{});
other.i_ = 0;
}
return *this; return *this;
} }
variant& operator=(variant const& other) variant& operator=(variant const& other)
{ {
if(i_ != 0) if(this != &other)
{
destroy(C<0>{}); destroy(C<0>{});
i_ = other.copy(&buf_, C<0>{}); i_ = other.copy(&buf_, C<0>{});
}
return *this; return *this;
} }
@@ -89,8 +102,7 @@ public:
void void
emplace(Args&&... args) emplace(Args&&... args)
{ {
if(i_ != 0) destroy(C<0>{});
destroy(C<0>{});
new(&buf_) type<I-1>( new(&buf_) type<I-1>(
std::forward<Args>(args)...); std::forward<Args>(args)...);
i_ = I; i_ = I;
@@ -117,72 +129,135 @@ public:
void void
reset() reset()
{ {
if(i_ == 0)
return;
destroy(C<0>{}); destroy(C<0>{});
} }
private: private:
void void
destroy(C<sizeof...(TN)>) destroy(C<0>)
{ {
return; auto const I = 0;
if(i_ == I)
return;
destroy(C<I+1>{});
i_ = 0;
} }
template<std::size_t I> template<std::size_t I>
void void
destroy(C<I>) destroy(C<I>)
{ {
if(i_ == I+1) if(i_ == I)
{ {
using T = type<I>; using T = type<I-1>;
get<I+1>().~T(); get<I>().~T();
i_ = 0;
return; return;
} }
destroy(C<I+1>{}); destroy(C<I+1>{});
} }
unsigned char void
move(void*, C<sizeof...(TN)>) destroy(C<sizeof...(TN)>)
{ {
return 0; auto const I = sizeof...(TN);
BOOST_ASSERT(i_ == I);
using T = type<I-1>;
get<I>().~T();
}
unsigned char
move(void* dest, C<0>)
{
auto const I = 0;
if(i_ == I)
return I;
return move(dest, C<I+1>{});
} }
template<std::size_t I> template<std::size_t I>
unsigned char unsigned char
move(void* dest, C<I>) move(void* dest, C<I>)
{ {
if(i_ == I+1) if(i_ == I)
{ {
using T = type<I>; using T = type<I-1>;
new(dest) T{std::move(get<I+1>())}; new(dest) T(std::move(get<I>()));
get<I+1>().~T(); get<I>().~T();
i_ = 0; return I;
return I+1;
} }
return move(dest, C<I+1>{}); return move(dest, C<I+1>{});
} }
unsigned char unsigned char
copy(void*, C<sizeof...(TN)>) const move(void* dest, C<sizeof...(TN)>)
{ {
return 0; auto const I = sizeof...(TN);
BOOST_ASSERT(i_ == I);
using T = type<I-1>;
new(dest) T(std::move(get<I>()));
get<I>().~T();
return I;
}
unsigned char
copy(void* dest, C<0>) const
{
auto const I = 0;
if(i_ == I)
return I;
return copy(dest, C<I+1>{});
} }
template<std::size_t I> template<std::size_t I>
unsigned char unsigned char
copy(void* dest, C<I>) const copy(void* dest, C<I>) const
{ {
if(i_ == I+1) if(i_ == I)
{ {
using T = type<I>; using T = type<I-1>;
auto const& t = get<I+1>(); auto const& t = get<I>();
new(dest) T{t}; new(dest) T(t);
return I+1; return I;
} }
return copy(dest, C<I+1>{}); return copy(dest, C<I+1>{});
} }
unsigned char
copy(void* dest, C<sizeof...(TN)>) const
{
auto const I = sizeof...(TN);
BOOST_ASSERT(i_ == I);
using T = type<I-1>;
auto const& t = get<I>();
new(dest) T(t);
return I;
}
bool
equal(variant const& other, C<0>) const
{
auto constexpr I = 0;
if(i_ == I)
return true;
return equal(other, C<I+1>{});
}
template<std::size_t I>
bool
equal(variant const& other, C<I>) const
{
if(i_ == I)
return get<I>() == other.get<I>();
return equal(other, C<I+1>{});
}
bool
equal(variant const& other, C<sizeof...(TN)>) const
{
auto constexpr I = sizeof...(TN);
BOOST_ASSERT(i_ == I);
return get<I>() == other.get<I>();
}
}; };
} // detail } // detail

View File

@@ -11,9 +11,9 @@
#define BOOST_BEAST_IMPL_BUFFERS_CAT_IPP #define BOOST_BEAST_IMPL_BUFFERS_CAT_IPP
#include <boost/beast/core/detail/type_traits.hpp> #include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/core/detail/variant.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <array>
#include <cstdint> #include <cstdint>
#include <iterator> #include <iterator>
#include <new> #include <new>
@@ -27,39 +27,29 @@ namespace beast {
template<class... Bn> template<class... Bn>
class buffers_cat_view<Bn...>::const_iterator class buffers_cat_view<Bn...>::const_iterator
{ {
std::size_t n_; // VFALCO The logic to skip empty sequences fails
std::tuple<Bn...> const* bn_; // if there is just one buffer in the list.
std::array<char, detail::max_sizeof< static_assert(sizeof...(Bn) >= 2,
typename detail::buffer_sequence_iterator<Bn>::type...>()> buf_; "A minimum of two sequences are required");
struct past_end
{
operator bool() const noexcept
{
return true;
}
};
std::tuple<Bn...> const* bn_ = nullptr;
detail::variant<typename
detail::buffer_sequence_iterator<Bn>::type...,
past_end> it_;
friend class buffers_cat_view<Bn...>; friend class buffers_cat_view<Bn...>;
template<std::size_t I> template<std::size_t I>
using C = std::integral_constant<std::size_t, I>; using C = std::integral_constant<std::size_t, I>;
template<std::size_t I>
using iter_t = typename detail::buffer_sequence_iterator<
typename std::tuple_element<I, std::tuple<Bn...>>::type>::type;
template<std::size_t I>
iter_t<I>&
iter()
{
// type-pun
return *reinterpret_cast<
iter_t<I>*>(static_cast<void*>(buf_.data()));
}
template<std::size_t I>
iter_t<I> const&
iter() const
{
// type-pun
return *reinterpret_cast<
iter_t<I> const*>(static_cast<
void const*>(buf_.data()));
}
public: public:
using value_type = typename using value_type = typename
detail::common_buffers_type<Bn...>::type; detail::common_buffers_type<Bn...>::type;
@@ -69,12 +59,11 @@ public:
using iterator_category = using iterator_category =
std::bidirectional_iterator_tag; std::bidirectional_iterator_tag;
~const_iterator(); const_iterator() = default;
const_iterator(); const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator&& other); const_iterator(const_iterator const& other) = default;
const_iterator(const_iterator const& other); const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator&& other); const_iterator& operator=(const_iterator const& other) = default;
const_iterator& operator=(const_iterator const& other);
bool bool
operator==(const_iterator const& other) const; operator==(const_iterator const& other) const;
@@ -97,9 +86,11 @@ 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);
@@ -107,13 +98,6 @@ private:
const_iterator( const_iterator(
std::tuple<Bn...> const& bn, bool at_end); std::tuple<Bn...> const& bn, bool at_end);
void
construct(C<sizeof...(Bn)> const&)
{
auto constexpr I = sizeof...(Bn);
n_ = I;
}
template<std::size_t I> template<std::size_t I>
void void
construct(C<I> const&) construct(C<I> const&)
@@ -121,122 +105,85 @@ private:
if(boost::asio::buffer_size( if(boost::asio::buffer_size(
std::get<I>(*bn_)) != 0) std::get<I>(*bn_)) != 0)
{ {
n_ = I; it_.template emplace<I+1>(
new(&buf_[0]) iter_t<I>{
boost::asio::buffer_sequence_begin( boost::asio::buffer_sequence_begin(
std::get<I>(*bn_))}; std::get<I>(*bn_)));
return; return;
} }
construct(C<I+1>{}); construct(C<I+1>{});
} }
void void
rconstruct(C<0> const&) construct(C<sizeof...(Bn)-1> const&)
{
auto constexpr I = sizeof...(Bn)-1;
it_.template emplace<I+1>(
boost::asio::buffer_sequence_begin(
std::get<I>(*bn_)));
}
void
construct(C<sizeof...(Bn)> const&)
{
// end
auto constexpr I = sizeof...(Bn);
it_.template emplace<I+1>();
}
template<std::size_t I>
void
next(C<I> const&)
{
if(boost::asio::buffer_size(
std::get<I>(*bn_)) != 0)
{
it_.template emplace<I+1>(
boost::asio::buffer_sequence_begin(
std::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(boost::asio::buffer_size(
std::get<I>(*bn_)) != 0)
{
it_.template emplace<I+1>(
boost::asio::buffer_sequence_end(
std::get<I>(*bn_)));
return;
}
prev(C<I-1>{});
}
void
prev(C<0> const&)
{ {
auto constexpr I = 0; auto constexpr I = 0;
if(boost::asio::buffer_size( it_.template emplace<I+1>(
std::get<I>(*bn_)) != 0) boost::asio::buffer_sequence_end(
{ std::get<I>(*bn_)));
n_ = I;
new(&buf_[0]) iter_t<I>{
boost::asio::buffer_sequence_end(
std::get<I>(*bn_))};
return;
}
BOOST_THROW_EXCEPTION(std::logic_error{
"invalid iterator"});
} }
template<std::size_t I> template<std::size_t I>
void reference
rconstruct(C<I> const&) dereference(C<I> const&) const
{ {
if(boost::asio::buffer_size( if(it_.index() == I+1)
std::get<I>(*bn_)) != 0) return *it_.template get<I+1>();
{ return dereference(C<I+1>{});
n_ = I;
new(&buf_[0]) iter_t<I>{
boost::asio::buffer_sequence_end(
std::get<I>(*bn_))};
return;
}
rconstruct(C<I-1>{});
}
void
destroy(C<sizeof...(Bn)> const&)
{
return;
}
template<std::size_t I>
void
destroy(C<I> const&)
{
if(n_ == I)
{
using Iter = iter_t<I>;
iter<I>().~Iter();
return;
}
destroy(C<I+1>{});
}
void
move(const_iterator&&,
C<sizeof...(Bn)> const&)
{
}
template<std::size_t I>
void
move(const_iterator&& other,
C<I> const&)
{
if(n_ == I)
{
new(&buf_[0]) iter_t<I>{
std::move(other.iter<I>())};
return;
}
move(std::move(other), C<I+1>{});
}
void
copy(const_iterator const&,
C<sizeof...(Bn)> const&)
{
}
template<std::size_t I>
void
copy(const_iterator const& other,
C<I> const&)
{
if(n_ == I)
{
new(&buf_[0]) iter_t<I>{
other.iter<I>()};
return;
}
copy(other, C<I+1>{});
}
bool
equal(const_iterator const&,
C<sizeof...(Bn)> const&) const
{
return true;
}
template<std::size_t I>
bool
equal(const_iterator const& other,
C<I> const&) const
{
if(n_ == I)
return iter<I>() == other.iter<I>();
return equal(other, C<I+1>{});
} }
[[noreturn]] [[noreturn]]
@@ -248,12 +195,18 @@ private:
} }
template<std::size_t I> template<std::size_t I>
reference void
dereference(C<I> const&) const increment(C<I> const&)
{ {
if(n_ == I) if(it_.index() == I+1)
return *iter<I>(); {
return dereference(C<I+1>{}); if(++it_.template get<I+1>() !=
boost::asio::buffer_sequence_end(
std::get<I>(*bn_)))
return;
return next(C<I+1>{});
}
increment(C<I+1>{});
} }
[[noreturn]] [[noreturn]]
@@ -264,29 +217,12 @@ private:
"invalid iterator"}); "invalid iterator"});
} }
template<std::size_t I>
void
increment(C<I> const&)
{
if(n_ == I)
{
if(++iter<I>() !=
boost::asio::buffer_sequence_end(
std::get<I>(*bn_)))
return;
using Iter = iter_t<I>;
iter<I>().~Iter();
return construct(C<I+1>{});
}
increment(C<I+1>{});
}
void void
decrement(C<sizeof...(Bn)> const&) decrement(C<sizeof...(Bn)> const&)
{ {
auto constexpr I = sizeof...(Bn); auto constexpr I = sizeof...(Bn);
if(n_ == I) if(it_.index() == I+1)
rconstruct(C<I-1>{}); prev(C<I-1>{});
decrement(C<I-1>{}); decrement(C<I-1>{});
} }
@@ -294,19 +230,16 @@ private:
void void
decrement(C<I> const&) decrement(C<I> const&)
{ {
if(n_ == I) if(it_.index() == I+1)
{ {
if(iter<I>() != if(it_.template get<I+1>() !=
boost::asio::buffer_sequence_begin( boost::asio::buffer_sequence_begin(
std::get<I>(*bn_))) std::get<I>(*bn_)))
{ {
--iter<I>(); --it_.template get<I+1>();
return; return;
} }
--n_; prev(C<I-1>{});
using Iter = iter_t<I>;
iter<I>().~Iter();
rconstruct(C<I-1>{});
} }
decrement(C<I-1>{}); decrement(C<I-1>{});
} }
@@ -315,11 +248,11 @@ private:
decrement(C<0> const&) decrement(C<0> const&)
{ {
auto constexpr I = 0; auto constexpr I = 0;
if(iter<I>() != if(it_.template get<I+1>() !=
boost::asio::buffer_sequence_begin( boost::asio::buffer_sequence_begin(
std::get<I>(*bn_))) std::get<I>(*bn_)))
{ {
--iter<I>(); --it_.template get<I+1>();
return; return;
} }
BOOST_THROW_EXCEPTION(std::logic_error{ BOOST_THROW_EXCEPTION(std::logic_error{
@@ -331,97 +264,33 @@ private:
template<class... Bn> template<class... Bn>
buffers_cat_view<Bn...>:: buffers_cat_view<Bn...>::
const_iterator::~const_iterator() const_iterator::
{ const_iterator(
destroy(C<0>{});
}
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::const_iterator()
: n_(sizeof...(Bn))
, bn_(nullptr)
{
}
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::const_iterator(
std::tuple<Bn...> const& bn, bool at_end) std::tuple<Bn...> const& bn, bool at_end)
: bn_(&bn) : bn_(&bn)
{ {
if(at_end) if(! at_end)
n_ = sizeof...(Bn);
else
construct(C<0>{}); construct(C<0>{});
} else
construct(C<sizeof...(Bn)>{});
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::const_iterator(const_iterator&& other)
: n_(other.n_)
, bn_(other.bn_)
{
move(std::move(other), C<0>{});
}
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::const_iterator(const_iterator const& other)
: n_(other.n_)
, bn_(other.bn_)
{
copy(other, C<0>{});
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::operator=(const_iterator&& other) ->
const_iterator&
{
if(&other == this)
return *this;
destroy(C<0>{});
n_ = other.n_;
bn_ = other.bn_;
// VFALCO What about exceptions?
move(std::move(other), C<0>{});
return *this;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::operator=(const_iterator const& other) ->
const_iterator&
{
if(&other == this)
return *this;
destroy(C<0>{});
n_ = other.n_;
bn_ = other.bn_;
// VFALCO What about exceptions?
copy(other, C<0>{});
return *this;
} }
template<class... Bn> template<class... Bn>
bool bool
buffers_cat_view<Bn...>:: buffers_cat_view<Bn...>::
const_iterator::operator==(const_iterator const& other) const const_iterator::
operator==(const_iterator const& other) const
{ {
if(bn_ != other.bn_) if(bn_ != other.bn_)
return false; return false;
if(n_ != other.n_) return it_ == other.it_;
return false;
return equal(other, C<0>{});
} }
template<class... Bn> template<class... Bn>
auto auto
buffers_cat_view<Bn...>:: buffers_cat_view<Bn...>::
const_iterator::operator*() const -> const_iterator::
operator*() const ->
reference reference
{ {
return dereference(C<0>{}); return dereference(C<0>{});
@@ -430,7 +299,8 @@ const_iterator::operator*() const ->
template<class... Bn> template<class... Bn>
auto auto
buffers_cat_view<Bn...>:: buffers_cat_view<Bn...>::
const_iterator::operator++() -> const_iterator::
operator++() ->
const_iterator& const_iterator&
{ {
increment(C<0>{}); increment(C<0>{});
@@ -440,7 +310,8 @@ const_iterator::operator++() ->
template<class... Bn> template<class... Bn>
auto auto
buffers_cat_view<Bn...>:: buffers_cat_view<Bn...>::
const_iterator::operator++(int) -> const_iterator::
operator++(int) ->
const_iterator const_iterator
{ {
auto temp = *this; auto temp = *this;
@@ -451,7 +322,8 @@ const_iterator::operator++(int) ->
template<class... Bn> template<class... Bn>
auto auto
buffers_cat_view<Bn...>:: buffers_cat_view<Bn...>::
const_iterator::operator--() -> const_iterator::
operator--() ->
const_iterator& const_iterator&
{ {
decrement(C<sizeof...(Bn)>{}); decrement(C<sizeof...(Bn)>{});
@@ -461,7 +333,8 @@ const_iterator::operator--() ->
template<class... Bn> template<class... Bn>
auto auto
buffers_cat_view<Bn...>:: buffers_cat_view<Bn...>::
const_iterator::operator--(int) -> const_iterator::
operator--(int) ->
const_iterator const_iterator
{ {
auto temp = *this; auto temp = *this;