buffers_iterator.hpp
Go to the documentation of this file.
00001 //
00002 // buffers_iterator.hpp
00003 // ~~~~~~~~~~~~~~~~~~~~
00004 //
00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
00006 //
00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
00009 //
00010 
00011 #ifndef ASIO_BUFFERS_ITERATOR_HPP
00012 #define ASIO_BUFFERS_ITERATOR_HPP
00013 
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017 
00018 #include "asio/detail/push_options.hpp"
00019 
00020 #include "asio/detail/push_options.hpp"
00021 #include <cstddef>
00022 #include <boost/assert.hpp>
00023 #include <boost/config.hpp>
00024 #include <boost/iterator/iterator_facade.hpp>
00025 #include <boost/type_traits/is_convertible.hpp>
00026 #include <boost/type_traits/add_const.hpp>
00027 #include "asio/detail/pop_options.hpp"
00028 
00029 #include "asio/buffer.hpp"
00030 
00031 namespace asio {
00032 
00033 namespace detail
00034 {
00035   template <bool IsMutable>
00036   struct buffers_iterator_types_helper;
00037 
00038   template <>
00039   struct buffers_iterator_types_helper<false>
00040   {
00041     typedef const_buffer buffer_type;
00042     template <typename ByteType>
00043     struct byte_type
00044     {
00045       typedef typename boost::add_const<ByteType>::type type;
00046     };
00047   };
00048 
00049   template <>
00050   struct buffers_iterator_types_helper<true>
00051   {
00052     typedef mutable_buffer buffer_type;
00053     template <typename ByteType>
00054     struct byte_type
00055     {
00056       typedef ByteType type;
00057     };
00058   };
00059 
00060   template <typename BufferSequence, typename ByteType>
00061   struct buffers_iterator_types
00062   {
00063     enum
00064     {
00065       is_mutable = boost::is_convertible<
00066         typename BufferSequence::value_type, mutable_buffer>::value
00067     };
00068     typedef buffers_iterator_types_helper<is_mutable> helper;
00069     typedef typename helper::buffer_type buffer_type;
00070     typedef typename helper::template byte_type<ByteType>::type byte_type;
00071   };
00072 }
00073 
00075 template <typename BufferSequence, typename ByteType = char>
00076 class buffers_iterator
00077   : public boost::iterator_facade<
00078         buffers_iterator<BufferSequence, ByteType>,
00079         typename detail::buffers_iterator_types<
00080           BufferSequence, ByteType>::byte_type,
00081         boost::random_access_traversal_tag>
00082 {
00083 private:
00084   typedef typename detail::buffers_iterator_types<
00085       BufferSequence, ByteType>::buffer_type buffer_type;
00086   typedef typename detail::buffers_iterator_types<
00087       BufferSequence, ByteType>::byte_type byte_type;
00088 
00089 public:
00091   buffers_iterator()
00092     : current_buffer_(),
00093       current_buffer_position_(0),
00094       begin_(),
00095       current_(),
00096       end_(),
00097       position_(0)
00098   {
00099   }
00100 
00102   static buffers_iterator begin(const BufferSequence& buffers)
00103   {
00104     buffers_iterator new_iter;
00105     new_iter.begin_ = buffers.begin();
00106     new_iter.current_ = buffers.begin();
00107     new_iter.end_ = buffers.end();
00108     while (new_iter.current_ != new_iter.end_)
00109     {
00110       new_iter.current_buffer_ = *new_iter.current_;
00111       if (asio::buffer_size(new_iter.current_buffer_) > 0)
00112         break;
00113       ++new_iter.current_;
00114     }
00115     return new_iter;
00116   }
00117 
00119   static buffers_iterator end(const BufferSequence& buffers)
00120   {
00121     buffers_iterator new_iter;
00122     new_iter.begin_ = buffers.begin();
00123     new_iter.current_ = buffers.begin();
00124     new_iter.end_ = buffers.end();
00125     while (new_iter.current_ != new_iter.end_)
00126     {
00127       buffer_type buffer = *new_iter.current_;
00128       new_iter.position_ += asio::buffer_size(buffer);
00129       ++new_iter.current_;
00130     }
00131     return new_iter;
00132   }
00133 
00134 private:
00135   friend class boost::iterator_core_access;
00136 
00137   // Dereference the iterator.
00138   byte_type& dereference() const
00139   {
00140     return buffer_cast<byte_type*>(current_buffer_)[current_buffer_position_];
00141   }
00142 
00143   // Compare two iterators for equality.
00144   bool equal(const buffers_iterator& other) const
00145   {
00146     return position_ == other.position_;
00147   }
00148 
00149   // Increment the iterator.
00150   void increment()
00151   {
00152     BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
00153     ++position_;
00154 
00155     // Check if the increment can be satisfied by the current buffer.
00156     ++current_buffer_position_;
00157     if (current_buffer_position_ != asio::buffer_size(current_buffer_))
00158       return;
00159 
00160     // Find the next non-empty buffer.
00161     ++current_;
00162     current_buffer_position_ = 0;
00163     while (current_ != end_)
00164     {
00165       current_buffer_ = *current_;
00166       if (asio::buffer_size(current_buffer_) > 0)
00167         return;
00168       ++current_;
00169     }
00170   }
00171 
00172   // Decrement the iterator.
00173   void decrement()
00174   {
00175     BOOST_ASSERT(position_ > 0 && "iterator out of bounds");
00176     --position_;
00177 
00178     // Check if the decrement can be satisfied by the current buffer.
00179     if (current_buffer_position_ != 0)
00180     {
00181       --current_buffer_position_;
00182       return;
00183     }
00184 
00185     // Find the previous non-empty buffer.
00186     typename BufferSequence::const_iterator iter = current_;
00187     while (iter != begin_)
00188     {
00189       --iter;
00190       buffer_type buffer = *iter;
00191       std::size_t buffer_size = asio::buffer_size(buffer);
00192       if (buffer_size > 0)
00193       {
00194         current_ = iter;
00195         current_buffer_ = buffer;
00196         current_buffer_position_ = buffer_size - 1;
00197         return;
00198       }
00199     }
00200   }
00201 
00202   // Advance the iterator by the specified distance.
00203   void advance(std::ptrdiff_t n)
00204   {
00205     if (n > 0)
00206     {
00207       BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
00208       for (;;)
00209       {
00210         std::ptrdiff_t current_buffer_balance
00211           = asio::buffer_size(current_buffer_)
00212           - current_buffer_position_;
00213 
00214         // Check if the advance can be satisfied by the current buffer.
00215         if (current_buffer_balance > n)
00216         {
00217           position_ += n;
00218           current_buffer_position_ += n;
00219           return;
00220         }
00221 
00222         // Update position.
00223         n -= current_buffer_balance;
00224         position_ += current_buffer_balance;
00225 
00226         // Move to next buffer. If it is empty then it will be skipped on the
00227         // next iteration of this loop.
00228         if (++current_ == end_)
00229         {
00230           BOOST_ASSERT(n == 0 && "iterator out of bounds");
00231           current_buffer_ = buffer_type();
00232           current_buffer_position_ = 0;
00233           return;
00234         }
00235         current_buffer_ = *current_;
00236         current_buffer_position_ = 0;
00237       }
00238     }
00239     else if (n < 0)
00240     {
00241       std::size_t abs_n = -n;
00242       BOOST_ASSERT(position_ >= abs_n && "iterator out of bounds");
00243       for (;;)
00244       {
00245         // Check if the advance can be satisfied by the current buffer.
00246         if (current_buffer_position_ >= abs_n)
00247         {
00248           position_ -= abs_n;
00249           current_buffer_position_ -= abs_n;
00250           return;
00251         }
00252 
00253         // Update position.
00254         abs_n -= current_buffer_position_;
00255         position_ -= current_buffer_position_;
00256 
00257         // Check if we've reached the beginning of the buffers.
00258         if (current_ == begin_)
00259         {
00260           BOOST_ASSERT(abs_n == 0 && "iterator out of bounds");
00261           current_buffer_position_ = 0;
00262           return;
00263         }
00264 
00265         // Find the previous non-empty buffer.
00266         typename BufferSequence::const_iterator iter = current_;
00267         while (iter != begin_)
00268         {
00269           --iter;
00270           buffer_type buffer = *iter;
00271           std::size_t buffer_size = asio::buffer_size(buffer);
00272           if (buffer_size > 0)
00273           {
00274             current_ = iter;
00275             current_buffer_ = buffer;
00276             current_buffer_position_ = buffer_size;
00277             break;
00278           }
00279         }
00280       }
00281     }
00282   }
00283 
00284   // Determine the distance between two iterators.
00285   std::ptrdiff_t distance_to(const buffers_iterator& other) const
00286   {
00287     return other.position_ - position_;
00288   }
00289 
00290   buffer_type current_buffer_;
00291   std::size_t current_buffer_position_;
00292   typename BufferSequence::const_iterator begin_;
00293   typename BufferSequence::const_iterator current_;
00294   typename BufferSequence::const_iterator end_;
00295   std::size_t position_;
00296 };
00297 
00299 template <typename BufferSequence>
00300 inline buffers_iterator<BufferSequence> buffers_begin(
00301     const BufferSequence& buffers)
00302 {
00303   return buffers_iterator<BufferSequence>::begin(buffers);
00304 }
00305 
00307 template <typename BufferSequence>
00308 inline buffers_iterator<BufferSequence> buffers_end(
00309     const BufferSequence& buffers)
00310 {
00311   return buffers_iterator<BufferSequence>::end(buffers);
00312 }
00313 
00314 } // namespace asio
00315 
00316 #include "asio/detail/pop_options.hpp"
00317 
00318 #endif // ASIO_BUFFERS_ITERATOR_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39