boost/beast/core/impl/buffers_cat.ipp
//
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef 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/variant.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
#include <cstdint>
#include <iterator>
#include <new>
#include <stdexcept>
#include <tuple>
#include <utility>
namespace boost {
namespace beast {
template<class... Bn>
class buffers_cat_view<Bn...>::const_iterator
{
// VFALCO The logic to skip empty sequences fails
// if there is just one buffer in the list.
static_assert(sizeof...(Bn) >= 2,
"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...>;
template<std::size_t I>
using C = std::integral_constant<std::size_t, I>;
public:
using value_type = typename
detail::common_buffers_type<Bn...>::type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
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
operator==(const_iterator const& other) const;
bool
operator!=(const_iterator const& other) const
{
return ! (*this == other);
}
reference
operator*() const;
pointer
operator->() const = delete;
const_iterator&
operator++();
const_iterator
operator++(int);
// deprecated
const_iterator&
operator--();
// deprecated
const_iterator
operator--(int);
private:
const_iterator(
std::tuple<Bn...> const& bn, bool at_end);
template<std::size_t I>
void
construct(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;
}
construct(C<I+1>{});
}
void
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;
it_.template emplace<I+1>(
boost::asio::buffer_sequence_end(
std::get<I>(*bn_)));
}
template<std::size_t I>
reference
dereference(C<I> const&) const
{
if(it_.index() == I+1)
return *it_.template get<I+1>();
return dereference(C<I+1>{});
}
[[noreturn]]
reference
dereference(C<sizeof...(Bn)> const&) const
{
BOOST_THROW_EXCEPTION(std::logic_error{
"invalid iterator"});
}
template<std::size_t I>
void
increment(C<I> const&)
{
if(it_.index() == 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]]
void
increment(C<sizeof...(Bn)> const&)
{
BOOST_THROW_EXCEPTION(std::logic_error{
"invalid iterator"});
}
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>() !=
boost::asio::buffer_sequence_begin(
std::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>() !=
boost::asio::buffer_sequence_begin(
std::get<I>(*bn_)))
{
--it_.template get<I+1>();
return;
}
BOOST_THROW_EXCEPTION(std::logic_error{
"invalid iterator"});
}
};
//------------------------------------------------------------------------------
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::
const_iterator(
std::tuple<Bn...> const& bn, bool at_end)
: bn_(&bn)
{
if(! at_end)
construct(C<0>{});
else
construct(C<sizeof...(Bn)>{});
}
template<class... Bn>
bool
buffers_cat_view<Bn...>::
const_iterator::
operator==(const_iterator const& other) const
{
if(bn_ != other.bn_)
return false;
return it_ == other.it_;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator*() const ->
reference
{
return dereference(C<0>{});
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator++() ->
const_iterator&
{
increment(C<0>{});
return *this;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator++(int) ->
const_iterator
{
auto temp = *this;
++(*this);
return temp;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator--() ->
const_iterator&
{
decrement(C<sizeof...(Bn)>{});
return *this;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator--(int) ->
const_iterator
{
auto temp = *this;
--(*this);
return temp;
}
//------------------------------------------------------------------------------
template<class... Bn>
buffers_cat_view<Bn...>::
buffers_cat_view(Bn const&... bn)
: bn_(bn...)
{
}
template<class... Bn>
inline
auto
buffers_cat_view<Bn...>::begin() const ->
const_iterator
{
return const_iterator{bn_, false};
}
template<class... Bn>
inline
auto
buffers_cat_view<Bn...>::end() const ->
const_iterator
{
return const_iterator{bn_, true};
}
} // beast
} // boost
#endif