blob: f6c6103740f7b143f830a093241d22b72d67f295 [file] [log] [blame]
//
// detail/consuming_buffers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 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 ASIO_DETAIL_CONSUMING_BUFFERS_HPP
#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include <iterator>
#include "asio/buffer.hpp"
#include "asio/detail/limits.hpp"
#include "asio/detail/push_options.hpp"
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:
/// The type used for the distance between two iterators.
typedef std::ptrdiff_t difference_type;
/// The type of the value pointed to by the iterator.
typedef Buffer value_type;
/// The type of the result of applying operator->() to the iterator.
typedef const Buffer* pointer;
/// The type of the result of applying operator*() to the iterator.
typedef const Buffer& reference;
/// The iterator category.
typedef std::forward_iterator_tag iterator_category;
// 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_ + first_.size() >= max_size_)
{
at_end_ = true;
}
else
{
offset_ += first_.size();
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_
&& first_.data() == other.first_.data()
&& first_.size() == other.first_.size()
&& 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 (first_.size() <= size)
{
size -= first_.size();
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_ && first_.size() == 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, asio::null_buffers>
: public asio::null_buffers
{
public:
consuming_buffers(const asio::null_buffers&)
{
// No-op.
}
void prepare(std::size_t)
{
// No-op.
}
void consume(std::size_t)
{
// No-op.
}
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP