Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
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
00138 byte_type& dereference() const
00139 {
00140 return buffer_cast<byte_type*>(current_buffer_)[current_buffer_position_];
00141 }
00142
00143
00144 bool equal(const buffers_iterator& other) const
00145 {
00146 return position_ == other.position_;
00147 }
00148
00149
00150 void increment()
00151 {
00152 BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
00153 ++position_;
00154
00155
00156 ++current_buffer_position_;
00157 if (current_buffer_position_ != asio::buffer_size(current_buffer_))
00158 return;
00159
00160
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
00173 void decrement()
00174 {
00175 BOOST_ASSERT(position_ > 0 && "iterator out of bounds");
00176 --position_;
00177
00178
00179 if (current_buffer_position_ != 0)
00180 {
00181 --current_buffer_position_;
00182 return;
00183 }
00184
00185
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
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
00215 if (current_buffer_balance > n)
00216 {
00217 position_ += n;
00218 current_buffer_position_ += n;
00219 return;
00220 }
00221
00222
00223 n -= current_buffer_balance;
00224 position_ += current_buffer_balance;
00225
00226
00227
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
00246 if (current_buffer_position_ >= abs_n)
00247 {
00248 position_ -= abs_n;
00249 current_buffer_position_ -= abs_n;
00250 return;
00251 }
00252
00253
00254 abs_n -= current_buffer_position_;
00255 position_ -= current_buffer_position_;
00256
00257
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
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
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 }
00315
00316 #include "asio/detail/pop_options.hpp"
00317
00318 #endif // ASIO_BUFFERS_ITERATOR_HPP