$search
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