1 // 2 // buffers_iterator.hpp 3 // ~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2017 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 BOOST_ASIO_BUFFERS_ITERATOR_HPP 12 #define BOOST_ASIO_BUFFERS_ITERATOR_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include <boost/asio/detail/config.hpp> 19 #include <cstddef> 20 #include <iterator> 21 #include <boost/asio/buffer.hpp> 22 #include <boost/asio/detail/assert.hpp> 23 #include <boost/asio/detail/type_traits.hpp> 24 25 #include <boost/asio/detail/push_options.hpp> 26 27 namespace boost { 28 namespace asio { 29 30 namespace detail 31 { 32 template <bool IsMutable> 33 struct buffers_iterator_types_helper; 34 35 template <> 36 struct buffers_iterator_types_helper<false> 37 { 38 typedef const_buffer buffer_type; 39 template <typename ByteType> 40 struct byte_type 41 { 42 typedef typename add_const<ByteType>::type type; 43 }; 44 }; 45 46 template <> 47 struct buffers_iterator_types_helper<true> 48 { 49 typedef mutable_buffer buffer_type; 50 template <typename ByteType> 51 struct byte_type 52 { 53 typedef ByteType type; 54 }; 55 }; 56 57 template <typename BufferSequence, typename ByteType> 58 struct buffers_iterator_types 59 { 60 enum 61 { 62 is_mutable = is_convertible< 63 typename BufferSequence::value_type, 64 mutable_buffer>::value 65 }; 66 typedef buffers_iterator_types_helper<is_mutable> helper; 67 typedef typename helper::buffer_type buffer_type; 68 typedef typename helper::template byte_type<ByteType>::type byte_type; 69 typedef typename BufferSequence::const_iterator const_iterator; 70 }; 71 72 template <typename ByteType> 73 struct buffers_iterator_types<mutable_buffer, ByteType> 74 { 75 typedef mutable_buffer buffer_type; 76 typedef ByteType byte_type; 77 typedef const mutable_buffer* const_iterator; 78 }; 79 80 template <typename ByteType> 81 struct buffers_iterator_types<const_buffer, ByteType> 82 { 83 typedef const_buffer buffer_type; 84 typedef typename add_const<ByteType>::type byte_type; 85 typedef const const_buffer* const_iterator; 86 }; 87 88 #if !defined(BOOST_ASIO_NO_DEPRECATED) 89 90 template <typename ByteType> 91 struct buffers_iterator_types<mutable_buffers_1, ByteType> 92 { 93 typedef mutable_buffer buffer_type; 94 typedef ByteType byte_type; 95 typedef const mutable_buffer* const_iterator; 96 }; 97 98 template <typename ByteType> 99 struct buffers_iterator_types<const_buffers_1, ByteType> 100 { 101 typedef const_buffer buffer_type; 102 typedef typename add_const<ByteType>::type byte_type; 103 typedef const const_buffer* const_iterator; 104 }; 105 106 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 107 } 108 109 /// A random access iterator over the bytes in a buffer sequence. 110 template <typename BufferSequence, typename ByteType = char> 111 class buffers_iterator 112 { 113 private: 114 typedef typename detail::buffers_iterator_types< 115 BufferSequence, ByteType>::buffer_type buffer_type; 116 117 typedef typename detail::buffers_iterator_types<BufferSequence, 118 ByteType>::const_iterator buffer_sequence_iterator_type; 119 120 public: 121 /// The type used for the distance between two iterators. 122 typedef std::ptrdiff_t difference_type; 123 124 /// The type of the value pointed to by the iterator. 125 typedef ByteType value_type; 126 127 #if defined(GENERATING_DOCUMENTATION) 128 /// The type of the result of applying operator->() to the iterator. 129 /** 130 * If the buffer sequence stores buffer objects that are convertible to 131 * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a 132 * pointer to a const ByteType. 133 */ 134 typedef const_or_non_const_ByteType* pointer; 135 #else // defined(GENERATING_DOCUMENTATION) 136 typedef typename detail::buffers_iterator_types< 137 BufferSequence, ByteType>::byte_type* pointer; 138 #endif // defined(GENERATING_DOCUMENTATION) 139 140 #if defined(GENERATING_DOCUMENTATION) 141 /// The type of the result of applying operator*() to the iterator. 142 /** 143 * If the buffer sequence stores buffer objects that are convertible to 144 * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a 145 * reference to a const ByteType. 146 */ 147 typedef const_or_non_const_ByteType& reference; 148 #else // defined(GENERATING_DOCUMENTATION) 149 typedef typename detail::buffers_iterator_types< 150 BufferSequence, ByteType>::byte_type& reference; 151 #endif // defined(GENERATING_DOCUMENTATION) 152 153 /// The iterator category. 154 typedef std::random_access_iterator_tag iterator_category; 155 156 /// Default constructor. Creates an iterator in an undefined state. 157 buffers_iterator() 158 : current_buffer_(), 159 current_buffer_position_(0), 160 begin_(), 161 current_(), 162 end_(), 163 position_(0) 164 { 165 } 166 167 /// Construct an iterator representing the beginning of the buffers' data. 168 static buffers_iterator begin(const BufferSequence& buffers) 169 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) 170 __attribute__ ((__noinline__)) 171 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) 172 { 173 buffers_iterator new_iter; 174 new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers); 175 new_iter.current_ = boost::asio::buffer_sequence_begin(buffers); 176 new_iter.end_ = boost::asio::buffer_sequence_end(buffers); 177 while (new_iter.current_ != new_iter.end_) 178 { 179 new_iter.current_buffer_ = *new_iter.current_; 180 if (new_iter.current_buffer_.size() > 0) 181 break; 182 ++new_iter.current_; 183 } 184 return new_iter; 185 } 186 187 /// Construct an iterator representing the end of the buffers' data. 188 static buffers_iterator end(const BufferSequence& buffers) 189 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) 190 __attribute__ ((__noinline__)) 191 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) 192 { 193 buffers_iterator new_iter; 194 new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers); 195 new_iter.current_ = boost::asio::buffer_sequence_begin(buffers); 196 new_iter.end_ = boost::asio::buffer_sequence_end(buffers); 197 while (new_iter.current_ != new_iter.end_) 198 { 199 buffer_type buffer = *new_iter.current_; 200 new_iter.position_ += buffer.size(); 201 ++new_iter.current_; 202 } 203 return new_iter; 204 } 205 206 /// Dereference an iterator. 207 reference operator*() const 208 { 209 return dereference(); 210 } 211 212 /// Dereference an iterator. 213 pointer operator->() const 214 { 215 return &dereference(); 216 } 217 218 /// Access an individual element. 219 reference operator[](std::ptrdiff_t difference) const 220 { 221 buffers_iterator tmp(*this); 222 tmp.advance(difference); 223 return *tmp; 224 } 225 226 /// Increment operator (prefix). 227 buffers_iterator& operator++() 228 { 229 increment(); 230 return *this; 231 } 232 233 /// Increment operator (postfix). 234 buffers_iterator operator++(int) 235 { 236 buffers_iterator tmp(*this); 237 ++*this; 238 return tmp; 239 } 240 241 /// Decrement operator (prefix). 242 buffers_iterator& operator--() 243 { 244 decrement(); 245 return *this; 246 } 247 248 /// Decrement operator (postfix). 249 buffers_iterator operator--(int) 250 { 251 buffers_iterator tmp(*this); 252 --*this; 253 return tmp; 254 } 255 256 /// Addition operator. 257 buffers_iterator& operator+=(std::ptrdiff_t difference) 258 { 259 advance(difference); 260 return *this; 261 } 262 263 /// Subtraction operator. 264 buffers_iterator& operator-=(std::ptrdiff_t difference) 265 { 266 advance(-difference); 267 return *this; 268 } 269 270 /// Addition operator. 271 friend buffers_iterator operator+(const buffers_iterator& iter, 272 std::ptrdiff_t difference) 273 { 274 buffers_iterator tmp(iter); 275 tmp.advance(difference); 276 return tmp; 277 } 278 279 /// Addition operator. 280 friend buffers_iterator operator+(std::ptrdiff_t difference, 281 const buffers_iterator& iter) 282 { 283 buffers_iterator tmp(iter); 284 tmp.advance(difference); 285 return tmp; 286 } 287 288 /// Subtraction operator. 289 friend buffers_iterator operator-(const buffers_iterator& iter, 290 std::ptrdiff_t difference) 291 { 292 buffers_iterator tmp(iter); 293 tmp.advance(-difference); 294 return tmp; 295 } 296 297 /// Subtraction operator. 298 friend std::ptrdiff_t operator-(const buffers_iterator& a, 299 const buffers_iterator& b) 300 { 301 return b.distance_to(a); 302 } 303 304 /// Test two iterators for equality. 305 friend bool operator==(const buffers_iterator& a, const buffers_iterator& b) 306 { 307 return a.equal(b); 308 } 309 310 /// Test two iterators for inequality. 311 friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b) 312 { 313 return !a.equal(b); 314 } 315 316 /// Compare two iterators. 317 friend bool operator<(const buffers_iterator& a, const buffers_iterator& b) 318 { 319 return a.distance_to(b) > 0; 320 } 321 322 /// Compare two iterators. 323 friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b) 324 { 325 return !(b < a); 326 } 327 328 /// Compare two iterators. 329 friend bool operator>(const buffers_iterator& a, const buffers_iterator& b) 330 { 331 return b < a; 332 } 333 334 /// Compare two iterators. 335 friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b) 336 { 337 return !(a < b); 338 } 339 340 private: 341 // Dereference the iterator. 342 reference dereference() const 343 { 344 return static_cast<pointer>( 345 current_buffer_.data())[current_buffer_position_]; 346 } 347 348 // Compare two iterators for equality. 349 bool equal(const buffers_iterator& other) const 350 { 351 return position_ == other.position_; 352 } 353 354 // Increment the iterator. 355 void increment() 356 { 357 BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); 358 ++position_; 359 360 // Check if the increment can be satisfied by the current buffer. 361 ++current_buffer_position_; 362 if (current_buffer_position_ != current_buffer_.size()) 363 return; 364 365 // Find the next non-empty buffer. 366 ++current_; 367 current_buffer_position_ = 0; 368 while (current_ != end_) 369 { 370 current_buffer_ = *current_; 371 if (current_buffer_.size() > 0) 372 return; 373 ++current_; 374 } 375 } 376 377 // Decrement the iterator. 378 void decrement() 379 { 380 BOOST_ASIO_ASSERT(position_ > 0 && "iterator out of bounds"); 381 --position_; 382 383 // Check if the decrement can be satisfied by the current buffer. 384 if (current_buffer_position_ != 0) 385 { 386 --current_buffer_position_; 387 return; 388 } 389 390 // Find the previous non-empty buffer. 391 buffer_sequence_iterator_type iter = current_; 392 while (iter != begin_) 393 { 394 --iter; 395 buffer_type buffer = *iter; 396 std::size_t buffer_size = buffer.size(); 397 if (buffer_size > 0) 398 { 399 current_ = iter; 400 current_buffer_ = buffer; 401 current_buffer_position_ = buffer_size - 1; 402 return; 403 } 404 } 405 } 406 407 // Advance the iterator by the specified distance. 408 void advance(std::ptrdiff_t n) 409 { 410 if (n > 0) 411 { 412 BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); 413 for (;;) 414 { 415 std::ptrdiff_t current_buffer_balance 416 = current_buffer_.size() - current_buffer_position_; 417 418 // Check if the advance can be satisfied by the current buffer. 419 if (current_buffer_balance > n) 420 { 421 position_ += n; 422 current_buffer_position_ += n; 423 return; 424 } 425 426 // Update position. 427 n -= current_buffer_balance; 428 position_ += current_buffer_balance; 429 430 // Move to next buffer. If it is empty then it will be skipped on the 431 // next iteration of this loop. 432 if (++current_ == end_) 433 { 434 BOOST_ASIO_ASSERT(n == 0 && "iterator out of bounds"); 435 current_buffer_ = buffer_type(); 436 current_buffer_position_ = 0; 437 return; 438 } 439 current_buffer_ = *current_; 440 current_buffer_position_ = 0; 441 } 442 } 443 else if (n < 0) 444 { 445 std::size_t abs_n = -n; 446 BOOST_ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds"); 447 for (;;) 448 { 449 // Check if the advance can be satisfied by the current buffer. 450 if (current_buffer_position_ >= abs_n) 451 { 452 position_ -= abs_n; 453 current_buffer_position_ -= abs_n; 454 return; 455 } 456 457 // Update position. 458 abs_n -= current_buffer_position_; 459 position_ -= current_buffer_position_; 460 461 // Check if we've reached the beginning of the buffers. 462 if (current_ == begin_) 463 { 464 BOOST_ASIO_ASSERT(abs_n == 0 && "iterator out of bounds"); 465 current_buffer_position_ = 0; 466 return; 467 } 468 469 // Find the previous non-empty buffer. 470 buffer_sequence_iterator_type iter = current_; 471 while (iter != begin_) 472 { 473 --iter; 474 buffer_type buffer = *iter; 475 std::size_t buffer_size = buffer.size(); 476 if (buffer_size > 0) 477 { 478 current_ = iter; 479 current_buffer_ = buffer; 480 current_buffer_position_ = buffer_size; 481 break; 482 } 483 } 484 } 485 } 486 } 487 488 // Determine the distance between two iterators. 489 std::ptrdiff_t distance_to(const buffers_iterator& other) const 490 { 491 return other.position_ - position_; 492 } 493 494 buffer_type current_buffer_; 495 std::size_t current_buffer_position_; 496 buffer_sequence_iterator_type begin_; 497 buffer_sequence_iterator_type current_; 498 buffer_sequence_iterator_type end_; 499 std::size_t position_; 500 }; 501 502 /// Construct an iterator representing the beginning of the buffers' data. 503 template <typename BufferSequence> 504 inline buffers_iterator<BufferSequence> buffers_begin( 505 const BufferSequence& buffers) 506 { 507 return buffers_iterator<BufferSequence>::begin(buffers); 508 } 509 510 /// Construct an iterator representing the end of the buffers' data. 511 template <typename BufferSequence> 512 inline buffers_iterator<BufferSequence> buffers_end( 513 const BufferSequence& buffers) 514 { 515 return buffers_iterator<BufferSequence>::end(buffers); 516 } 517 518 } // namespace asio 519 } // namespace boost 520 521 #include <boost/asio/detail/pop_options.hpp> 522 523 #endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP 524