You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
280 lines
6.9 KiB
280 lines
6.9 KiB
// |
|
// detail/consuming_buffers.hpp |
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
// |
|
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff 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) |
|
// |
|
|
|
#ifndef BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP |
|
#define BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP |
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200) |
|
# pragma once |
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
|
|
|
#include <boost/asio/detail/config.hpp> |
|
#include <cstddef> |
|
#include <boost/iterator.hpp> |
|
#include <boost/limits.hpp> |
|
#include <boost/asio/buffer.hpp> |
|
|
|
#include <boost/asio/detail/push_options.hpp> |
|
|
|
namespace boost { |
|
namespace asio { |
|
namespace detail { |
|
|
|
// A proxy iterator for a sub-range in a list of buffers. |
|
template <typename Buffer, typename Buffer_Iterator> |
|
class consuming_buffers_iterator |
|
: public boost::iterator<std::forward_iterator_tag, const Buffer> |
|
{ |
|
public: |
|
// Default constructor creates an end iterator. |
|
consuming_buffers_iterator() |
|
: at_end_(true) |
|
{ |
|
} |
|
|
|
// Construct with a buffer for the first entry and an iterator |
|
// range for the remaining entries. |
|
consuming_buffers_iterator(bool at_end, const Buffer& first, |
|
Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder, |
|
std::size_t max_size) |
|
: at_end_(max_size > 0 ? at_end : true), |
|
first_(buffer(first, max_size)), |
|
begin_remainder_(begin_remainder), |
|
end_remainder_(end_remainder), |
|
offset_(0), |
|
max_size_(max_size) |
|
{ |
|
} |
|
|
|
// Dereference an iterator. |
|
const Buffer& operator*() const |
|
{ |
|
return dereference(); |
|
} |
|
|
|
// Dereference an iterator. |
|
const Buffer* operator->() const |
|
{ |
|
return &dereference(); |
|
} |
|
|
|
// Increment operator (prefix). |
|
consuming_buffers_iterator& operator++() |
|
{ |
|
increment(); |
|
return *this; |
|
} |
|
|
|
// Increment operator (postfix). |
|
consuming_buffers_iterator operator++(int) |
|
{ |
|
consuming_buffers_iterator tmp(*this); |
|
++*this; |
|
return tmp; |
|
} |
|
|
|
// Test two iterators for equality. |
|
friend bool operator==(const consuming_buffers_iterator& a, |
|
const consuming_buffers_iterator& b) |
|
{ |
|
return a.equal(b); |
|
} |
|
|
|
// Test two iterators for inequality. |
|
friend bool operator!=(const consuming_buffers_iterator& a, |
|
const consuming_buffers_iterator& b) |
|
{ |
|
return !a.equal(b); |
|
} |
|
|
|
private: |
|
void increment() |
|
{ |
|
if (!at_end_) |
|
{ |
|
if (begin_remainder_ == end_remainder_ |
|
|| offset_ + buffer_size(first_) >= max_size_) |
|
{ |
|
at_end_ = true; |
|
} |
|
else |
|
{ |
|
offset_ += buffer_size(first_); |
|
first_ = buffer(*begin_remainder_++, max_size_ - offset_); |
|
} |
|
} |
|
} |
|
|
|
bool equal(const consuming_buffers_iterator& other) const |
|
{ |
|
if (at_end_ && other.at_end_) |
|
return true; |
|
return !at_end_ && !other.at_end_ |
|
&& buffer_cast<const void*>(first_) |
|
== buffer_cast<const void*>(other.first_) |
|
&& buffer_size(first_) == buffer_size(other.first_) |
|
&& begin_remainder_ == other.begin_remainder_ |
|
&& end_remainder_ == other.end_remainder_; |
|
} |
|
|
|
const Buffer& dereference() const |
|
{ |
|
return first_; |
|
} |
|
|
|
bool at_end_; |
|
Buffer first_; |
|
Buffer_Iterator begin_remainder_; |
|
Buffer_Iterator end_remainder_; |
|
std::size_t offset_; |
|
std::size_t max_size_; |
|
}; |
|
|
|
// A proxy for a sub-range in a list of buffers. |
|
template <typename Buffer, typename Buffers> |
|
class consuming_buffers |
|
{ |
|
public: |
|
// The type for each element in the list of buffers. |
|
typedef Buffer value_type; |
|
|
|
// A forward-only iterator type that may be used to read elements. |
|
typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator> |
|
const_iterator; |
|
|
|
// Construct to represent the entire list of buffers. |
|
consuming_buffers(const Buffers& buffers) |
|
: buffers_(buffers), |
|
at_end_(buffers_.begin() == buffers_.end()), |
|
begin_remainder_(buffers_.begin()), |
|
max_size_((std::numeric_limits<std::size_t>::max)()) |
|
{ |
|
if (!at_end_) |
|
{ |
|
first_ = *buffers_.begin(); |
|
++begin_remainder_; |
|
} |
|
} |
|
|
|
// Copy constructor. |
|
consuming_buffers(const consuming_buffers& other) |
|
: buffers_(other.buffers_), |
|
at_end_(other.at_end_), |
|
first_(other.first_), |
|
begin_remainder_(buffers_.begin()), |
|
max_size_(other.max_size_) |
|
{ |
|
typename Buffers::const_iterator first = other.buffers_.begin(); |
|
typename Buffers::const_iterator second = other.begin_remainder_; |
|
std::advance(begin_remainder_, std::distance(first, second)); |
|
} |
|
|
|
// Assignment operator. |
|
consuming_buffers& operator=(const consuming_buffers& other) |
|
{ |
|
buffers_ = other.buffers_; |
|
at_end_ = other.at_end_; |
|
first_ = other.first_; |
|
begin_remainder_ = buffers_.begin(); |
|
typename Buffers::const_iterator first = other.buffers_.begin(); |
|
typename Buffers::const_iterator second = other.begin_remainder_; |
|
std::advance(begin_remainder_, std::distance(first, second)); |
|
max_size_ = other.max_size_; |
|
return *this; |
|
} |
|
|
|
// Get a forward-only iterator to the first element. |
|
const_iterator begin() const |
|
{ |
|
return const_iterator(at_end_, first_, |
|
begin_remainder_, buffers_.end(), max_size_); |
|
} |
|
|
|
// Get a forward-only iterator for one past the last element. |
|
const_iterator end() const |
|
{ |
|
return const_iterator(); |
|
} |
|
|
|
// Set the maximum size for a single transfer. |
|
void prepare(std::size_t max_size) |
|
{ |
|
max_size_ = max_size; |
|
} |
|
|
|
// Consume the specified number of bytes from the buffers. |
|
void consume(std::size_t size) |
|
{ |
|
// Remove buffers from the start until the specified size is reached. |
|
while (size > 0 && !at_end_) |
|
{ |
|
if (buffer_size(first_) <= size) |
|
{ |
|
size -= buffer_size(first_); |
|
if (begin_remainder_ == buffers_.end()) |
|
at_end_ = true; |
|
else |
|
first_ = *begin_remainder_++; |
|
} |
|
else |
|
{ |
|
first_ = first_ + size; |
|
size = 0; |
|
} |
|
} |
|
|
|
// Remove any more empty buffers at the start. |
|
while (!at_end_ && buffer_size(first_) == 0) |
|
{ |
|
if (begin_remainder_ == buffers_.end()) |
|
at_end_ = true; |
|
else |
|
first_ = *begin_remainder_++; |
|
} |
|
} |
|
|
|
private: |
|
Buffers buffers_; |
|
bool at_end_; |
|
Buffer first_; |
|
typename Buffers::const_iterator begin_remainder_; |
|
std::size_t max_size_; |
|
}; |
|
|
|
// Specialisation for null_buffers to ensure that the null_buffers type is |
|
// always passed through to the underlying read or write operation. |
|
template <typename Buffer> |
|
class consuming_buffers<Buffer, boost::asio::null_buffers> |
|
: public boost::asio::null_buffers |
|
{ |
|
public: |
|
consuming_buffers(const boost::asio::null_buffers&) |
|
{ |
|
// No-op. |
|
} |
|
|
|
void prepare(std::size_t) |
|
{ |
|
// No-op. |
|
} |
|
|
|
void consume(std::size_t) |
|
{ |
|
// No-op. |
|
} |
|
}; |
|
|
|
} // namespace detail |
|
} // namespace asio |
|
} // namespace boost |
|
|
|
#include <boost/asio/detail/pop_options.hpp> |
|
|
|
#endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP
|
|
|