Home | History | Annotate | Download | only in detail
      1 //
      2 // detail/consuming_buffers.hpp
      3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      4 //
      5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
      6 //
      7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
      8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      9 //
     10 
     11 #ifndef ASIO_DETAIL_CONSUMING_BUFFERS_HPP
     12 #define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
     13 
     14 
     15 #include "asio/detail/config.hpp"
     16 #include <cstddef>
     17 #include <iterator>
     18 #include "asio/buffer.hpp"
     19 #include "asio/detail/limits.hpp"
     20 
     21 #include "asio/detail/push_options.hpp"
     22 
     23 namespace asio {
     24 namespace detail {
     25 
     26 // A proxy iterator for a sub-range in a list of buffers.
     27 template <typename Buffer, typename Buffer_Iterator>
     28 class consuming_buffers_iterator
     29 {
     30 public:
     31   /// The type used for the distance between two iterators.
     32   typedef std::ptrdiff_t difference_type;
     33 
     34   /// The type of the value pointed to by the iterator.
     35   typedef Buffer value_type;
     36 
     37   /// The type of the result of applying operator->() to the iterator.
     38   typedef const Buffer* pointer;
     39 
     40   /// The type of the result of applying operator*() to the iterator.
     41   typedef const Buffer& reference;
     42 
     43   /// The iterator category.
     44   typedef std::forward_iterator_tag iterator_category;
     45 
     46   // Default constructor creates an end iterator.
     47   consuming_buffers_iterator()
     48     : at_end_(true)
     49   {
     50   }
     51 
     52   // Construct with a buffer for the first entry and an iterator
     53   // range for the remaining entries.
     54   consuming_buffers_iterator(bool at_end, const Buffer& first,
     55       Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder,
     56       std::size_t max_size)
     57     : at_end_(max_size > 0 ? at_end : true),
     58       first_(buffer(first, max_size)),
     59       begin_remainder_(begin_remainder),
     60       end_remainder_(end_remainder),
     61       offset_(0),
     62       max_size_(max_size)
     63   {
     64   }
     65 
     66   // Dereference an iterator.
     67   const Buffer& operator*() const
     68   {
     69     return dereference();
     70   }
     71 
     72   // Dereference an iterator.
     73   const Buffer* operator->() const
     74   {
     75     return &dereference();
     76   }
     77 
     78   // Increment operator (prefix).
     79   consuming_buffers_iterator& operator++()
     80   {
     81     increment();
     82     return *this;
     83   }
     84 
     85   // Increment operator (postfix).
     86   consuming_buffers_iterator operator++(int)
     87   {
     88     consuming_buffers_iterator tmp(*this);
     89     ++*this;
     90     return tmp;
     91   }
     92 
     93   // Test two iterators for equality.
     94   friend bool operator==(const consuming_buffers_iterator& a,
     95       const consuming_buffers_iterator& b)
     96   {
     97     return a.equal(b);
     98   }
     99 
    100   // Test two iterators for inequality.
    101   friend bool operator!=(const consuming_buffers_iterator& a,
    102       const consuming_buffers_iterator& b)
    103   {
    104     return !a.equal(b);
    105   }
    106 
    107 private:
    108   void increment()
    109   {
    110     if (!at_end_)
    111     {
    112       if (begin_remainder_ == end_remainder_
    113           || offset_ + buffer_size(first_) >= max_size_)
    114       {
    115         at_end_ = true;
    116       }
    117       else
    118       {
    119         offset_ += buffer_size(first_);
    120         first_ = buffer(*begin_remainder_++, max_size_ - offset_);
    121       }
    122     }
    123   }
    124 
    125   bool equal(const consuming_buffers_iterator& other) const
    126   {
    127     if (at_end_ && other.at_end_)
    128       return true;
    129     return !at_end_ && !other.at_end_
    130       && buffer_cast<const void*>(first_)
    131         == buffer_cast<const void*>(other.first_)
    132       && buffer_size(first_) == buffer_size(other.first_)
    133       && begin_remainder_ == other.begin_remainder_
    134       && end_remainder_ == other.end_remainder_;
    135   }
    136 
    137   const Buffer& dereference() const
    138   {
    139     return first_;
    140   }
    141 
    142   bool at_end_;
    143   Buffer first_;
    144   Buffer_Iterator begin_remainder_;
    145   Buffer_Iterator end_remainder_;
    146   std::size_t offset_;
    147   std::size_t max_size_;
    148 };
    149 
    150 // A proxy for a sub-range in a list of buffers.
    151 template <typename Buffer, typename Buffers>
    152 class consuming_buffers
    153 {
    154 public:
    155   // The type for each element in the list of buffers.
    156   typedef Buffer value_type;
    157 
    158   // A forward-only iterator type that may be used to read elements.
    159   typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
    160     const_iterator;
    161 
    162   // Construct to represent the entire list of buffers.
    163   consuming_buffers(const Buffers& buffers)
    164     : buffers_(buffers),
    165       at_end_(buffers_.begin() == buffers_.end()),
    166       begin_remainder_(buffers_.begin()),
    167       max_size_((std::numeric_limits<std::size_t>::max)())
    168   {
    169     if (!at_end_)
    170     {
    171       first_ = *buffers_.begin();
    172       ++begin_remainder_;
    173     }
    174   }
    175 
    176   // Copy constructor.
    177   consuming_buffers(const consuming_buffers& other)
    178     : buffers_(other.buffers_),
    179       at_end_(other.at_end_),
    180       first_(other.first_),
    181       begin_remainder_(buffers_.begin()),
    182       max_size_(other.max_size_)
    183   {
    184     typename Buffers::const_iterator first = other.buffers_.begin();
    185     typename Buffers::const_iterator second = other.begin_remainder_;
    186     std::advance(begin_remainder_, std::distance(first, second));
    187   }
    188 
    189   // Assignment operator.
    190   consuming_buffers& operator=(const consuming_buffers& other)
    191   {
    192     buffers_ = other.buffers_;
    193     at_end_ = other.at_end_;
    194     first_ = other.first_;
    195     begin_remainder_ = buffers_.begin();
    196     typename Buffers::const_iterator first = other.buffers_.begin();
    197     typename Buffers::const_iterator second = other.begin_remainder_;
    198     std::advance(begin_remainder_, std::distance(first, second));
    199     max_size_ = other.max_size_;
    200     return *this;
    201   }
    202 
    203   // Get a forward-only iterator to the first element.
    204   const_iterator begin() const
    205   {
    206     return const_iterator(at_end_, first_,
    207         begin_remainder_, buffers_.end(), max_size_);
    208   }
    209 
    210   // Get a forward-only iterator for one past the last element.
    211   const_iterator end() const
    212   {
    213     return const_iterator();
    214   }
    215 
    216   // Set the maximum size for a single transfer.
    217   void prepare(std::size_t max_size)
    218   {
    219     max_size_ = max_size;
    220   }
    221 
    222   // Consume the specified number of bytes from the buffers.
    223   void consume(std::size_t size)
    224   {
    225     // Remove buffers from the start until the specified size is reached.
    226     while (size > 0 && !at_end_)
    227     {
    228       if (buffer_size(first_) <= size)
    229       {
    230         size -= buffer_size(first_);
    231         if (begin_remainder_ == buffers_.end())
    232           at_end_ = true;
    233         else
    234           first_ = *begin_remainder_++;
    235       }
    236       else
    237       {
    238         first_ = first_ + size;
    239         size = 0;
    240       }
    241     }
    242 
    243     // Remove any more empty buffers at the start.
    244     while (!at_end_ && buffer_size(first_) == 0)
    245     {
    246       if (begin_remainder_ == buffers_.end())
    247         at_end_ = true;
    248       else
    249         first_ = *begin_remainder_++;
    250     }
    251   }
    252 
    253 private:
    254   Buffers buffers_;
    255   bool at_end_;
    256   Buffer first_;
    257   typename Buffers::const_iterator begin_remainder_;
    258   std::size_t max_size_;
    259 };
    260 
    261 // Specialisation for null_buffers to ensure that the null_buffers type is
    262 // always passed through to the underlying read or write operation.
    263 template <typename Buffer>
    264 class consuming_buffers<Buffer, asio::null_buffers>
    265   : public asio::null_buffers
    266 {
    267 public:
    268   consuming_buffers(const asio::null_buffers&)
    269   {
    270     // No-op.
    271   }
    272 
    273   void prepare(std::size_t)
    274   {
    275     // No-op.
    276   }
    277 
    278   void consume(std::size_t)
    279   {
    280     // No-op.
    281   }
    282 };
    283 
    284 } // namespace detail
    285 } // namespace asio
    286 
    287 #include "asio/detail/pop_options.hpp"
    288 
    289 #endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP
    290