// // 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_ADAPTER_IPP #define BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP #include #include #include #include #include #include #include namespace boost { namespace beast { template class buffers_adapter:: const_buffers_type { buffers_adapter const* ba_; public: using value_type = boost::asio::mutable_buffer; class const_iterator; const_buffers_type() = delete; const_buffers_type( const_buffers_type const&) = default; const_buffers_type& operator=( const_buffers_type const&) = default; const_iterator begin() const; const_iterator end() const; private: friend class buffers_adapter; const_buffers_type(buffers_adapter const& ba) : ba_(&ba) { } }; template class buffers_adapter:: const_buffers_type::const_iterator { iter_type it_; buffers_adapter const* ba_ = nullptr; public: using value_type = boost::asio::const_buffer; 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 { return ba_ == other.ba_ && it_ == other.it_; } bool operator!=(const_iterator const& other) const { return !(*this == other); } reference operator*() const { value_type const b = *it_; return value_type{b.data(), (ba_->out_ == boost::asio::buffer_sequence_end(ba_->bs_) || it_ != ba_->out_) ? b.size() : ba_->out_pos_} + (it_ == ba_->begin_ ? ba_->in_pos_ : 0); } pointer operator->() const = delete; const_iterator& operator++() { ++it_; return *this; } const_iterator operator++(int) { auto temp = *this; ++(*this); return temp; } const_iterator& operator--() { --it_; return *this; } const_iterator operator--(int) { auto temp = *this; --(*this); return temp; } private: friend class const_buffers_type; const_iterator(buffers_adapter const& ba, iter_type iter) : it_(iter) , ba_(&ba) { } }; template inline auto buffers_adapter::const_buffers_type::begin() const -> const_iterator { return const_iterator{*ba_, ba_->begin_}; } template inline auto buffers_adapter::const_buffers_type::end() const -> const_iterator { return const_iterator{*ba_, ba_->out_ == ba_->end_ ? ba_->end_ : std::next(ba_->out_)}; } //------------------------------------------------------------------------------ template class buffers_adapter:: mutable_buffers_type { buffers_adapter const* ba_; public: using value_type = boost::asio::mutable_buffer; class const_iterator; mutable_buffers_type() = delete; mutable_buffers_type( mutable_buffers_type const&) = default; mutable_buffers_type& operator=( mutable_buffers_type const&) = default; const_iterator begin() const; const_iterator end() const; private: friend class buffers_adapter; mutable_buffers_type( buffers_adapter const& ba) : ba_(&ba) { } }; template class buffers_adapter:: mutable_buffers_type::const_iterator { iter_type it_; buffers_adapter const* ba_ = nullptr; public: using value_type = boost::asio::mutable_buffer; 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 { return ba_ == other.ba_ && it_ == other.it_; } bool operator!=(const_iterator const& other) const { return !(*this == other); } reference operator*() const { value_type const b = *it_; return value_type{b.data(), it_ == std::prev(ba_->end_) ? ba_->out_end_ : b.size()} + (it_ == ba_->out_ ? ba_->out_pos_ : 0); } pointer operator->() const = delete; const_iterator& operator++() { ++it_; return *this; } const_iterator operator++(int) { auto temp = *this; ++(*this); return temp; } const_iterator& operator--() { --it_; return *this; } const_iterator operator--(int) { auto temp = *this; --(*this); return temp; } private: friend class mutable_buffers_type; const_iterator(buffers_adapter const& ba, iter_type iter) : it_(iter) , ba_(&ba) { } }; template inline auto buffers_adapter:: mutable_buffers_type:: begin() const -> const_iterator { return const_iterator{*ba_, ba_->out_}; } template inline auto buffers_adapter:: mutable_buffers_type:: end() const -> const_iterator { return const_iterator{*ba_, ba_->end_}; } //------------------------------------------------------------------------------ template buffers_adapter::buffers_adapter( buffers_adapter&& other) : buffers_adapter(std::move(other), std::distance(boost::asio::buffer_sequence_begin(other.bs_), other.begin_), std::distance(boost::asio::buffer_sequence_begin(other.bs_), other.out_), std::distance(boost::asio::buffer_sequence_begin(other.bs_), other.end_)) { } template buffers_adapter::buffers_adapter( buffers_adapter const& other) : buffers_adapter(other, std::distance(boost::asio::buffer_sequence_begin(other.bs_), other.begin_), std::distance(boost::asio::buffer_sequence_begin(other.bs_), other.out_), std::distance(boost::asio::buffer_sequence_begin(other.bs_), other.end_)) { } template auto buffers_adapter::operator=( buffers_adapter&& other) -> buffers_adapter& { auto const nbegin = std::distance( boost::asio::buffer_sequence_begin(other.bs_), other.begin_); auto const nout = std::distance( boost::asio::buffer_sequence_begin(other.bs_), other.out_); auto const nend = std::distance( boost::asio::buffer_sequence_begin(other.bs_), other.end_); bs_ = std::move(other.bs_); begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin); out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout); end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend); max_size_ = other.max_size_; in_pos_ = other.in_pos_; in_size_ = other.in_size_; out_pos_ = other.out_pos_; out_end_ = other.out_end_; return *this; } template auto buffers_adapter::operator=( buffers_adapter const& other) -> buffers_adapter& { auto const nbegin = std::distance( boost::asio::buffer_sequence_begin(other.bs_), other.begin_); auto const nout = std::distance( boost::asio::buffer_sequence_begin(other.bs_), other.out_); auto const nend = std::distance( boost::asio::buffer_sequence_begin(other.bs_), other.end_); bs_ = other.bs_; begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin); out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout); end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend); max_size_ = other.max_size_; in_pos_ = other.in_pos_; in_size_ = other.in_size_; out_pos_ = other.out_pos_; out_end_ = other.out_end_; return *this; } template buffers_adapter::buffers_adapter( MutableBufferSequence const& bs) : bs_(bs) , begin_(boost::asio::buffer_sequence_begin(bs_)) , out_ (boost::asio::buffer_sequence_begin(bs_)) , end_ (boost::asio::buffer_sequence_begin(bs_)) , max_size_(boost::asio::buffer_size(bs_)) { } template auto buffers_adapter::prepare(std::size_t n) -> mutable_buffers_type { using boost::asio::buffer_size; end_ = out_; if(end_ != boost::asio::buffer_sequence_end(bs_)) { auto size = buffer_size(*end_) - out_pos_; if(n > size) { n -= size; while(++end_ != boost::asio::buffer_sequence_end(bs_)) { size = buffer_size(*end_); if(n < size) { out_end_ = n; n = 0; ++end_; break; } n -= size; out_end_ = size; } } else { ++end_; out_end_ = out_pos_ + n; n = 0; } } if(n > 0) BOOST_THROW_EXCEPTION(std::length_error{ "buffer overflow"}); return mutable_buffers_type{*this}; } template void buffers_adapter::commit(std::size_t n) { using boost::asio::buffer_size; if(out_ == end_) return; auto const last = std::prev(end_); while(out_ != last) { auto const avail = buffer_size(*out_) - out_pos_; if(n < avail) { out_pos_ += n; in_size_ += n; max_size_ -= n; return; } ++out_; n -= avail; out_pos_ = 0; in_size_ += avail; max_size_ -= avail; } n = (std::min)(n, out_end_ - out_pos_); out_pos_ += n; in_size_ += n; max_size_ -= n; if(out_pos_ == buffer_size(*out_)) { ++out_; out_pos_ = 0; out_end_ = 0; } } template inline auto buffers_adapter::data() const -> const_buffers_type { return const_buffers_type{*this}; } template void buffers_adapter::consume(std::size_t n) { using boost::asio::buffer_size; while(begin_ != out_) { auto const avail = buffer_size(*begin_) - in_pos_; if(n < avail) { in_size_ -= n; in_pos_ += n; return; } n -= avail; in_size_ -= avail; in_pos_ = 0; ++begin_; } auto const avail = out_pos_ - in_pos_; if(n < avail) { in_size_ -= n; in_pos_ += n; } else { in_size_ -= avail; in_pos_ = out_pos_; } } } // beast } // boost #endif