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/asio/buffer.hpp> #include <boost/throw_exception.hpp> #include <array> #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 { std::size_t n_; std::tuple<Bn...> const* bn_; std::array<char, detail::max_sizeof< typename detail::buffer_sequence_iterator<Bn>::type...>()> buf_; friend class buffers_cat_view<Bn...>; template<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: 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(); const_iterator(); const_iterator(const_iterator&& other); const_iterator(const_iterator const& other); const_iterator& operator=(const_iterator&& other); const_iterator& operator=(const_iterator const& other); 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); const_iterator& operator--(); const_iterator operator--(int); private: const_iterator( 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> void construct(C<I> const&) { if(boost::asio::buffer_size( std::get<I>(*bn_)) != 0) { n_ = I; new(&buf_[0]) iter_t<I>{ boost::asio::buffer_sequence_begin( std::get<I>(*bn_))}; return; } construct(C<I+1>{}); } void rconstruct(C<0> const&) { auto constexpr I = 0; if(boost::asio::buffer_size( std::get<I>(*bn_)) != 0) { 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> void rconstruct(C<I> const&) { if(boost::asio::buffer_size( std::get<I>(*bn_)) != 0) { 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]] reference dereference(C<sizeof...(Bn)> const&) const { BOOST_THROW_EXCEPTION(std::logic_error{ "invalid iterator"}); } template<std::size_t I> reference dereference(C<I> const&) const { if(n_ == I) return *iter<I>(); return dereference(C<I+1>{}); } [[noreturn]] void increment(C<sizeof...(Bn)> const&) { BOOST_THROW_EXCEPTION(std::logic_error{ "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 decrement(C<sizeof...(Bn)> const&) { auto constexpr I = sizeof...(Bn); if(n_ == I) rconstruct(C<I-1>{}); decrement(C<I-1>{}); } template<std::size_t I> void decrement(C<I> const&) { if(n_ == I) { if(iter<I>() != boost::asio::buffer_sequence_begin( std::get<I>(*bn_))) { --iter<I>(); return; } --n_; using Iter = iter_t<I>; iter<I>().~Iter(); rconstruct(C<I-1>{}); } decrement(C<I-1>{}); } void decrement(C<0> const&) { auto constexpr I = 0; if(iter<I>() != boost::asio::buffer_sequence_begin( std::get<I>(*bn_))) { --iter<I>(); return; } BOOST_THROW_EXCEPTION(std::logic_error{ "invalid iterator"}); } }; //------------------------------------------------------------------------------ template<class... Bn> buffers_cat_view<Bn...>:: 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) : bn_(&bn) { if(at_end) n_ = sizeof...(Bn); else construct(C<0>{}); } 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> bool buffers_cat_view<Bn...>:: const_iterator::operator==(const_iterator const& other) const { if(bn_ != other.bn_) return false; if(n_ != other.n_) return false; return equal(other, C<0>{}); } 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