1 // 2 // buffer.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_BUFFER_HPP 12 #define ASIO_BUFFER_HPP 13 14 15 #include "asio/detail/config.hpp" 16 #include <cstddef> 17 #include <cstring> 18 #include <string> 19 #include <vector> 20 #include "asio/detail/array_fwd.hpp" 21 22 23 #if defined(__GNUC__) 24 # if defined(_GLIBCXX_DEBUG) 25 # endif // defined(_GLIBCXX_DEBUG) 26 #endif // defined(__GNUC__) 27 28 29 30 #if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) 31 # include "asio/detail/type_traits.hpp" 32 #endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) 33 34 #include "asio/detail/push_options.hpp" 35 36 namespace asio { 37 38 class mutable_buffer; 39 class const_buffer; 40 41 namespace detail { 42 void* buffer_cast_helper(const mutable_buffer&); 43 const void* buffer_cast_helper(const const_buffer&); 44 std::size_t buffer_size_helper(const mutable_buffer&); 45 std::size_t buffer_size_helper(const const_buffer&); 46 } // namespace detail 47 48 /// Holds a buffer that can be modified. 49 /** 50 * The mutable_buffer class provides a safe representation of a buffer that can 51 * be modified. It does not own the underlying data, and so is cheap to copy or 52 * assign. 53 * 54 * @par Accessing Buffer Contents 55 * 56 * The contents of a buffer may be accessed using the @ref buffer_size 57 * and @ref buffer_cast functions: 58 * 59 * @code asio::mutable_buffer b1 = ...; 60 * std::size_t s1 = asio::buffer_size(b1); 61 * unsigned char* p1 = asio::buffer_cast<unsigned char*>(b1); 62 * @endcode 63 * 64 * The asio::buffer_cast function permits violations of type safety, so 65 * uses of it in application code should be carefully considered. 66 */ 67 class mutable_buffer 68 { 69 public: 70 /// Construct an empty buffer. 71 mutable_buffer() 72 : data_(0), 73 size_(0) 74 { 75 } 76 77 /// Construct a buffer to represent a given memory range. 78 mutable_buffer(void* data, std::size_t size) 79 : data_(data), 80 size_(size) 81 { 82 } 83 84 85 private: 86 friend void* asio::detail::buffer_cast_helper( 87 const mutable_buffer& b); 88 friend std::size_t asio::detail::buffer_size_helper( 89 const mutable_buffer& b); 90 91 void* data_; 92 std::size_t size_; 93 94 }; 95 96 namespace detail { 97 98 inline void* buffer_cast_helper(const mutable_buffer& b) 99 { 100 return b.data_; 101 } 102 103 inline std::size_t buffer_size_helper(const mutable_buffer& b) 104 { 105 return b.size_; 106 } 107 108 } // namespace detail 109 110 /// Adapts a single modifiable buffer so that it meets the requirements of the 111 /// MutableBufferSequence concept. 112 class mutable_buffers_1 113 : public mutable_buffer 114 { 115 public: 116 /// The type for each element in the list of buffers. 117 typedef mutable_buffer value_type; 118 119 /// A random-access iterator type that may be used to read elements. 120 typedef const mutable_buffer* const_iterator; 121 122 /// Construct to represent a given memory range. 123 mutable_buffers_1(void* data, std::size_t size) 124 : mutable_buffer(data, size) 125 { 126 } 127 128 /// Construct to represent a single modifiable buffer. 129 explicit mutable_buffers_1(const mutable_buffer& b) 130 : mutable_buffer(b) 131 { 132 } 133 134 /// Get a random-access iterator to the first element. 135 const_iterator begin() const 136 { 137 return this; 138 } 139 140 /// Get a random-access iterator for one past the last element. 141 const_iterator end() const 142 { 143 return begin() + 1; 144 } 145 }; 146 147 /// Holds a buffer that cannot be modified. 148 /** 149 * The const_buffer class provides a safe representation of a buffer that cannot 150 * be modified. It does not own the underlying data, and so is cheap to copy or 151 * assign. 152 * 153 * @par Accessing Buffer Contents 154 * 155 * The contents of a buffer may be accessed using the @ref buffer_size 156 * and @ref buffer_cast functions: 157 * 158 * @code asio::const_buffer b1 = ...; 159 * std::size_t s1 = asio::buffer_size(b1); 160 * const unsigned char* p1 = asio::buffer_cast<const unsigned char*>(b1); 161 * @endcode 162 * 163 * The asio::buffer_cast function permits violations of type safety, so 164 * uses of it in application code should be carefully considered. 165 */ 166 class const_buffer 167 { 168 public: 169 /// Construct an empty buffer. 170 const_buffer() 171 : data_(0), 172 size_(0) 173 { 174 } 175 176 /// Construct a buffer to represent a given memory range. 177 const_buffer(const void* data, std::size_t size) 178 : data_(data), 179 size_(size) 180 { 181 } 182 183 /// Construct a non-modifiable buffer from a modifiable one. 184 const_buffer(const mutable_buffer& b) 185 : data_(asio::detail::buffer_cast_helper(b)), 186 size_(asio::detail::buffer_size_helper(b)) 187 { 188 } 189 190 191 private: 192 friend const void* asio::detail::buffer_cast_helper( 193 const const_buffer& b); 194 friend std::size_t asio::detail::buffer_size_helper( 195 const const_buffer& b); 196 197 const void* data_; 198 std::size_t size_; 199 200 }; 201 202 namespace detail { 203 204 inline const void* buffer_cast_helper(const const_buffer& b) 205 { 206 return b.data_; 207 } 208 209 inline std::size_t buffer_size_helper(const const_buffer& b) 210 { 211 return b.size_; 212 } 213 214 } // namespace detail 215 216 /// Adapts a single non-modifiable buffer so that it meets the requirements of 217 /// the ConstBufferSequence concept. 218 class const_buffers_1 219 : public const_buffer 220 { 221 public: 222 /// The type for each element in the list of buffers. 223 typedef const_buffer value_type; 224 225 /// A random-access iterator type that may be used to read elements. 226 typedef const const_buffer* const_iterator; 227 228 /// Construct to represent a given memory range. 229 const_buffers_1(const void* data, std::size_t size) 230 : const_buffer(data, size) 231 { 232 } 233 234 /// Construct to represent a single non-modifiable buffer. 235 explicit const_buffers_1(const const_buffer& b) 236 : const_buffer(b) 237 { 238 } 239 240 /// Get a random-access iterator to the first element. 241 const_iterator begin() const 242 { 243 return this; 244 } 245 246 /// Get a random-access iterator for one past the last element. 247 const_iterator end() const 248 { 249 return begin() + 1; 250 } 251 }; 252 253 /// An implementation of both the ConstBufferSequence and MutableBufferSequence 254 /// concepts to represent a null buffer sequence. 255 class null_buffers 256 { 257 public: 258 /// The type for each element in the list of buffers. 259 typedef mutable_buffer value_type; 260 261 /// A random-access iterator type that may be used to read elements. 262 typedef const mutable_buffer* const_iterator; 263 264 /// Get a random-access iterator to the first element. 265 const_iterator begin() const 266 { 267 return &buf_; 268 } 269 270 /// Get a random-access iterator for one past the last element. 271 const_iterator end() const 272 { 273 return &buf_; 274 } 275 276 private: 277 mutable_buffer buf_; 278 }; 279 280 /** @defgroup buffer_size asio::buffer_size 281 * 282 * @brief The asio::buffer_size function determines the total number of 283 * bytes in a buffer or buffer sequence. 284 */ 285 /*@{*/ 286 287 /// Get the number of bytes in a modifiable buffer. 288 inline std::size_t buffer_size(const mutable_buffer& b) 289 { 290 return detail::buffer_size_helper(b); 291 } 292 293 /// Get the number of bytes in a modifiable buffer. 294 inline std::size_t buffer_size(const mutable_buffers_1& b) 295 { 296 return detail::buffer_size_helper(b); 297 } 298 299 /// Get the number of bytes in a non-modifiable buffer. 300 inline std::size_t buffer_size(const const_buffer& b) 301 { 302 return detail::buffer_size_helper(b); 303 } 304 305 /// Get the number of bytes in a non-modifiable buffer. 306 inline std::size_t buffer_size(const const_buffers_1& b) 307 { 308 return detail::buffer_size_helper(b); 309 } 310 311 /// Get the total number of bytes in a buffer sequence. 312 /** 313 * The @c BufferSequence template parameter may meet either of the @c 314 * ConstBufferSequence or @c MutableBufferSequence type requirements. 315 */ 316 template <typename BufferSequence> 317 inline std::size_t buffer_size(const BufferSequence& b) 318 { 319 std::size_t total_buffer_size = 0; 320 321 typename BufferSequence::const_iterator iter = b.begin(); 322 typename BufferSequence::const_iterator end = b.end(); 323 for (; iter != end; ++iter) 324 total_buffer_size += detail::buffer_size_helper(*iter); 325 326 return total_buffer_size; 327 } 328 329 /*@}*/ 330 331 /** @defgroup buffer_cast asio::buffer_cast 332 * 333 * @brief The asio::buffer_cast function is used to obtain a pointer to 334 * the underlying memory region associated with a buffer. 335 * 336 * @par Examples: 337 * 338 * To access the memory of a non-modifiable buffer, use: 339 * @code asio::const_buffer b1 = ...; 340 * const unsigned char* p1 = asio::buffer_cast<const unsigned char*>(b1); 341 * @endcode 342 * 343 * To access the memory of a modifiable buffer, use: 344 * @code asio::mutable_buffer b2 = ...; 345 * unsigned char* p2 = asio::buffer_cast<unsigned char*>(b2); 346 * @endcode 347 * 348 * The asio::buffer_cast function permits violations of type safety, so 349 * uses of it in application code should be carefully considered. 350 */ 351 /*@{*/ 352 353 /// Cast a non-modifiable buffer to a specified pointer to POD type. 354 template <typename PointerToPodType> 355 inline PointerToPodType buffer_cast(const mutable_buffer& b) 356 { 357 return static_cast<PointerToPodType>(detail::buffer_cast_helper(b)); 358 } 359 360 /// Cast a non-modifiable buffer to a specified pointer to POD type. 361 template <typename PointerToPodType> 362 inline PointerToPodType buffer_cast(const const_buffer& b) 363 { 364 return static_cast<PointerToPodType>(detail::buffer_cast_helper(b)); 365 } 366 367 /*@}*/ 368 369 /// Create a new modifiable buffer that is offset from the start of another. 370 /** 371 * @relates mutable_buffer 372 */ 373 inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start) 374 { 375 if (start > buffer_size(b)) 376 return mutable_buffer(); 377 char* new_data = buffer_cast<char*>(b) + start; 378 std::size_t new_size = buffer_size(b) - start; 379 return mutable_buffer(new_data, new_size 380 ); 381 } 382 383 /// Create a new modifiable buffer that is offset from the start of another. 384 /** 385 * @relates mutable_buffer 386 */ 387 inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b) 388 { 389 if (start > buffer_size(b)) 390 return mutable_buffer(); 391 char* new_data = buffer_cast<char*>(b) + start; 392 std::size_t new_size = buffer_size(b) - start; 393 return mutable_buffer(new_data, new_size 394 ); 395 } 396 397 /// Create a new non-modifiable buffer that is offset from the start of another. 398 /** 399 * @relates const_buffer 400 */ 401 inline const_buffer operator+(const const_buffer& b, std::size_t start) 402 { 403 if (start > buffer_size(b)) 404 return const_buffer(); 405 const char* new_data = buffer_cast<const char*>(b) + start; 406 std::size_t new_size = buffer_size(b) - start; 407 return const_buffer(new_data, new_size 408 ); 409 } 410 411 /// Create a new non-modifiable buffer that is offset from the start of another. 412 /** 413 * @relates const_buffer 414 */ 415 inline const_buffer operator+(std::size_t start, const const_buffer& b) 416 { 417 if (start > buffer_size(b)) 418 return const_buffer(); 419 const char* new_data = buffer_cast<const char*>(b) + start; 420 std::size_t new_size = buffer_size(b) - start; 421 return const_buffer(new_data, new_size 422 ); 423 } 424 425 426 /** @defgroup buffer asio::buffer 427 * 428 * @brief The asio::buffer function is used to create a buffer object to 429 * represent raw memory, an array of POD elements, a vector of POD elements, 430 * or a std::string. 431 * 432 * A buffer object represents a contiguous region of memory as a 2-tuple 433 * consisting of a pointer and size in bytes. A tuple of the form <tt>{void*, 434 * size_t}</tt> specifies a mutable (modifiable) region of memory. Similarly, a 435 * tuple of the form <tt>{const void*, size_t}</tt> specifies a const 436 * (non-modifiable) region of memory. These two forms correspond to the classes 437 * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion 438 * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the 439 * opposite conversion is not permitted. 440 * 441 * The simplest use case involves reading or writing a single buffer of a 442 * specified size: 443 * 444 * @code sock.send(asio::buffer(data, size)); @endcode 445 * 446 * In the above example, the return value of asio::buffer meets the 447 * requirements of the ConstBufferSequence concept so that it may be directly 448 * passed to the socket's write function. A buffer created for modifiable 449 * memory also meets the requirements of the MutableBufferSequence concept. 450 * 451 * An individual buffer may be created from a builtin array, std::vector, 452 * std::array or boost::array of POD elements. This helps prevent buffer 453 * overruns by automatically determining the size of the buffer: 454 * 455 * @code char d1[128]; 456 * size_t bytes_transferred = sock.receive(asio::buffer(d1)); 457 * 458 * std::vector<char> d2(128); 459 * bytes_transferred = sock.receive(asio::buffer(d2)); 460 * 461 * std::array<char, 128> d3; 462 * bytes_transferred = sock.receive(asio::buffer(d3)); 463 * 464 * boost::array<char, 128> d4; 465 * bytes_transferred = sock.receive(asio::buffer(d4)); @endcode 466 * 467 * In all three cases above, the buffers created are exactly 128 bytes long. 468 * Note that a vector is @e never automatically resized when creating or using 469 * a buffer. The buffer size is determined using the vector's <tt>size()</tt> 470 * member function, and not its capacity. 471 * 472 * @par Accessing Buffer Contents 473 * 474 * The contents of a buffer may be accessed using the @ref buffer_size and 475 * @ref buffer_cast functions: 476 * 477 * @code asio::mutable_buffer b1 = ...; 478 * std::size_t s1 = asio::buffer_size(b1); 479 * unsigned char* p1 = asio::buffer_cast<unsigned char*>(b1); 480 * 481 * asio::const_buffer b2 = ...; 482 * std::size_t s2 = asio::buffer_size(b2); 483 * const void* p2 = asio::buffer_cast<const void*>(b2); @endcode 484 * 485 * The asio::buffer_cast function permits violations of type safety, so 486 * uses of it in application code should be carefully considered. 487 * 488 * For convenience, the @ref buffer_size function also works on buffer 489 * sequences (that is, types meeting the ConstBufferSequence or 490 * MutableBufferSequence type requirements). In this case, the function returns 491 * the total size of all buffers in the sequence. 492 * 493 * @par Buffer Copying 494 * 495 * The @ref buffer_copy function may be used to copy raw bytes between 496 * individual buffers and buffer sequences. 497 * 498 * In particular, when used with the @ref buffer_size, the @ref buffer_copy 499 * function can be used to linearise a sequence of buffers. For example: 500 * 501 * @code vector<const_buffer> buffers = ...; 502 * 503 * vector<unsigned char> data(asio::buffer_size(buffers)); 504 * asio::buffer_copy(asio::buffer(data), buffers); @endcode 505 * 506 * Note that @ref buffer_copy is implemented in terms of @c memcpy, and 507 * consequently it cannot be used to copy between overlapping memory regions. 508 * 509 * @par Buffer Invalidation 510 * 511 * A buffer object does not have any ownership of the memory it refers to. It 512 * is the responsibility of the application to ensure the memory region remains 513 * valid until it is no longer required for an I/O operation. When the memory 514 * is no longer available, the buffer is said to have been invalidated. 515 * 516 * For the asio::buffer overloads that accept an argument of type 517 * std::vector, the buffer objects returned are invalidated by any vector 518 * operation that also invalidates all references, pointers and iterators 519 * referring to the elements in the sequence (C++ Std, 23.2.4) 520 * 521 * For the asio::buffer overloads that accept an argument of type 522 * std::basic_string, the buffer objects returned are invalidated according to 523 * the rules defined for invalidation of references, pointers and iterators 524 * referring to elements of the sequence (C++ Std, 21.3). 525 * 526 * @par Buffer Arithmetic 527 * 528 * Buffer objects may be manipulated using simple arithmetic in a safe way 529 * which helps prevent buffer overruns. Consider an array initialised as 530 * follows: 531 * 532 * @code boost::array<char, 6> a = { 'a', 'b', 'c', 'd', 'e' }; @endcode 533 * 534 * A buffer object @c b1 created using: 535 * 536 * @code b1 = asio::buffer(a); @endcode 537 * 538 * represents the entire array, <tt>{ 'a', 'b', 'c', 'd', 'e' }</tt>. An 539 * optional second argument to the asio::buffer function may be used to 540 * limit the size, in bytes, of the buffer: 541 * 542 * @code b2 = asio::buffer(a, 3); @endcode 543 * 544 * such that @c b2 represents the data <tt>{ 'a', 'b', 'c' }</tt>. Even if the 545 * size argument exceeds the actual size of the array, the size of the buffer 546 * object created will be limited to the array size. 547 * 548 * An offset may be applied to an existing buffer to create a new one: 549 * 550 * @code b3 = b1 + 2; @endcode 551 * 552 * where @c b3 will set to represent <tt>{ 'c', 'd', 'e' }</tt>. If the offset 553 * exceeds the size of the existing buffer, the newly created buffer will be 554 * empty. 555 * 556 * Both an offset and size may be specified to create a buffer that corresponds 557 * to a specific range of bytes within an existing buffer: 558 * 559 * @code b4 = asio::buffer(b1 + 1, 3); @endcode 560 * 561 * so that @c b4 will refer to the bytes <tt>{ 'b', 'c', 'd' }</tt>. 562 * 563 * @par Buffers and Scatter-Gather I/O 564 * 565 * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple 566 * buffer objects may be assigned into a container that supports the 567 * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts: 568 * 569 * @code 570 * char d1[128]; 571 * std::vector<char> d2(128); 572 * boost::array<char, 128> d3; 573 * 574 * boost::array<mutable_buffer, 3> bufs1 = { 575 * asio::buffer(d1), 576 * asio::buffer(d2), 577 * asio::buffer(d3) }; 578 * bytes_transferred = sock.receive(bufs1); 579 * 580 * std::vector<const_buffer> bufs2; 581 * bufs2.push_back(asio::buffer(d1)); 582 * bufs2.push_back(asio::buffer(d2)); 583 * bufs2.push_back(asio::buffer(d3)); 584 * bytes_transferred = sock.send(bufs2); @endcode 585 */ 586 /*@{*/ 587 588 /// Create a new modifiable buffer from an existing buffer. 589 /** 590 * @returns <tt>mutable_buffers_1(b)</tt>. 591 */ 592 inline mutable_buffers_1 buffer(const mutable_buffer& b) 593 { 594 return mutable_buffers_1(b); 595 } 596 597 /// Create a new modifiable buffer from an existing buffer. 598 /** 599 * @returns A mutable_buffers_1 value equivalent to: 600 * @code mutable_buffers_1( 601 * buffer_cast<void*>(b), 602 * min(buffer_size(b), max_size_in_bytes)); @endcode 603 */ 604 inline mutable_buffers_1 buffer(const mutable_buffer& b, 605 std::size_t max_size_in_bytes) 606 { 607 return mutable_buffers_1( 608 mutable_buffer(buffer_cast<void*>(b), 609 buffer_size(b) < max_size_in_bytes 610 ? buffer_size(b) : max_size_in_bytes 611 )); 612 } 613 614 /// Create a new non-modifiable buffer from an existing buffer. 615 /** 616 * @returns <tt>const_buffers_1(b)</tt>. 617 */ 618 inline const_buffers_1 buffer(const const_buffer& b) 619 { 620 return const_buffers_1(b); 621 } 622 623 /// Create a new non-modifiable buffer from an existing buffer. 624 /** 625 * @returns A const_buffers_1 value equivalent to: 626 * @code const_buffers_1( 627 * buffer_cast<const void*>(b), 628 * min(buffer_size(b), max_size_in_bytes)); @endcode 629 */ 630 inline const_buffers_1 buffer(const const_buffer& b, 631 std::size_t max_size_in_bytes) 632 { 633 return const_buffers_1( 634 const_buffer(buffer_cast<const void*>(b), 635 buffer_size(b) < max_size_in_bytes 636 ? buffer_size(b) : max_size_in_bytes 637 )); 638 } 639 640 /// Create a new modifiable buffer that represents the given memory range. 641 /** 642 * @returns <tt>mutable_buffers_1(data, size_in_bytes)</tt>. 643 */ 644 inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes) 645 { 646 return mutable_buffers_1(mutable_buffer(data, size_in_bytes)); 647 } 648 649 /// Create a new non-modifiable buffer that represents the given memory range. 650 /** 651 * @returns <tt>const_buffers_1(data, size_in_bytes)</tt>. 652 */ 653 inline const_buffers_1 buffer(const void* data, 654 std::size_t size_in_bytes) 655 { 656 return const_buffers_1(const_buffer(data, size_in_bytes)); 657 } 658 659 /// Create a new modifiable buffer that represents the given POD array. 660 /** 661 * @returns A mutable_buffers_1 value equivalent to: 662 * @code mutable_buffers_1( 663 * static_cast<void*>(data), 664 * N * sizeof(PodType)); @endcode 665 */ 666 template <typename PodType, std::size_t N> 667 inline mutable_buffers_1 buffer(PodType (&data)[N]) 668 { 669 return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType))); 670 } 671 672 /// Create a new modifiable buffer that represents the given POD array. 673 /** 674 * @returns A mutable_buffers_1 value equivalent to: 675 * @code mutable_buffers_1( 676 * static_cast<void*>(data), 677 * min(N * sizeof(PodType), max_size_in_bytes)); @endcode 678 */ 679 template <typename PodType, std::size_t N> 680 inline mutable_buffers_1 buffer(PodType (&data)[N], 681 std::size_t max_size_in_bytes) 682 { 683 return mutable_buffers_1( 684 mutable_buffer(data, 685 N * sizeof(PodType) < max_size_in_bytes 686 ? N * sizeof(PodType) : max_size_in_bytes)); 687 } 688 689 /// Create a new non-modifiable buffer that represents the given POD array. 690 /** 691 * @returns A const_buffers_1 value equivalent to: 692 * @code const_buffers_1( 693 * static_cast<const void*>(data), 694 * N * sizeof(PodType)); @endcode 695 */ 696 template <typename PodType, std::size_t N> 697 inline const_buffers_1 buffer(const PodType (&data)[N]) 698 { 699 return const_buffers_1(const_buffer(data, N * sizeof(PodType))); 700 } 701 702 /// Create a new non-modifiable buffer that represents the given POD array. 703 /** 704 * @returns A const_buffers_1 value equivalent to: 705 * @code const_buffers_1( 706 * static_cast<const void*>(data), 707 * min(N * sizeof(PodType), max_size_in_bytes)); @endcode 708 */ 709 template <typename PodType, std::size_t N> 710 inline const_buffers_1 buffer(const PodType (&data)[N], 711 std::size_t max_size_in_bytes) 712 { 713 return const_buffers_1( 714 const_buffer(data, 715 N * sizeof(PodType) < max_size_in_bytes 716 ? N * sizeof(PodType) : max_size_in_bytes)); 717 } 718 719 #if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) 720 721 // Borland C++ and Sun Studio think the overloads: 722 // 723 // unspecified buffer(boost::array<PodType, N>& array ...); 724 // 725 // and 726 // 727 // unspecified buffer(boost::array<const PodType, N>& array ...); 728 // 729 // are ambiguous. This will be worked around by using a buffer_types traits 730 // class that contains typedefs for the appropriate buffer and container 731 // classes, based on whether PodType is const or non-const. 732 733 namespace detail { 734 735 template <bool IsConst> 736 struct buffer_types_base; 737 738 template <> 739 struct buffer_types_base<false> 740 { 741 typedef mutable_buffer buffer_type; 742 typedef mutable_buffers_1 container_type; 743 }; 744 745 template <> 746 struct buffer_types_base<true> 747 { 748 typedef const_buffer buffer_type; 749 typedef const_buffers_1 container_type; 750 }; 751 752 template <typename PodType> 753 struct buffer_types 754 : public buffer_types_base<is_const<PodType>::value> 755 { 756 }; 757 758 } // namespace detail 759 760 template <typename PodType, std::size_t N> 761 inline typename detail::buffer_types<PodType>::container_type 762 buffer(boost::array<PodType, N>& data) 763 { 764 typedef typename asio::detail::buffer_types<PodType>::buffer_type 765 buffer_type; 766 typedef typename asio::detail::buffer_types<PodType>::container_type 767 container_type; 768 return container_type( 769 buffer_type(data.c_array(), data.size() * sizeof(PodType))); 770 } 771 772 template <typename PodType, std::size_t N> 773 inline typename detail::buffer_types<PodType>::container_type 774 buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes) 775 { 776 typedef typename asio::detail::buffer_types<PodType>::buffer_type 777 buffer_type; 778 typedef typename asio::detail::buffer_types<PodType>::container_type 779 container_type; 780 return container_type( 781 buffer_type(data.c_array(), 782 data.size() * sizeof(PodType) < max_size_in_bytes 783 ? data.size() * sizeof(PodType) : max_size_in_bytes)); 784 } 785 786 #else // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) 787 788 /// Create a new modifiable buffer that represents the given POD array. 789 /** 790 * @returns A mutable_buffers_1 value equivalent to: 791 * @code mutable_buffers_1( 792 * data.data(), 793 * data.size() * sizeof(PodType)); @endcode 794 */ 795 template <typename PodType, std::size_t N> 796 inline mutable_buffers_1 buffer(boost::array<PodType, N>& data) 797 { 798 return mutable_buffers_1( 799 mutable_buffer(data.c_array(), data.size() * sizeof(PodType))); 800 } 801 802 /// Create a new modifiable buffer that represents the given POD array. 803 /** 804 * @returns A mutable_buffers_1 value equivalent to: 805 * @code mutable_buffers_1( 806 * data.data(), 807 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 808 */ 809 template <typename PodType, std::size_t N> 810 inline mutable_buffers_1 buffer(boost::array<PodType, N>& data, 811 std::size_t max_size_in_bytes) 812 { 813 return mutable_buffers_1( 814 mutable_buffer(data.c_array(), 815 data.size() * sizeof(PodType) < max_size_in_bytes 816 ? data.size() * sizeof(PodType) : max_size_in_bytes)); 817 } 818 819 /// Create a new non-modifiable buffer that represents the given POD array. 820 /** 821 * @returns A const_buffers_1 value equivalent to: 822 * @code const_buffers_1( 823 * data.data(), 824 * data.size() * sizeof(PodType)); @endcode 825 */ 826 template <typename PodType, std::size_t N> 827 inline const_buffers_1 buffer(boost::array<const PodType, N>& data) 828 { 829 return const_buffers_1( 830 const_buffer(data.data(), data.size() * sizeof(PodType))); 831 } 832 833 /// Create a new non-modifiable buffer that represents the given POD array. 834 /** 835 * @returns A const_buffers_1 value equivalent to: 836 * @code const_buffers_1( 837 * data.data(), 838 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 839 */ 840 template <typename PodType, std::size_t N> 841 inline const_buffers_1 buffer(boost::array<const PodType, N>& data, 842 std::size_t max_size_in_bytes) 843 { 844 return const_buffers_1( 845 const_buffer(data.data(), 846 data.size() * sizeof(PodType) < max_size_in_bytes 847 ? data.size() * sizeof(PodType) : max_size_in_bytes)); 848 } 849 850 #endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) 851 852 /// Create a new non-modifiable buffer that represents the given POD array. 853 /** 854 * @returns A const_buffers_1 value equivalent to: 855 * @code const_buffers_1( 856 * data.data(), 857 * data.size() * sizeof(PodType)); @endcode 858 */ 859 template <typename PodType, std::size_t N> 860 inline const_buffers_1 buffer(const boost::array<PodType, N>& data) 861 { 862 return const_buffers_1( 863 const_buffer(data.data(), data.size() * sizeof(PodType))); 864 } 865 866 /// Create a new non-modifiable buffer that represents the given POD array. 867 /** 868 * @returns A const_buffers_1 value equivalent to: 869 * @code const_buffers_1( 870 * data.data(), 871 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 872 */ 873 template <typename PodType, std::size_t N> 874 inline const_buffers_1 buffer(const boost::array<PodType, N>& data, 875 std::size_t max_size_in_bytes) 876 { 877 return const_buffers_1( 878 const_buffer(data.data(), 879 data.size() * sizeof(PodType) < max_size_in_bytes 880 ? data.size() * sizeof(PodType) : max_size_in_bytes)); 881 } 882 883 884 /// Create a new modifiable buffer that represents the given POD array. 885 /** 886 * @returns A mutable_buffers_1 value equivalent to: 887 * @code mutable_buffers_1( 888 * data.data(), 889 * data.size() * sizeof(PodType)); @endcode 890 */ 891 template <typename PodType, std::size_t N> 892 inline mutable_buffers_1 buffer(std::array<PodType, N>& data) 893 { 894 return mutable_buffers_1( 895 mutable_buffer(data.data(), data.size() * sizeof(PodType))); 896 } 897 898 /// Create a new modifiable buffer that represents the given POD array. 899 /** 900 * @returns A mutable_buffers_1 value equivalent to: 901 * @code mutable_buffers_1( 902 * data.data(), 903 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 904 */ 905 template <typename PodType, std::size_t N> 906 inline mutable_buffers_1 buffer(std::array<PodType, N>& data, 907 std::size_t max_size_in_bytes) 908 { 909 return mutable_buffers_1( 910 mutable_buffer(data.data(), 911 data.size() * sizeof(PodType) < max_size_in_bytes 912 ? data.size() * sizeof(PodType) : max_size_in_bytes)); 913 } 914 915 /// Create a new non-modifiable buffer that represents the given POD array. 916 /** 917 * @returns A const_buffers_1 value equivalent to: 918 * @code const_buffers_1( 919 * data.data(), 920 * data.size() * sizeof(PodType)); @endcode 921 */ 922 template <typename PodType, std::size_t N> 923 inline const_buffers_1 buffer(std::array<const PodType, N>& data) 924 { 925 return const_buffers_1( 926 const_buffer(data.data(), data.size() * sizeof(PodType))); 927 } 928 929 /// Create a new non-modifiable buffer that represents the given POD array. 930 /** 931 * @returns A const_buffers_1 value equivalent to: 932 * @code const_buffers_1( 933 * data.data(), 934 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 935 */ 936 template <typename PodType, std::size_t N> 937 inline const_buffers_1 buffer(std::array<const PodType, N>& data, 938 std::size_t max_size_in_bytes) 939 { 940 return const_buffers_1( 941 const_buffer(data.data(), 942 data.size() * sizeof(PodType) < max_size_in_bytes 943 ? data.size() * sizeof(PodType) : max_size_in_bytes)); 944 } 945 946 /// Create a new non-modifiable buffer that represents the given POD array. 947 /** 948 * @returns A const_buffers_1 value equivalent to: 949 * @code const_buffers_1( 950 * data.data(), 951 * data.size() * sizeof(PodType)); @endcode 952 */ 953 template <typename PodType, std::size_t N> 954 inline const_buffers_1 buffer(const std::array<PodType, N>& data) 955 { 956 return const_buffers_1( 957 const_buffer(data.data(), data.size() * sizeof(PodType))); 958 } 959 960 /// Create a new non-modifiable buffer that represents the given POD array. 961 /** 962 * @returns A const_buffers_1 value equivalent to: 963 * @code const_buffers_1( 964 * data.data(), 965 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 966 */ 967 template <typename PodType, std::size_t N> 968 inline const_buffers_1 buffer(const std::array<PodType, N>& data, 969 std::size_t max_size_in_bytes) 970 { 971 return const_buffers_1( 972 const_buffer(data.data(), 973 data.size() * sizeof(PodType) < max_size_in_bytes 974 ? data.size() * sizeof(PodType) : max_size_in_bytes)); 975 } 976 977 978 /// Create a new modifiable buffer that represents the given POD vector. 979 /** 980 * @returns A mutable_buffers_1 value equivalent to: 981 * @code mutable_buffers_1( 982 * data.size() ? &data[0] : 0, 983 * data.size() * sizeof(PodType)); @endcode 984 * 985 * @note The buffer is invalidated by any vector operation that would also 986 * invalidate iterators. 987 */ 988 template <typename PodType, typename Allocator> 989 inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data) 990 { 991 return mutable_buffers_1( 992 mutable_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) 993 )); 994 } 995 996 /// Create a new modifiable buffer that represents the given POD vector. 997 /** 998 * @returns A mutable_buffers_1 value equivalent to: 999 * @code mutable_buffers_1( 1000 * data.size() ? &data[0] : 0, 1001 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 1002 * 1003 * @note The buffer is invalidated by any vector operation that would also 1004 * invalidate iterators. 1005 */ 1006 template <typename PodType, typename Allocator> 1007 inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data, 1008 std::size_t max_size_in_bytes) 1009 { 1010 return mutable_buffers_1( 1011 mutable_buffer(data.size() ? &data[0] : 0, 1012 data.size() * sizeof(PodType) < max_size_in_bytes 1013 ? data.size() * sizeof(PodType) : max_size_in_bytes 1014 )); 1015 } 1016 1017 /// Create a new non-modifiable buffer that represents the given POD vector. 1018 /** 1019 * @returns A const_buffers_1 value equivalent to: 1020 * @code const_buffers_1( 1021 * data.size() ? &data[0] : 0, 1022 * data.size() * sizeof(PodType)); @endcode 1023 * 1024 * @note The buffer is invalidated by any vector operation that would also 1025 * invalidate iterators. 1026 */ 1027 template <typename PodType, typename Allocator> 1028 inline const_buffers_1 buffer( 1029 const std::vector<PodType, Allocator>& data) 1030 { 1031 return const_buffers_1( 1032 const_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) 1033 )); 1034 } 1035 1036 /// Create a new non-modifiable buffer that represents the given POD vector. 1037 /** 1038 * @returns A const_buffers_1 value equivalent to: 1039 * @code const_buffers_1( 1040 * data.size() ? &data[0] : 0, 1041 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode 1042 * 1043 * @note The buffer is invalidated by any vector operation that would also 1044 * invalidate iterators. 1045 */ 1046 template <typename PodType, typename Allocator> 1047 inline const_buffers_1 buffer( 1048 const std::vector<PodType, Allocator>& data, std::size_t max_size_in_bytes) 1049 { 1050 return const_buffers_1( 1051 const_buffer(data.size() ? &data[0] : 0, 1052 data.size() * sizeof(PodType) < max_size_in_bytes 1053 ? data.size() * sizeof(PodType) : max_size_in_bytes 1054 )); 1055 } 1056 1057 /// Create a new non-modifiable buffer that represents the given string. 1058 /** 1059 * @returns <tt>const_buffers_1(data.data(), data.size() * sizeof(Elem))</tt>. 1060 * 1061 * @note The buffer is invalidated by any non-const operation called on the 1062 * given string object. 1063 */ 1064 template <typename Elem, typename Traits, typename Allocator> 1065 inline const_buffers_1 buffer( 1066 const std::basic_string<Elem, Traits, Allocator>& data) 1067 { 1068 return const_buffers_1(const_buffer(data.data(), data.size() * sizeof(Elem) 1069 )); 1070 } 1071 1072 /// Create a new non-modifiable buffer that represents the given string. 1073 /** 1074 * @returns A const_buffers_1 value equivalent to: 1075 * @code const_buffers_1( 1076 * data.data(), 1077 * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode 1078 * 1079 * @note The buffer is invalidated by any non-const operation called on the 1080 * given string object. 1081 */ 1082 template <typename Elem, typename Traits, typename Allocator> 1083 inline const_buffers_1 buffer( 1084 const std::basic_string<Elem, Traits, Allocator>& data, 1085 std::size_t max_size_in_bytes) 1086 { 1087 return const_buffers_1( 1088 const_buffer(data.data(), 1089 data.size() * sizeof(Elem) < max_size_in_bytes 1090 ? data.size() * sizeof(Elem) : max_size_in_bytes 1091 )); 1092 } 1093 1094 /*@}*/ 1095 1096 /** @defgroup buffer_copy asio::buffer_copy 1097 * 1098 * @brief The asio::buffer_copy function is used to copy bytes from a 1099 * source buffer (or buffer sequence) to a target buffer (or buffer sequence). 1100 * 1101 * The @c buffer_copy function is available in two forms: 1102 * 1103 * @li A 2-argument form: @c buffer_copy(target, source) 1104 * 1105 * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy) 1106 1107 * Both forms return the number of bytes actually copied. The number of bytes 1108 * copied is the lesser of: 1109 * 1110 * @li @c buffer_size(target) 1111 * 1112 * @li @c buffer_size(source) 1113 * 1114 * @li @c If specified, @c max_bytes_to_copy. 1115 * 1116 * This prevents buffer overflow, regardless of the buffer sizes used in the 1117 * copy operation. 1118 * 1119 * Note that @ref buffer_copy is implemented in terms of @c memcpy, and 1120 * consequently it cannot be used to copy between overlapping memory regions. 1121 */ 1122 /*@{*/ 1123 1124 /// Copies bytes from a source buffer to a target buffer. 1125 /** 1126 * @param target A modifiable buffer representing the memory region to which 1127 * the bytes will be copied. 1128 * 1129 * @param source A non-modifiable buffer representing the memory region from 1130 * which the bytes will be copied. 1131 * 1132 * @returns The number of bytes copied. 1133 * 1134 * @note The number of bytes copied is the lesser of: 1135 * 1136 * @li @c buffer_size(target) 1137 * 1138 * @li @c buffer_size(source) 1139 * 1140 * This function is implemented in terms of @c memcpy, and consequently it 1141 * cannot be used to copy between overlapping memory regions. 1142 */ 1143 inline std::size_t buffer_copy(const mutable_buffer& target, 1144 const const_buffer& source) 1145 { 1146 using namespace std; // For memcpy. 1147 std::size_t target_size = buffer_size(target); 1148 std::size_t source_size = buffer_size(source); 1149 std::size_t n = target_size < source_size ? target_size : source_size; 1150 memcpy(buffer_cast<void*>(target), buffer_cast<const void*>(source), n); 1151 return n; 1152 } 1153 1154 /// Copies bytes from a source buffer to a target buffer. 1155 /** 1156 * @param target A modifiable buffer representing the memory region to which 1157 * the bytes will be copied. 1158 * 1159 * @param source A non-modifiable buffer representing the memory region from 1160 * which the bytes will be copied. 1161 * 1162 * @returns The number of bytes copied. 1163 * 1164 * @note The number of bytes copied is the lesser of: 1165 * 1166 * @li @c buffer_size(target) 1167 * 1168 * @li @c buffer_size(source) 1169 * 1170 * This function is implemented in terms of @c memcpy, and consequently it 1171 * cannot be used to copy between overlapping memory regions. 1172 */ 1173 inline std::size_t buffer_copy(const mutable_buffer& target, 1174 const const_buffers_1& source) 1175 { 1176 return buffer_copy(target, static_cast<const const_buffer&>(source)); 1177 } 1178 1179 /// Copies bytes from a source buffer to a target buffer. 1180 /** 1181 * @param target A modifiable buffer representing the memory region to which 1182 * the bytes will be copied. 1183 * 1184 * @param source A modifiable buffer representing the memory region from which 1185 * the bytes will be copied. The contents of the source buffer will not be 1186 * modified. 1187 * 1188 * @returns The number of bytes copied. 1189 * 1190 * @note The number of bytes copied is the lesser of: 1191 * 1192 * @li @c buffer_size(target) 1193 * 1194 * @li @c buffer_size(source) 1195 * 1196 * This function is implemented in terms of @c memcpy, and consequently it 1197 * cannot be used to copy between overlapping memory regions. 1198 */ 1199 inline std::size_t buffer_copy(const mutable_buffer& target, 1200 const mutable_buffer& source) 1201 { 1202 return buffer_copy(target, const_buffer(source)); 1203 } 1204 1205 /// Copies bytes from a source buffer to a target buffer. 1206 /** 1207 * @param target A modifiable buffer representing the memory region to which 1208 * the bytes will be copied. 1209 * 1210 * @param source A modifiable buffer representing the memory region from which 1211 * the bytes will be copied. The contents of the source buffer will not be 1212 * modified. 1213 * 1214 * @returns The number of bytes copied. 1215 * 1216 * @note The number of bytes copied is the lesser of: 1217 * 1218 * @li @c buffer_size(target) 1219 * 1220 * @li @c buffer_size(source) 1221 * 1222 * This function is implemented in terms of @c memcpy, and consequently it 1223 * cannot be used to copy between overlapping memory regions. 1224 */ 1225 inline std::size_t buffer_copy(const mutable_buffer& target, 1226 const mutable_buffers_1& source) 1227 { 1228 return buffer_copy(target, const_buffer(source)); 1229 } 1230 1231 /// Copies bytes from a source buffer sequence to a target buffer. 1232 /** 1233 * @param target A modifiable buffer representing the memory region to which 1234 * the bytes will be copied. 1235 * 1236 * @param source A non-modifiable buffer sequence representing the memory 1237 * regions from which the bytes will be copied. 1238 * 1239 * @returns The number of bytes copied. 1240 * 1241 * @note The number of bytes copied is the lesser of: 1242 * 1243 * @li @c buffer_size(target) 1244 * 1245 * @li @c buffer_size(source) 1246 * 1247 * This function is implemented in terms of @c memcpy, and consequently it 1248 * cannot be used to copy between overlapping memory regions. 1249 */ 1250 template <typename ConstBufferSequence> 1251 std::size_t buffer_copy(const mutable_buffer& target, 1252 const ConstBufferSequence& source) 1253 { 1254 std::size_t total_bytes_copied = 0; 1255 1256 typename ConstBufferSequence::const_iterator source_iter = source.begin(); 1257 typename ConstBufferSequence::const_iterator source_end = source.end(); 1258 1259 for (mutable_buffer target_buffer(target); 1260 buffer_size(target_buffer) && source_iter != source_end; ++source_iter) 1261 { 1262 const_buffer source_buffer(*source_iter); 1263 std::size_t bytes_copied = buffer_copy(target_buffer, source_buffer); 1264 total_bytes_copied += bytes_copied; 1265 target_buffer = target_buffer + bytes_copied; 1266 } 1267 1268 return total_bytes_copied; 1269 } 1270 1271 /// Copies bytes from a source buffer to a target buffer. 1272 /** 1273 * @param target A modifiable buffer representing the memory region to which 1274 * the bytes will be copied. 1275 * 1276 * @param source A non-modifiable buffer representing the memory region from 1277 * which the bytes will be copied. 1278 * 1279 * @returns The number of bytes copied. 1280 * 1281 * @note The number of bytes copied is the lesser of: 1282 * 1283 * @li @c buffer_size(target) 1284 * 1285 * @li @c buffer_size(source) 1286 * 1287 * This function is implemented in terms of @c memcpy, and consequently it 1288 * cannot be used to copy between overlapping memory regions. 1289 */ 1290 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1291 const const_buffer& source) 1292 { 1293 return buffer_copy(static_cast<const mutable_buffer&>(target), source); 1294 } 1295 1296 /// Copies bytes from a source buffer to a target buffer. 1297 /** 1298 * @param target A modifiable buffer representing the memory region to which 1299 * the bytes will be copied. 1300 * 1301 * @param source A non-modifiable buffer representing the memory region from 1302 * which the bytes will be copied. 1303 * 1304 * @returns The number of bytes copied. 1305 * 1306 * @note The number of bytes copied is the lesser of: 1307 * 1308 * @li @c buffer_size(target) 1309 * 1310 * @li @c buffer_size(source) 1311 * 1312 * This function is implemented in terms of @c memcpy, and consequently it 1313 * cannot be used to copy between overlapping memory regions. 1314 */ 1315 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1316 const const_buffers_1& source) 1317 { 1318 return buffer_copy(static_cast<const mutable_buffer&>(target), 1319 static_cast<const const_buffer&>(source)); 1320 } 1321 1322 /// Copies bytes from a source buffer to a target buffer. 1323 /** 1324 * @param target A modifiable buffer representing the memory region to which 1325 * the bytes will be copied. 1326 * 1327 * @param source A modifiable buffer representing the memory region from which 1328 * the bytes will be copied. The contents of the source buffer will not be 1329 * modified. 1330 * 1331 * @returns The number of bytes copied. 1332 * 1333 * @note The number of bytes copied is the lesser of: 1334 * 1335 * @li @c buffer_size(target) 1336 * 1337 * @li @c buffer_size(source) 1338 * 1339 * This function is implemented in terms of @c memcpy, and consequently it 1340 * cannot be used to copy between overlapping memory regions. 1341 */ 1342 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1343 const mutable_buffer& source) 1344 { 1345 return buffer_copy(static_cast<const mutable_buffer&>(target), 1346 const_buffer(source)); 1347 } 1348 1349 /// Copies bytes from a source buffer to a target buffer. 1350 /** 1351 * @param target A modifiable buffer representing the memory region to which 1352 * the bytes will be copied. 1353 * 1354 * @param source A modifiable buffer representing the memory region from which 1355 * the bytes will be copied. The contents of the source buffer will not be 1356 * modified. 1357 * 1358 * @returns The number of bytes copied. 1359 * 1360 * @note The number of bytes copied is the lesser of: 1361 * 1362 * @li @c buffer_size(target) 1363 * 1364 * @li @c buffer_size(source) 1365 * 1366 * This function is implemented in terms of @c memcpy, and consequently it 1367 * cannot be used to copy between overlapping memory regions. 1368 */ 1369 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1370 const mutable_buffers_1& source) 1371 { 1372 return buffer_copy(static_cast<const mutable_buffer&>(target), 1373 const_buffer(source)); 1374 } 1375 1376 /// Copies bytes from a source buffer sequence to a target buffer. 1377 /** 1378 * @param target A modifiable buffer representing the memory region to which 1379 * the bytes will be copied. 1380 * 1381 * @param source A non-modifiable buffer sequence representing the memory 1382 * regions from which the bytes will be copied. 1383 * 1384 * @returns The number of bytes copied. 1385 * 1386 * @note The number of bytes copied is the lesser of: 1387 * 1388 * @li @c buffer_size(target) 1389 * 1390 * @li @c buffer_size(source) 1391 * 1392 * This function is implemented in terms of @c memcpy, and consequently it 1393 * cannot be used to copy between overlapping memory regions. 1394 */ 1395 template <typename ConstBufferSequence> 1396 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1397 const ConstBufferSequence& source) 1398 { 1399 return buffer_copy(static_cast<const mutable_buffer&>(target), source); 1400 } 1401 1402 /// Copies bytes from a source buffer to a target buffer sequence. 1403 /** 1404 * @param target A modifiable buffer sequence representing the memory regions to 1405 * which the bytes will be copied. 1406 * 1407 * @param source A non-modifiable buffer representing the memory region from 1408 * which the bytes will be copied. 1409 * 1410 * @returns The number of bytes copied. 1411 * 1412 * @note The number of bytes copied is the lesser of: 1413 * 1414 * @li @c buffer_size(target) 1415 * 1416 * @li @c buffer_size(source) 1417 * 1418 * This function is implemented in terms of @c memcpy, and consequently it 1419 * cannot be used to copy between overlapping memory regions. 1420 */ 1421 template <typename MutableBufferSequence> 1422 std::size_t buffer_copy(const MutableBufferSequence& target, 1423 const const_buffer& source) 1424 { 1425 std::size_t total_bytes_copied = 0; 1426 1427 typename MutableBufferSequence::const_iterator target_iter = target.begin(); 1428 typename MutableBufferSequence::const_iterator target_end = target.end(); 1429 1430 for (const_buffer source_buffer(source); 1431 buffer_size(source_buffer) && target_iter != target_end; ++target_iter) 1432 { 1433 mutable_buffer target_buffer(*target_iter); 1434 std::size_t bytes_copied = buffer_copy(target_buffer, source_buffer); 1435 total_bytes_copied += bytes_copied; 1436 source_buffer = source_buffer + bytes_copied; 1437 } 1438 1439 return total_bytes_copied; 1440 } 1441 1442 /// Copies bytes from a source buffer to a target buffer sequence. 1443 /** 1444 * @param target A modifiable buffer sequence representing the memory regions to 1445 * which the bytes will be copied. 1446 * 1447 * @param source A non-modifiable buffer representing the memory region from 1448 * which the bytes will be copied. 1449 * 1450 * @returns The number of bytes copied. 1451 * 1452 * @note The number of bytes copied is the lesser of: 1453 * 1454 * @li @c buffer_size(target) 1455 * 1456 * @li @c buffer_size(source) 1457 * 1458 * This function is implemented in terms of @c memcpy, and consequently it 1459 * cannot be used to copy between overlapping memory regions. 1460 */ 1461 template <typename MutableBufferSequence> 1462 inline std::size_t buffer_copy(const MutableBufferSequence& target, 1463 const const_buffers_1& source) 1464 { 1465 return buffer_copy(target, static_cast<const const_buffer&>(source)); 1466 } 1467 1468 /// Copies bytes from a source buffer to a target buffer sequence. 1469 /** 1470 * @param target A modifiable buffer sequence representing the memory regions to 1471 * which the bytes will be copied. 1472 * 1473 * @param source A modifiable buffer representing the memory region from which 1474 * the bytes will be copied. The contents of the source buffer will not be 1475 * modified. 1476 * 1477 * @returns The number of bytes copied. 1478 * 1479 * @note The number of bytes copied is the lesser of: 1480 * 1481 * @li @c buffer_size(target) 1482 * 1483 * @li @c buffer_size(source) 1484 * 1485 * This function is implemented in terms of @c memcpy, and consequently it 1486 * cannot be used to copy between overlapping memory regions. 1487 */ 1488 template <typename MutableBufferSequence> 1489 inline std::size_t buffer_copy(const MutableBufferSequence& target, 1490 const mutable_buffer& source) 1491 { 1492 return buffer_copy(target, const_buffer(source)); 1493 } 1494 1495 /// Copies bytes from a source buffer to a target buffer sequence. 1496 /** 1497 * @param target A modifiable buffer sequence representing the memory regions to 1498 * which the bytes will be copied. 1499 * 1500 * @param source A modifiable buffer representing the memory region from which 1501 * the bytes will be copied. The contents of the source buffer will not be 1502 * modified. 1503 * 1504 * @returns The number of bytes copied. 1505 * 1506 * @note The number of bytes copied is the lesser of: 1507 * 1508 * @li @c buffer_size(target) 1509 * 1510 * @li @c buffer_size(source) 1511 * 1512 * This function is implemented in terms of @c memcpy, and consequently it 1513 * cannot be used to copy between overlapping memory regions. 1514 */ 1515 template <typename MutableBufferSequence> 1516 inline std::size_t buffer_copy(const MutableBufferSequence& target, 1517 const mutable_buffers_1& source) 1518 { 1519 return buffer_copy(target, const_buffer(source)); 1520 } 1521 1522 /// Copies bytes from a source buffer sequence to a target buffer sequence. 1523 /** 1524 * @param target A modifiable buffer sequence representing the memory regions to 1525 * which the bytes will be copied. 1526 * 1527 * @param source A non-modifiable buffer sequence representing the memory 1528 * regions from which the bytes will be copied. 1529 * 1530 * @returns The number of bytes copied. 1531 * 1532 * @note The number of bytes copied is the lesser of: 1533 * 1534 * @li @c buffer_size(target) 1535 * 1536 * @li @c buffer_size(source) 1537 * 1538 * This function is implemented in terms of @c memcpy, and consequently it 1539 * cannot be used to copy between overlapping memory regions. 1540 */ 1541 template <typename MutableBufferSequence, typename ConstBufferSequence> 1542 std::size_t buffer_copy(const MutableBufferSequence& target, 1543 const ConstBufferSequence& source) 1544 { 1545 std::size_t total_bytes_copied = 0; 1546 1547 typename MutableBufferSequence::const_iterator target_iter = target.begin(); 1548 typename MutableBufferSequence::const_iterator target_end = target.end(); 1549 std::size_t target_buffer_offset = 0; 1550 1551 typename ConstBufferSequence::const_iterator source_iter = source.begin(); 1552 typename ConstBufferSequence::const_iterator source_end = source.end(); 1553 std::size_t source_buffer_offset = 0; 1554 1555 while (target_iter != target_end && source_iter != source_end) 1556 { 1557 mutable_buffer target_buffer = 1558 mutable_buffer(*target_iter) + target_buffer_offset; 1559 1560 const_buffer source_buffer = 1561 const_buffer(*source_iter) + source_buffer_offset; 1562 1563 std::size_t bytes_copied = buffer_copy(target_buffer, source_buffer); 1564 total_bytes_copied += bytes_copied; 1565 1566 if (bytes_copied == buffer_size(target_buffer)) 1567 { 1568 ++target_iter; 1569 target_buffer_offset = 0; 1570 } 1571 else 1572 target_buffer_offset += bytes_copied; 1573 1574 if (bytes_copied == buffer_size(source_buffer)) 1575 { 1576 ++source_iter; 1577 source_buffer_offset = 0; 1578 } 1579 else 1580 source_buffer_offset += bytes_copied; 1581 } 1582 1583 return total_bytes_copied; 1584 } 1585 1586 /// Copies a limited number of bytes from a source buffer to a target buffer. 1587 /** 1588 * @param target A modifiable buffer representing the memory region to which 1589 * the bytes will be copied. 1590 * 1591 * @param source A non-modifiable buffer representing the memory region from 1592 * which the bytes will be copied. 1593 * 1594 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1595 * 1596 * @returns The number of bytes copied. 1597 * 1598 * @note The number of bytes copied is the lesser of: 1599 * 1600 * @li @c buffer_size(target) 1601 * 1602 * @li @c buffer_size(source) 1603 * 1604 * @li @c max_bytes_to_copy 1605 * 1606 * This function is implemented in terms of @c memcpy, and consequently it 1607 * cannot be used to copy between overlapping memory regions. 1608 */ 1609 inline std::size_t buffer_copy(const mutable_buffer& target, 1610 const const_buffer& source, std::size_t max_bytes_to_copy) 1611 { 1612 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1613 } 1614 1615 /// Copies a limited number of bytes from a source buffer to a target buffer. 1616 /** 1617 * @param target A modifiable buffer representing the memory region to which 1618 * the bytes will be copied. 1619 * 1620 * @param source A non-modifiable buffer representing the memory region from 1621 * which the bytes will be copied. 1622 * 1623 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1624 * 1625 * @returns The number of bytes copied. 1626 * 1627 * @note The number of bytes copied is the lesser of: 1628 * 1629 * @li @c buffer_size(target) 1630 * 1631 * @li @c buffer_size(source) 1632 * 1633 * @li @c max_bytes_to_copy 1634 * 1635 * This function is implemented in terms of @c memcpy, and consequently it 1636 * cannot be used to copy between overlapping memory regions. 1637 */ 1638 inline std::size_t buffer_copy(const mutable_buffer& target, 1639 const const_buffers_1& source, std::size_t max_bytes_to_copy) 1640 { 1641 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1642 } 1643 1644 /// Copies a limited number of bytes from a source buffer to a target buffer. 1645 /** 1646 * @param target A modifiable buffer representing the memory region to which 1647 * the bytes will be copied. 1648 * 1649 * @param source A modifiable buffer representing the memory region from which 1650 * the bytes will be copied. The contents of the source buffer will not be 1651 * modified. 1652 * 1653 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1654 * 1655 * @returns The number of bytes copied. 1656 * 1657 * @note The number of bytes copied is the lesser of: 1658 * 1659 * @li @c buffer_size(target) 1660 * 1661 * @li @c buffer_size(source) 1662 * 1663 * @li @c max_bytes_to_copy 1664 * 1665 * This function is implemented in terms of @c memcpy, and consequently it 1666 * cannot be used to copy between overlapping memory regions. 1667 */ 1668 inline std::size_t buffer_copy(const mutable_buffer& target, 1669 const mutable_buffer& source, std::size_t max_bytes_to_copy) 1670 { 1671 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1672 } 1673 1674 /// Copies a limited number of bytes from a source buffer to a target buffer. 1675 /** 1676 * @param target A modifiable buffer representing the memory region to which 1677 * the bytes will be copied. 1678 * 1679 * @param source A modifiable buffer representing the memory region from which 1680 * the bytes will be copied. The contents of the source buffer will not be 1681 * modified. 1682 * 1683 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1684 * 1685 * @returns The number of bytes copied. 1686 * 1687 * @note The number of bytes copied is the lesser of: 1688 * 1689 * @li @c buffer_size(target) 1690 * 1691 * @li @c buffer_size(source) 1692 * 1693 * @li @c max_bytes_to_copy 1694 * 1695 * This function is implemented in terms of @c memcpy, and consequently it 1696 * cannot be used to copy between overlapping memory regions. 1697 */ 1698 inline std::size_t buffer_copy(const mutable_buffer& target, 1699 const mutable_buffers_1& source, std::size_t max_bytes_to_copy) 1700 { 1701 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1702 } 1703 1704 /// Copies a limited number of bytes from a source buffer sequence to a target 1705 /// buffer. 1706 /** 1707 * @param target A modifiable buffer representing the memory region to which 1708 * the bytes will be copied. 1709 * 1710 * @param source A non-modifiable buffer sequence representing the memory 1711 * regions from which the bytes will be copied. 1712 * 1713 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1714 * 1715 * @returns The number of bytes copied. 1716 * 1717 * @note The number of bytes copied is the lesser of: 1718 * 1719 * @li @c buffer_size(target) 1720 * 1721 * @li @c buffer_size(source) 1722 * 1723 * @li @c max_bytes_to_copy 1724 * 1725 * This function is implemented in terms of @c memcpy, and consequently it 1726 * cannot be used to copy between overlapping memory regions. 1727 */ 1728 template <typename ConstBufferSequence> 1729 inline std::size_t buffer_copy(const mutable_buffer& target, 1730 const ConstBufferSequence& source, std::size_t max_bytes_to_copy) 1731 { 1732 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1733 } 1734 1735 /// Copies a limited number of bytes from a source buffer to a target buffer. 1736 /** 1737 * @param target A modifiable buffer representing the memory region to which 1738 * the bytes will be copied. 1739 * 1740 * @param source A non-modifiable buffer representing the memory region from 1741 * which the bytes will be copied. 1742 * 1743 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1744 * 1745 * @returns The number of bytes copied. 1746 * 1747 * @note The number of bytes copied is the lesser of: 1748 * 1749 * @li @c buffer_size(target) 1750 * 1751 * @li @c buffer_size(source) 1752 * 1753 * @li @c max_bytes_to_copy 1754 * 1755 * This function is implemented in terms of @c memcpy, and consequently it 1756 * cannot be used to copy between overlapping memory regions. 1757 */ 1758 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1759 const const_buffer& source, std::size_t max_bytes_to_copy) 1760 { 1761 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1762 } 1763 1764 /// Copies a limited number of bytes from a source buffer to a target buffer. 1765 /** 1766 * @param target A modifiable buffer representing the memory region to which 1767 * the bytes will be copied. 1768 * 1769 * @param source A non-modifiable buffer representing the memory region from 1770 * which the bytes will be copied. 1771 * 1772 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1773 * 1774 * @returns The number of bytes copied. 1775 * 1776 * @note The number of bytes copied is the lesser of: 1777 * 1778 * @li @c buffer_size(target) 1779 * 1780 * @li @c buffer_size(source) 1781 * 1782 * @li @c max_bytes_to_copy 1783 * 1784 * This function is implemented in terms of @c memcpy, and consequently it 1785 * cannot be used to copy between overlapping memory regions. 1786 */ 1787 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1788 const const_buffers_1& source, std::size_t max_bytes_to_copy) 1789 { 1790 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1791 } 1792 1793 /// Copies a limited number of bytes from a source buffer to a target buffer. 1794 /** 1795 * @param target A modifiable buffer representing the memory region to which 1796 * the bytes will be copied. 1797 * 1798 * @param source A modifiable buffer representing the memory region from which 1799 * the bytes will be copied. The contents of the source buffer will not be 1800 * modified. 1801 * 1802 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1803 * 1804 * @returns The number of bytes copied. 1805 * 1806 * @note The number of bytes copied is the lesser of: 1807 * 1808 * @li @c buffer_size(target) 1809 * 1810 * @li @c buffer_size(source) 1811 * 1812 * @li @c max_bytes_to_copy 1813 * 1814 * This function is implemented in terms of @c memcpy, and consequently it 1815 * cannot be used to copy between overlapping memory regions. 1816 */ 1817 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1818 const mutable_buffer& source, std::size_t max_bytes_to_copy) 1819 { 1820 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1821 } 1822 1823 /// Copies a limited number of bytes from a source buffer to a target buffer. 1824 /** 1825 * @param target A modifiable buffer representing the memory region to which 1826 * the bytes will be copied. 1827 * 1828 * @param source A modifiable buffer representing the memory region from which 1829 * the bytes will be copied. The contents of the source buffer will not be 1830 * modified. 1831 * 1832 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1833 * 1834 * @returns The number of bytes copied. 1835 * 1836 * @note The number of bytes copied is the lesser of: 1837 * 1838 * @li @c buffer_size(target) 1839 * 1840 * @li @c buffer_size(source) 1841 * 1842 * @li @c max_bytes_to_copy 1843 * 1844 * This function is implemented in terms of @c memcpy, and consequently it 1845 * cannot be used to copy between overlapping memory regions. 1846 */ 1847 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1848 const mutable_buffers_1& source, std::size_t max_bytes_to_copy) 1849 { 1850 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1851 } 1852 1853 /// Copies a limited number of bytes from a source buffer sequence to a target 1854 /// buffer. 1855 /** 1856 * @param target A modifiable buffer representing the memory region to which 1857 * the bytes will be copied. 1858 * 1859 * @param source A non-modifiable buffer sequence representing the memory 1860 * regions from which the bytes will be copied. 1861 * 1862 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1863 * 1864 * @returns The number of bytes copied. 1865 * 1866 * @note The number of bytes copied is the lesser of: 1867 * 1868 * @li @c buffer_size(target) 1869 * 1870 * @li @c buffer_size(source) 1871 * 1872 * @li @c max_bytes_to_copy 1873 * 1874 * This function is implemented in terms of @c memcpy, and consequently it 1875 * cannot be used to copy between overlapping memory regions. 1876 */ 1877 template <typename ConstBufferSequence> 1878 inline std::size_t buffer_copy(const mutable_buffers_1& target, 1879 const ConstBufferSequence& source, std::size_t max_bytes_to_copy) 1880 { 1881 return buffer_copy(buffer(target, max_bytes_to_copy), source); 1882 } 1883 1884 /// Copies a limited number of bytes from a source buffer to a target buffer 1885 /// sequence. 1886 /** 1887 * @param target A modifiable buffer sequence representing the memory regions to 1888 * which the bytes will be copied. 1889 * 1890 * @param source A non-modifiable buffer representing the memory region from 1891 * which the bytes will be copied. 1892 * 1893 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1894 * 1895 * @returns The number of bytes copied. 1896 * 1897 * @note The number of bytes copied is the lesser of: 1898 * 1899 * @li @c buffer_size(target) 1900 * 1901 * @li @c buffer_size(source) 1902 * 1903 * @li @c max_bytes_to_copy 1904 * 1905 * This function is implemented in terms of @c memcpy, and consequently it 1906 * cannot be used to copy between overlapping memory regions. 1907 */ 1908 template <typename MutableBufferSequence> 1909 inline std::size_t buffer_copy(const MutableBufferSequence& target, 1910 const const_buffer& source, std::size_t max_bytes_to_copy) 1911 { 1912 return buffer_copy(target, buffer(source, max_bytes_to_copy)); 1913 } 1914 1915 /// Copies a limited number of bytes from a source buffer to a target buffer 1916 /// sequence. 1917 /** 1918 * @param target A modifiable buffer sequence representing the memory regions to 1919 * which the bytes will be copied. 1920 * 1921 * @param source A non-modifiable buffer representing the memory region from 1922 * which the bytes will be copied. 1923 * 1924 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1925 * 1926 * @returns The number of bytes copied. 1927 * 1928 * @note The number of bytes copied is the lesser of: 1929 * 1930 * @li @c buffer_size(target) 1931 * 1932 * @li @c buffer_size(source) 1933 * 1934 * @li @c max_bytes_to_copy 1935 * 1936 * This function is implemented in terms of @c memcpy, and consequently it 1937 * cannot be used to copy between overlapping memory regions. 1938 */ 1939 template <typename MutableBufferSequence> 1940 inline std::size_t buffer_copy(const MutableBufferSequence& target, 1941 const const_buffers_1& source, std::size_t max_bytes_to_copy) 1942 { 1943 return buffer_copy(target, buffer(source, max_bytes_to_copy)); 1944 } 1945 1946 /// Copies a limited number of bytes from a source buffer to a target buffer 1947 /// sequence. 1948 /** 1949 * @param target A modifiable buffer sequence representing the memory regions to 1950 * which the bytes will be copied. 1951 * 1952 * @param source A modifiable buffer representing the memory region from which 1953 * the bytes will be copied. The contents of the source buffer will not be 1954 * modified. 1955 * 1956 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1957 * 1958 * @returns The number of bytes copied. 1959 * 1960 * @note The number of bytes copied is the lesser of: 1961 * 1962 * @li @c buffer_size(target) 1963 * 1964 * @li @c buffer_size(source) 1965 * 1966 * @li @c max_bytes_to_copy 1967 * 1968 * This function is implemented in terms of @c memcpy, and consequently it 1969 * cannot be used to copy between overlapping memory regions. 1970 */ 1971 template <typename MutableBufferSequence> 1972 inline std::size_t buffer_copy(const MutableBufferSequence& target, 1973 const mutable_buffer& source, std::size_t max_bytes_to_copy) 1974 { 1975 return buffer_copy(target, buffer(source, max_bytes_to_copy)); 1976 } 1977 1978 /// Copies a limited number of bytes from a source buffer to a target buffer 1979 /// sequence. 1980 /** 1981 * @param target A modifiable buffer sequence representing the memory regions to 1982 * which the bytes will be copied. 1983 * 1984 * @param source A modifiable buffer representing the memory region from which 1985 * the bytes will be copied. The contents of the source buffer will not be 1986 * modified. 1987 * 1988 * @param max_bytes_to_copy The maximum number of bytes to be copied. 1989 * 1990 * @returns The number of bytes copied. 1991 * 1992 * @note The number of bytes copied is the lesser of: 1993 * 1994 * @li @c buffer_size(target) 1995 * 1996 * @li @c buffer_size(source) 1997 * 1998 * @li @c max_bytes_to_copy 1999 * 2000 * This function is implemented in terms of @c memcpy, and consequently it 2001 * cannot be used to copy between overlapping memory regions. 2002 */ 2003 template <typename MutableBufferSequence> 2004 inline std::size_t buffer_copy(const MutableBufferSequence& target, 2005 const mutable_buffers_1& source, std::size_t max_bytes_to_copy) 2006 { 2007 return buffer_copy(target, buffer(source, max_bytes_to_copy)); 2008 } 2009 2010 /// Copies a limited number of bytes from a source buffer sequence to a target 2011 /// buffer sequence. 2012 /** 2013 * @param target A modifiable buffer sequence representing the memory regions to 2014 * which the bytes will be copied. 2015 * 2016 * @param source A non-modifiable buffer sequence representing the memory 2017 * regions from which the bytes will be copied. 2018 * 2019 * @param max_bytes_to_copy The maximum number of bytes to be copied. 2020 * 2021 * @returns The number of bytes copied. 2022 * 2023 * @note The number of bytes copied is the lesser of: 2024 * 2025 * @li @c buffer_size(target) 2026 * 2027 * @li @c buffer_size(source) 2028 * 2029 * @li @c max_bytes_to_copy 2030 * 2031 * This function is implemented in terms of @c memcpy, and consequently it 2032 * cannot be used to copy between overlapping memory regions. 2033 */ 2034 template <typename MutableBufferSequence, typename ConstBufferSequence> 2035 std::size_t buffer_copy(const MutableBufferSequence& target, 2036 const ConstBufferSequence& source, std::size_t max_bytes_to_copy) 2037 { 2038 std::size_t total_bytes_copied = 0; 2039 2040 typename MutableBufferSequence::const_iterator target_iter = target.begin(); 2041 typename MutableBufferSequence::const_iterator target_end = target.end(); 2042 std::size_t target_buffer_offset = 0; 2043 2044 typename ConstBufferSequence::const_iterator source_iter = source.begin(); 2045 typename ConstBufferSequence::const_iterator source_end = source.end(); 2046 std::size_t source_buffer_offset = 0; 2047 2048 while (total_bytes_copied != max_bytes_to_copy 2049 && target_iter != target_end && source_iter != source_end) 2050 { 2051 mutable_buffer target_buffer = 2052 mutable_buffer(*target_iter) + target_buffer_offset; 2053 2054 const_buffer source_buffer = 2055 const_buffer(*source_iter) + source_buffer_offset; 2056 2057 std::size_t bytes_copied = buffer_copy(target_buffer, 2058 source_buffer, max_bytes_to_copy - total_bytes_copied); 2059 total_bytes_copied += bytes_copied; 2060 2061 if (bytes_copied == buffer_size(target_buffer)) 2062 { 2063 ++target_iter; 2064 target_buffer_offset = 0; 2065 } 2066 else 2067 target_buffer_offset += bytes_copied; 2068 2069 if (bytes_copied == buffer_size(source_buffer)) 2070 { 2071 ++source_iter; 2072 source_buffer_offset = 0; 2073 } 2074 else 2075 source_buffer_offset += bytes_copied; 2076 } 2077 2078 return total_bytes_copied; 2079 } 2080 2081 /*@}*/ 2082 2083 } // namespace asio 2084 2085 #include "asio/detail/pop_options.hpp" 2086 2087 #endif // ASIO_BUFFER_HPP 2088