1//
2// buffer.hpp
3// ~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 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_BUFFER_HPP
12#define BOOST_ASIO_BUFFER_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 <cstring>
21#include <limits>
22#include <stdexcept>
23#include <string>
24#include <vector>
25#include <boost/asio/detail/array_fwd.hpp>
26#include <boost/asio/detail/memory.hpp>
27#include <boost/asio/detail/string_view.hpp>
28#include <boost/asio/detail/throw_exception.hpp>
29#include <boost/asio/detail/type_traits.hpp>
30#include <boost/asio/is_contiguous_iterator.hpp>
31
32#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700)
33# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
34# if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
35# define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
36# endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
37# endif // defined(_HAS_ITERATOR_DEBUGGING)
38#endif // defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700)
39
40#if defined(__GNUC__)
41# if defined(_GLIBCXX_DEBUG)
42# if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
43# define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
44# endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
45# endif // defined(_GLIBCXX_DEBUG)
46#endif // defined(__GNUC__)
47
48#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
49# include <boost/asio/detail/functional.hpp>
50#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
51
52#include <boost/asio/detail/push_options.hpp>
53
54namespace boost {
55namespace asio {
56
57class mutable_buffer;
58class const_buffer;
59
60/// Holds a buffer that can be modified.
61/**
62 * The mutable_buffer class provides a safe representation of a buffer that can
63 * be modified. It does not own the underlying data, and so is cheap to copy or
64 * assign.
65 *
66 * @par Accessing Buffer Contents
67 *
68 * The contents of a buffer may be accessed using the @c data() and @c size()
69 * member functions:
70 *
71 * @code boost::asio::mutable_buffer b1 = ...;
72 * std::size_t s1 = b1.size();
73 * unsigned char* p1 = static_cast<unsigned char*>(b1.data());
74 * @endcode
75 *
76 * The @c data() member function permits violations of type safety, so uses of
77 * it in application code should be carefully considered.
78 */
79class mutable_buffer
80{
81public:
82 /// Construct an empty buffer.
83 mutable_buffer() noexcept
84 : data_(0),
85 size_(0)
86 {
87 }
88
89 /// Construct a buffer to represent a given memory range.
90 mutable_buffer(void* data, std::size_t size) noexcept
91 : data_(data),
92 size_(size)
93 {
94 }
95
96#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
97 mutable_buffer(void* data, std::size_t size,
98 boost::asio::detail::function<void()> debug_check)
99 : data_(data),
100 size_(size),
101 debug_check_(debug_check)
102 {
103 }
104
105 const boost::asio::detail::function<void()>& get_debug_check() const
106 {
107 return debug_check_;
108 }
109#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
110
111 /// Get a pointer to the beginning of the memory range.
112 void* data() const noexcept
113 {
114#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
115 if (size_ && debug_check_)
116 debug_check_();
117#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
118 return data_;
119 }
120
121 /// Get the size of the memory range.
122 std::size_t size() const noexcept
123 {
124 return size_;
125 }
126
127 /// Move the start of the buffer by the specified number of bytes.
128 mutable_buffer& operator+=(std::size_t n) noexcept
129 {
130 std::size_t offset = n < size_ ? n : size_;
131 data_ = static_cast<char*>(data_) + offset;
132 size_ -= offset;
133 return *this;
134 }
135
136private:
137 void* data_;
138 std::size_t size_;
139
140#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
141 boost::asio::detail::function<void()> debug_check_;
142#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
143};
144
145#if !defined(BOOST_ASIO_NO_DEPRECATED)
146
147/// (Deprecated: Use mutable_buffer.) Adapts a single modifiable buffer so that
148/// it meets the requirements of the MutableBufferSequence concept.
149class mutable_buffers_1
150 : public mutable_buffer
151{
152public:
153 /// The type for each element in the list of buffers.
154 typedef mutable_buffer value_type;
155
156 /// A random-access iterator type that may be used to read elements.
157 typedef const mutable_buffer* const_iterator;
158
159 /// Construct to represent a given memory range.
160 mutable_buffers_1(void* data, std::size_t size) noexcept
161 : mutable_buffer(data, size)
162 {
163 }
164
165#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
166 mutable_buffers_1(void* data, std::size_t size,
167 boost::asio::detail::function<void()> debug_check)
168 : mutable_buffer(data, size, debug_check)
169 {
170 }
171#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
172
173 /// Construct to represent a single modifiable buffer.
174 explicit mutable_buffers_1(const mutable_buffer& b) noexcept
175 : mutable_buffer(b)
176 {
177 }
178
179 /// Get a random-access iterator to the first element.
180 const_iterator begin() const noexcept
181 {
182 return this;
183 }
184
185 /// Get a random-access iterator for one past the last element.
186 const_iterator end() const noexcept
187 {
188 return begin() + 1;
189 }
190};
191
192#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
193
194/// Holds a buffer that cannot be modified.
195/**
196 * The const_buffer class provides a safe representation of a buffer that cannot
197 * be modified. It does not own the underlying data, and so is cheap to copy or
198 * assign.
199 *
200 * @par Accessing Buffer Contents
201 *
202 * The contents of a buffer may be accessed using the @c data() and @c size()
203 * member functions:
204 *
205 * @code boost::asio::const_buffer b1 = ...;
206 * std::size_t s1 = b1.size();
207 * const unsigned char* p1 = static_cast<const unsigned char*>(b1.data());
208 * @endcode
209 *
210 * The @c data() member function permits violations of type safety, so uses of
211 * it in application code should be carefully considered.
212 */
213class const_buffer
214{
215public:
216 /// Construct an empty buffer.
217 const_buffer() noexcept
218 : data_(0),
219 size_(0)
220 {
221 }
222
223 /// Construct a buffer to represent a given memory range.
224 const_buffer(const void* data, std::size_t size) noexcept
225 : data_(data),
226 size_(size)
227 {
228 }
229
230 /// Construct a non-modifiable buffer from a modifiable one.
231 const_buffer(const mutable_buffer& b) noexcept
232 : data_(b.data()),
233 size_(b.size())
234#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
235 , debug_check_(b.get_debug_check())
236#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
237 {
238 }
239
240#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
241 const_buffer(const void* data, std::size_t size,
242 boost::asio::detail::function<void()> debug_check)
243 : data_(data),
244 size_(size),
245 debug_check_(debug_check)
246 {
247 }
248
249 const boost::asio::detail::function<void()>& get_debug_check() const
250 {
251 return debug_check_;
252 }
253#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
254
255 /// Get a pointer to the beginning of the memory range.
256 const void* data() const noexcept
257 {
258#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
259 if (size_ && debug_check_)
260 debug_check_();
261#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
262 return data_;
263 }
264
265 /// Get the size of the memory range.
266 std::size_t size() const noexcept
267 {
268 return size_;
269 }
270
271 /// Move the start of the buffer by the specified number of bytes.
272 const_buffer& operator+=(std::size_t n) noexcept
273 {
274 std::size_t offset = n < size_ ? n : size_;
275 data_ = static_cast<const char*>(data_) + offset;
276 size_ -= offset;
277 return *this;
278 }
279
280private:
281 const void* data_;
282 std::size_t size_;
283
284#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
285 boost::asio::detail::function<void()> debug_check_;
286#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
287};
288
289#if !defined(BOOST_ASIO_NO_DEPRECATED)
290
291/// (Deprecated: Use const_buffer.) Adapts a single non-modifiable buffer so
292/// that it meets the requirements of the ConstBufferSequence concept.
293class const_buffers_1
294 : public const_buffer
295{
296public:
297 /// The type for each element in the list of buffers.
298 typedef const_buffer value_type;
299
300 /// A random-access iterator type that may be used to read elements.
301 typedef const const_buffer* const_iterator;
302
303 /// Construct to represent a given memory range.
304 const_buffers_1(const void* data, std::size_t size) noexcept
305 : const_buffer(data, size)
306 {
307 }
308
309#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
310 const_buffers_1(const void* data, std::size_t size,
311 boost::asio::detail::function<void()> debug_check)
312 : const_buffer(data, size, debug_check)
313 {
314 }
315#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
316
317 /// Construct to represent a single non-modifiable buffer.
318 explicit const_buffers_1(const const_buffer& b) noexcept
319 : const_buffer(b)
320 {
321 }
322
323 /// Get a random-access iterator to the first element.
324 const_iterator begin() const noexcept
325 {
326 return this;
327 }
328
329 /// Get a random-access iterator for one past the last element.
330 const_iterator end() const noexcept
331 {
332 return begin() + 1;
333 }
334};
335
336#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
337
338/// (Deprecated: Use the socket/descriptor wait() and async_wait() member
339/// functions.) An implementation of both the ConstBufferSequence and
340/// MutableBufferSequence concepts to represent a null buffer sequence.
341class null_buffers
342{
343public:
344 /// The type for each element in the list of buffers.
345 typedef mutable_buffer value_type;
346
347 /// A random-access iterator type that may be used to read elements.
348 typedef const mutable_buffer* const_iterator;
349
350 /// Get a random-access iterator to the first element.
351 const_iterator begin() const noexcept
352 {
353 return &buf_;
354 }
355
356 /// Get a random-access iterator for one past the last element.
357 const_iterator end() const noexcept
358 {
359 return &buf_;
360 }
361
362private:
363 mutable_buffer buf_;
364};
365
366/** @defgroup buffer_sequence_begin boost::asio::buffer_sequence_begin
367 *
368 * @brief The boost::asio::buffer_sequence_begin function returns an iterator
369 * pointing to the first element in a buffer sequence.
370 */
371/*@{*/
372
373/// Get an iterator to the first element in a buffer sequence.
374template <typename MutableBuffer>
375inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b,
376 constraint_t<
377 is_convertible<const MutableBuffer*, const mutable_buffer*>::value
378 > = 0) noexcept
379{
380 return static_cast<const mutable_buffer*>(detail::addressof(b));
381}
382
383/// Get an iterator to the first element in a buffer sequence.
384template <typename ConstBuffer>
385inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b,
386 constraint_t<
387 is_convertible<const ConstBuffer*, const const_buffer*>::value
388 > = 0) noexcept
389{
390 return static_cast<const const_buffer*>(detail::addressof(b));
391}
392
393/// Get an iterator to the first element in a buffer sequence.
394template <typename C>
395inline auto buffer_sequence_begin(C& c,
396 constraint_t<
397 !is_convertible<const C*, const mutable_buffer*>::value
398 && !is_convertible<const C*, const const_buffer*>::value
399 > = 0) noexcept -> decltype(c.begin())
400{
401 return c.begin();
402}
403
404/// Get an iterator to the first element in a buffer sequence.
405template <typename C>
406inline auto buffer_sequence_begin(const C& c,
407 constraint_t<
408 !is_convertible<const C*, const mutable_buffer*>::value
409 && !is_convertible<const C*, const const_buffer*>::value
410 > = 0) noexcept -> decltype(c.begin())
411{
412 return c.begin();
413}
414
415/*@}*/
416
417/** @defgroup buffer_sequence_end boost::asio::buffer_sequence_end
418 *
419 * @brief The boost::asio::buffer_sequence_end function returns an iterator
420 * pointing to one past the end element in a buffer sequence.
421 */
422/*@{*/
423
424/// Get an iterator to one past the end element in a buffer sequence.
425template <typename MutableBuffer>
426inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b,
427 constraint_t<
428 is_convertible<const MutableBuffer*, const mutable_buffer*>::value
429 > = 0) noexcept
430{
431 return static_cast<const mutable_buffer*>(detail::addressof(b)) + 1;
432}
433
434/// Get an iterator to one past the end element in a buffer sequence.
435template <typename ConstBuffer>
436inline const const_buffer* buffer_sequence_end(const ConstBuffer& b,
437 constraint_t<
438 is_convertible<const ConstBuffer*, const const_buffer*>::value
439 > = 0) noexcept
440{
441 return static_cast<const const_buffer*>(detail::addressof(b)) + 1;
442}
443
444/// Get an iterator to one past the end element in a buffer sequence.
445template <typename C>
446inline auto buffer_sequence_end(C& c,
447 constraint_t<
448 !is_convertible<const C*, const mutable_buffer*>::value
449 && !is_convertible<const C*, const const_buffer*>::value
450 > = 0) noexcept -> decltype(c.end())
451{
452 return c.end();
453}
454
455/// Get an iterator to one past the end element in a buffer sequence.
456template <typename C>
457inline auto buffer_sequence_end(const C& c,
458 constraint_t<
459 !is_convertible<const C*, const mutable_buffer*>::value
460 && !is_convertible<const C*, const const_buffer*>::value
461 > = 0) noexcept -> decltype(c.end())
462{
463 return c.end();
464}
465
466/*@}*/
467
468namespace detail {
469
470// Tag types used to select appropriately optimised overloads.
471struct one_buffer {};
472struct multiple_buffers {};
473
474// Helper trait to detect single buffers.
475template <typename BufferSequence>
476struct buffer_sequence_cardinality :
477 conditional_t<
478 is_same<BufferSequence, mutable_buffer>::value
479#if !defined(BOOST_ASIO_NO_DEPRECATED)
480 || is_same<BufferSequence, mutable_buffers_1>::value
481 || is_same<BufferSequence, const_buffers_1>::value
482#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
483 || is_same<BufferSequence, const_buffer>::value,
484 one_buffer, multiple_buffers> {};
485
486template <typename Iterator>
487inline std::size_t buffer_size(one_buffer,
488 Iterator begin, Iterator) noexcept
489{
490 return const_buffer(*begin).size();
491}
492
493template <typename Iterator>
494inline std::size_t buffer_size(multiple_buffers,
495 Iterator begin, Iterator end) noexcept
496{
497 std::size_t total_buffer_size = 0;
498
499 Iterator iter = begin;
500 for (; iter != end; ++iter)
501 {
502 const_buffer b(*iter);
503 total_buffer_size += b.size();
504 }
505
506 return total_buffer_size;
507}
508
509} // namespace detail
510
511/// Get the total number of bytes in a buffer sequence.
512/**
513 * The @c buffer_size function determines the total size of all buffers in the
514 * buffer sequence, as if computed as follows:
515 *
516 * @code size_t total_size = 0;
517 * auto i = boost::asio::buffer_sequence_begin(buffers);
518 * auto end = boost::asio::buffer_sequence_end(buffers);
519 * for (; i != end; ++i)
520 * {
521 * const_buffer b(*i);
522 * total_size += b.size();
523 * }
524 * return total_size; @endcode
525 *
526 * The @c BufferSequence template parameter may meet either of the @c
527 * ConstBufferSequence or @c MutableBufferSequence type requirements.
528 */
529template <typename BufferSequence>
530inline std::size_t buffer_size(const BufferSequence& b) noexcept
531{
532 return detail::buffer_size(
533 detail::buffer_sequence_cardinality<BufferSequence>(),
534 boost::asio::buffer_sequence_begin(b),
535 boost::asio::buffer_sequence_end(b));
536}
537
538#if !defined(BOOST_ASIO_NO_DEPRECATED)
539
540/** @defgroup buffer_cast boost::asio::buffer_cast
541 *
542 * @brief (Deprecated: Use the @c data() member function.) The
543 * boost::asio::buffer_cast function is used to obtain a pointer to the
544 * underlying memory region associated with a buffer.
545 *
546 * @par Examples:
547 *
548 * To access the memory of a non-modifiable buffer, use:
549 * @code boost::asio::const_buffer b1 = ...;
550 * const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(b1);
551 * @endcode
552 *
553 * To access the memory of a modifiable buffer, use:
554 * @code boost::asio::mutable_buffer b2 = ...;
555 * unsigned char* p2 = boost::asio::buffer_cast<unsigned char*>(b2);
556 * @endcode
557 *
558 * The boost::asio::buffer_cast function permits violations of type safety, so
559 * uses of it in application code should be carefully considered.
560 */
561/*@{*/
562
563/// Cast a non-modifiable buffer to a specified pointer to POD type.
564template <typename PointerToPodType>
565inline PointerToPodType buffer_cast(const mutable_buffer& b) noexcept
566{
567 return static_cast<PointerToPodType>(b.data());
568}
569
570/// Cast a non-modifiable buffer to a specified pointer to POD type.
571template <typename PointerToPodType>
572inline PointerToPodType buffer_cast(const const_buffer& b) noexcept
573{
574 return static_cast<PointerToPodType>(b.data());
575}
576
577/*@}*/
578
579#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
580
581/// Create a new modifiable buffer that is offset from the start of another.
582/**
583 * @relates mutable_buffer
584 */
585inline mutable_buffer operator+(const mutable_buffer& b,
586 std::size_t n) noexcept
587{
588 std::size_t offset = n < b.size() ? n : b.size();
589 char* new_data = static_cast<char*>(b.data()) + offset;
590 std::size_t new_size = b.size() - offset;
591 return mutable_buffer(new_data, new_size
592#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
593 , b.get_debug_check()
594#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
595 );
596}
597
598/// Create a new modifiable buffer that is offset from the start of another.
599/**
600 * @relates mutable_buffer
601 */
602inline mutable_buffer operator+(std::size_t n,
603 const mutable_buffer& b) noexcept
604{
605 return b + n;
606}
607
608/// Create a new non-modifiable buffer that is offset from the start of another.
609/**
610 * @relates const_buffer
611 */
612inline const_buffer operator+(const const_buffer& b,
613 std::size_t n) noexcept
614{
615 std::size_t offset = n < b.size() ? n : b.size();
616 const char* new_data = static_cast<const char*>(b.data()) + offset;
617 std::size_t new_size = b.size() - offset;
618 return const_buffer(new_data, new_size
619#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
620 , b.get_debug_check()
621#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
622 );
623}
624
625/// Create a new non-modifiable buffer that is offset from the start of another.
626/**
627 * @relates const_buffer
628 */
629inline const_buffer operator+(std::size_t n,
630 const const_buffer& b) noexcept
631{
632 return b + n;
633}
634
635#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
636namespace detail {
637
638template <typename Iterator>
639class buffer_debug_check
640{
641public:
642 buffer_debug_check(Iterator iter)
643 : iter_(iter)
644 {
645 }
646
647 ~buffer_debug_check()
648 {
649#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC == 1400)
650 // MSVC 8's string iterator checking may crash in a std::string::iterator
651 // object's destructor when the iterator points to an already-destroyed
652 // std::string object, unless the iterator is cleared first.
653 iter_ = Iterator();
654#endif // defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC == 1400)
655 }
656
657 void operator()()
658 {
659 (void)*iter_;
660 }
661
662private:
663 Iterator iter_;
664};
665
666} // namespace detail
667#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
668
669/** @defgroup buffer boost::asio::buffer
670 *
671 * @brief The boost::asio::buffer function is used to create a buffer object to
672 * represent raw memory, an array of POD elements, a vector of POD elements,
673 * or a std::string.
674 *
675 * A buffer object represents a contiguous region of memory as a 2-tuple
676 * consisting of a pointer and size in bytes. A tuple of the form <tt>{void*,
677 * size_t}</tt> specifies a mutable (modifiable) region of memory. Similarly, a
678 * tuple of the form <tt>{const void*, size_t}</tt> specifies a const
679 * (non-modifiable) region of memory. These two forms correspond to the classes
680 * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion
681 * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the
682 * opposite conversion is not permitted.
683 *
684 * The simplest use case involves reading or writing a single buffer of a
685 * specified size:
686 *
687 * @code sock.send(boost::asio::buffer(data, size)); @endcode
688 *
689 * In the above example, the return value of boost::asio::buffer meets the
690 * requirements of the ConstBufferSequence concept so that it may be directly
691 * passed to the socket's write function. A buffer created for modifiable
692 * memory also meets the requirements of the MutableBufferSequence concept.
693 *
694 * An individual buffer may be created from a builtin array, std::vector,
695 * std::array or boost::array of POD elements. This helps prevent buffer
696 * overruns by automatically determining the size of the buffer:
697 *
698 * @code char d1[128];
699 * size_t bytes_transferred = sock.receive(boost::asio::buffer(d1));
700 *
701 * std::vector<char> d2(128);
702 * bytes_transferred = sock.receive(boost::asio::buffer(d2));
703 *
704 * std::array<char, 128> d3;
705 * bytes_transferred = sock.receive(boost::asio::buffer(d3));
706 *
707 * boost::array<char, 128> d4;
708 * bytes_transferred = sock.receive(boost::asio::buffer(d4)); @endcode
709 *
710 * In all three cases above, the buffers created are exactly 128 bytes long.
711 * Note that a vector is @e never automatically resized when creating or using
712 * a buffer. The buffer size is determined using the vector's <tt>size()</tt>
713 * member function, and not its capacity.
714 *
715 * @par Accessing Buffer Contents
716 *
717 * The contents of a buffer may be accessed using the @c data() and @c size()
718 * member functions:
719 *
720 * @code boost::asio::mutable_buffer b1 = ...;
721 * std::size_t s1 = b1.size();
722 * unsigned char* p1 = static_cast<unsigned char*>(b1.data());
723 *
724 * boost::asio::const_buffer b2 = ...;
725 * std::size_t s2 = b2.size();
726 * const void* p2 = b2.data(); @endcode
727 *
728 * The @c data() member function permits violations of type safety, so
729 * uses of it in application code should be carefully considered.
730 *
731 * For convenience, a @ref buffer_size function is provided that works with
732 * both buffers and buffer sequences (that is, types meeting the
733 * ConstBufferSequence or MutableBufferSequence type requirements). In this
734 * case, the function returns the total size of all buffers in the sequence.
735 *
736 * @par Buffer Copying
737 *
738 * The @ref buffer_copy function may be used to copy raw bytes between
739 * individual buffers and buffer sequences.
740*
741 * In particular, when used with the @ref buffer_size function, the @ref
742 * buffer_copy function can be used to linearise a sequence of buffers. For
743 * example:
744 *
745 * @code vector<const_buffer> buffers = ...;
746 *
747 * vector<unsigned char> data(boost::asio::buffer_size(buffers));
748 * boost::asio::buffer_copy(boost::asio::buffer(data), buffers); @endcode
749 *
750 * Note that @ref buffer_copy is implemented in terms of @c memcpy, and
751 * consequently it cannot be used to copy between overlapping memory regions.
752 *
753 * @par Buffer Invalidation
754 *
755 * A buffer object does not have any ownership of the memory it refers to. It
756 * is the responsibility of the application to ensure the memory region remains
757 * valid until it is no longer required for an I/O operation. When the memory
758 * is no longer available, the buffer is said to have been invalidated.
759 *
760 * For the boost::asio::buffer overloads that accept an argument of type
761 * std::vector, the buffer objects returned are invalidated by any vector
762 * operation that also invalidates all references, pointers and iterators
763 * referring to the elements in the sequence (C++ Std, 23.2.4)
764 *
765 * For the boost::asio::buffer overloads that accept an argument of type
766 * std::basic_string, the buffer objects returned are invalidated according to
767 * the rules defined for invalidation of references, pointers and iterators
768 * referring to elements of the sequence (C++ Std, 21.3).
769 *
770 * @par Buffer Arithmetic
771 *
772 * Buffer objects may be manipulated using simple arithmetic in a safe way
773 * which helps prevent buffer overruns. Consider an array initialised as
774 * follows:
775 *
776 * @code boost::array<char, 6> a = { 'a', 'b', 'c', 'd', 'e' }; @endcode
777 *
778 * A buffer object @c b1 created using:
779 *
780 * @code b1 = boost::asio::buffer(a); @endcode
781 *
782 * represents the entire array, <tt>{ 'a', 'b', 'c', 'd', 'e' }</tt>. An
783 * optional second argument to the boost::asio::buffer function may be used to
784 * limit the size, in bytes, of the buffer:
785 *
786 * @code b2 = boost::asio::buffer(a, 3); @endcode
787 *
788 * such that @c b2 represents the data <tt>{ 'a', 'b', 'c' }</tt>. Even if the
789 * size argument exceeds the actual size of the array, the size of the buffer
790 * object created will be limited to the array size.
791 *
792 * An offset may be applied to an existing buffer to create a new one:
793 *
794 * @code b3 = b1 + 2; @endcode
795 *
796 * where @c b3 will set to represent <tt>{ 'c', 'd', 'e' }</tt>. If the offset
797 * exceeds the size of the existing buffer, the newly created buffer will be
798 * empty.
799 *
800 * Both an offset and size may be specified to create a buffer that corresponds
801 * to a specific range of bytes within an existing buffer:
802 *
803 * @code b4 = boost::asio::buffer(b1 + 1, 3); @endcode
804 *
805 * so that @c b4 will refer to the bytes <tt>{ 'b', 'c', 'd' }</tt>.
806 *
807 * @par Buffers and Scatter-Gather I/O
808 *
809 * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple
810 * buffer objects may be assigned into a container that supports the
811 * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts:
812 *
813 * @code
814 * char d1[128];
815 * std::vector<char> d2(128);
816 * boost::array<char, 128> d3;
817 *
818 * boost::array<mutable_buffer, 3> bufs1 = {
819 * boost::asio::buffer(d1),
820 * boost::asio::buffer(d2),
821 * boost::asio::buffer(d3) };
822 * bytes_transferred = sock.receive(bufs1);
823 *
824 * std::vector<const_buffer> bufs2;
825 * bufs2.push_back(boost::asio::buffer(d1));
826 * bufs2.push_back(boost::asio::buffer(d2));
827 * bufs2.push_back(boost::asio::buffer(d3));
828 * bytes_transferred = sock.send(bufs2); @endcode
829 *
830 * @par Buffer Literals
831 *
832 * The `_buf` literal suffix, defined in namespace
833 * <tt>boost::asio::buffer_literals</tt>, may be used to create @c const_buffer
834 * objects from string, binary integer, and hexadecimal integer literals.
835 * For example:
836 *
837 * @code
838 * using namespace boost::asio::buffer_literals;
839 *
840 * boost::asio::const_buffer b1 = "hello"_buf;
841 * boost::asio::const_buffer b2 = 0xdeadbeef_buf;
842 * boost::asio::const_buffer b3 = 0x0123456789abcdef0123456789abcdef_buf;
843 * boost::asio::const_buffer b4 = 0b1010101011001100_buf; @endcode
844 *
845 * Note that the memory associated with a buffer literal is valid for the
846 * lifetime of the program. This means that the buffer can be safely used with
847 * asynchronous operations.
848 */
849/*@{*/
850
851#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
852# define BOOST_ASIO_MUTABLE_BUFFER mutable_buffer
853# define BOOST_ASIO_CONST_BUFFER const_buffer
854#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
855# define BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_1
856# define BOOST_ASIO_CONST_BUFFER const_buffers_1
857#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
858
859/// Create a new modifiable buffer from an existing buffer.
860/**
861 * @returns <tt>mutable_buffer(b)</tt>.
862 */
863BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
864 const mutable_buffer& b) noexcept
865{
866 return BOOST_ASIO_MUTABLE_BUFFER(b);
867}
868
869/// Create a new modifiable buffer from an existing buffer.
870/**
871 * @returns A mutable_buffer value equivalent to:
872 * @code mutable_buffer(
873 * b.data(),
874 * min(b.size(), max_size_in_bytes)); @endcode
875 */
876BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
877 const mutable_buffer& b,
878 std::size_t max_size_in_bytes) noexcept
879{
880 return BOOST_ASIO_MUTABLE_BUFFER(
881 mutable_buffer(b.data(),
882 b.size() < max_size_in_bytes
883 ? b.size() : max_size_in_bytes
884#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
885 , b.get_debug_check()
886#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
887 ));
888}
889
890/// Create a new non-modifiable buffer from an existing buffer.
891/**
892 * @returns <tt>const_buffer(b)</tt>.
893 */
894BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
895 const const_buffer& b) noexcept
896{
897 return BOOST_ASIO_CONST_BUFFER(b);
898}
899
900/// Create a new non-modifiable buffer from an existing buffer.
901/**
902 * @returns A const_buffer value equivalent to:
903 * @code const_buffer(
904 * b.data(),
905 * min(b.size(), max_size_in_bytes)); @endcode
906 */
907BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
908 const const_buffer& b,
909 std::size_t max_size_in_bytes) noexcept
910{
911 return BOOST_ASIO_CONST_BUFFER(b.data(),
912 b.size() < max_size_in_bytes
913 ? b.size() : max_size_in_bytes
914#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
915 , b.get_debug_check()
916#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
917 );
918}
919
920/// Create a new modifiable buffer that represents the given memory range.
921/**
922 * @returns <tt>mutable_buffer(data, size_in_bytes)</tt>.
923 */
924BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
925 void* data, std::size_t size_in_bytes) noexcept
926{
927 return BOOST_ASIO_MUTABLE_BUFFER(data, size_in_bytes);
928}
929
930/// Create a new non-modifiable buffer that represents the given memory range.
931/**
932 * @returns <tt>const_buffer(data, size_in_bytes)</tt>.
933 */
934BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
935 const void* data, std::size_t size_in_bytes) noexcept
936{
937 return BOOST_ASIO_CONST_BUFFER(data, size_in_bytes);
938}
939
940/// Create a new modifiable buffer that represents the given POD array.
941/**
942 * @returns A mutable_buffer value equivalent to:
943 * @code mutable_buffer(
944 * static_cast<void*>(data),
945 * N * sizeof(PodType)); @endcode
946 */
947template <typename PodType, std::size_t N>
948BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
949 PodType (&data)[N]) noexcept
950{
951 return BOOST_ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType));
952}
953
954/// Create a new modifiable buffer that represents the given POD array.
955/**
956 * @returns A mutable_buffer value equivalent to:
957 * @code mutable_buffer(
958 * static_cast<void*>(data),
959 * min(N * sizeof(PodType), max_size_in_bytes)); @endcode
960 */
961template <typename PodType, std::size_t N>
962BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
963 PodType (&data)[N],
964 std::size_t max_size_in_bytes) noexcept
965{
966 return BOOST_ASIO_MUTABLE_BUFFER(data,
967 N * sizeof(PodType) < max_size_in_bytes
968 ? N * sizeof(PodType) : max_size_in_bytes);
969}
970
971/// Create a new non-modifiable buffer that represents the given POD array.
972/**
973 * @returns A const_buffer value equivalent to:
974 * @code const_buffer(
975 * static_cast<const void*>(data),
976 * N * sizeof(PodType)); @endcode
977 */
978template <typename PodType, std::size_t N>
979BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
980 const PodType (&data)[N]) noexcept
981{
982 return BOOST_ASIO_CONST_BUFFER(data, N * sizeof(PodType));
983}
984
985/// Create a new non-modifiable buffer that represents the given POD array.
986/**
987 * @returns A const_buffer value equivalent to:
988 * @code const_buffer(
989 * static_cast<const void*>(data),
990 * min(N * sizeof(PodType), max_size_in_bytes)); @endcode
991 */
992template <typename PodType, std::size_t N>
993BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
994 const PodType (&data)[N],
995 std::size_t max_size_in_bytes) noexcept
996{
997 return BOOST_ASIO_CONST_BUFFER(data,
998 N * sizeof(PodType) < max_size_in_bytes
999 ? N * sizeof(PodType) : max_size_in_bytes);
1000}
1001
1002/// Create a new modifiable buffer that represents the given POD array.
1003/**
1004 * @returns A mutable_buffer value equivalent to:
1005 * @code mutable_buffer(
1006 * data.data(),
1007 * data.size() * sizeof(PodType)); @endcode
1008 */
1009template <typename PodType, std::size_t N>
1010BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1011 boost::array<PodType, N>& data) noexcept
1012{
1013 return BOOST_ASIO_MUTABLE_BUFFER(
1014 data.c_array(), data.size() * sizeof(PodType));
1015}
1016
1017/// Create a new modifiable buffer that represents the given POD array.
1018/**
1019 * @returns A mutable_buffer value equivalent to:
1020 * @code mutable_buffer(
1021 * data.data(),
1022 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1023 */
1024template <typename PodType, std::size_t N>
1025BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1026 boost::array<PodType, N>& data,
1027 std::size_t max_size_in_bytes) noexcept
1028{
1029 return BOOST_ASIO_MUTABLE_BUFFER(data.c_array(),
1030 data.size() * sizeof(PodType) < max_size_in_bytes
1031 ? data.size() * sizeof(PodType) : max_size_in_bytes);
1032}
1033
1034/// Create a new non-modifiable buffer that represents the given POD array.
1035/**
1036 * @returns A const_buffer value equivalent to:
1037 * @code const_buffer(
1038 * data.data(),
1039 * data.size() * sizeof(PodType)); @endcode
1040 */
1041template <typename PodType, std::size_t N>
1042BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1043 boost::array<const PodType, N>& data) noexcept
1044{
1045 return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
1046}
1047
1048/// Create a new non-modifiable buffer that represents the given POD array.
1049/**
1050 * @returns A const_buffer value equivalent to:
1051 * @code const_buffer(
1052 * data.data(),
1053 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1054 */
1055template <typename PodType, std::size_t N>
1056BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1057 boost::array<const PodType, N>& data,
1058 std::size_t max_size_in_bytes) noexcept
1059{
1060 return BOOST_ASIO_CONST_BUFFER(data.data(),
1061 data.size() * sizeof(PodType) < max_size_in_bytes
1062 ? data.size() * sizeof(PodType) : max_size_in_bytes);
1063}
1064
1065/// Create a new non-modifiable buffer that represents the given POD array.
1066/**
1067 * @returns A const_buffer value equivalent to:
1068 * @code const_buffer(
1069 * data.data(),
1070 * data.size() * sizeof(PodType)); @endcode
1071 */
1072template <typename PodType, std::size_t N>
1073BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1074 const boost::array<PodType, N>& data) noexcept
1075{
1076 return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
1077}
1078
1079/// Create a new non-modifiable buffer that represents the given POD array.
1080/**
1081 * @returns A const_buffer value equivalent to:
1082 * @code const_buffer(
1083 * data.data(),
1084 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1085 */
1086template <typename PodType, std::size_t N>
1087BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1088 const boost::array<PodType, N>& data,
1089 std::size_t max_size_in_bytes) noexcept
1090{
1091 return BOOST_ASIO_CONST_BUFFER(data.data(),
1092 data.size() * sizeof(PodType) < max_size_in_bytes
1093 ? data.size() * sizeof(PodType) : max_size_in_bytes);
1094}
1095
1096/// Create a new modifiable buffer that represents the given POD array.
1097/**
1098 * @returns A mutable_buffer value equivalent to:
1099 * @code mutable_buffer(
1100 * data.data(),
1101 * data.size() * sizeof(PodType)); @endcode
1102 */
1103template <typename PodType, std::size_t N>
1104BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1105 std::array<PodType, N>& data) noexcept
1106{
1107 return BOOST_ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType));
1108}
1109
1110/// Create a new modifiable buffer that represents the given POD array.
1111/**
1112 * @returns A mutable_buffer value equivalent to:
1113 * @code mutable_buffer(
1114 * data.data(),
1115 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1116 */
1117template <typename PodType, std::size_t N>
1118BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1119 std::array<PodType, N>& data,
1120 std::size_t max_size_in_bytes) noexcept
1121{
1122 return BOOST_ASIO_MUTABLE_BUFFER(data.data(),
1123 data.size() * sizeof(PodType) < max_size_in_bytes
1124 ? data.size() * sizeof(PodType) : max_size_in_bytes);
1125}
1126
1127/// Create a new non-modifiable buffer that represents the given POD array.
1128/**
1129 * @returns A const_buffer value equivalent to:
1130 * @code const_buffer(
1131 * data.data(),
1132 * data.size() * sizeof(PodType)); @endcode
1133 */
1134template <typename PodType, std::size_t N>
1135BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1136 std::array<const PodType, N>& data) noexcept
1137{
1138 return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
1139}
1140
1141/// Create a new non-modifiable buffer that represents the given POD array.
1142/**
1143 * @returns A const_buffer value equivalent to:
1144 * @code const_buffer(
1145 * data.data(),
1146 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1147 */
1148template <typename PodType, std::size_t N>
1149BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1150 std::array<const PodType, N>& data,
1151 std::size_t max_size_in_bytes) noexcept
1152{
1153 return BOOST_ASIO_CONST_BUFFER(data.data(),
1154 data.size() * sizeof(PodType) < max_size_in_bytes
1155 ? data.size() * sizeof(PodType) : max_size_in_bytes);
1156}
1157
1158/// Create a new non-modifiable buffer that represents the given POD array.
1159/**
1160 * @returns A const_buffer value equivalent to:
1161 * @code const_buffer(
1162 * data.data(),
1163 * data.size() * sizeof(PodType)); @endcode
1164 */
1165template <typename PodType, std::size_t N>
1166BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1167 const std::array<PodType, N>& data) noexcept
1168{
1169 return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));
1170}
1171
1172/// Create a new non-modifiable buffer that represents the given POD array.
1173/**
1174 * @returns A const_buffer value equivalent to:
1175 * @code const_buffer(
1176 * data.data(),
1177 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1178 */
1179template <typename PodType, std::size_t N>
1180BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1181 const std::array<PodType, N>& data,
1182 std::size_t max_size_in_bytes) noexcept
1183{
1184 return BOOST_ASIO_CONST_BUFFER(data.data(),
1185 data.size() * sizeof(PodType) < max_size_in_bytes
1186 ? data.size() * sizeof(PodType) : max_size_in_bytes);
1187}
1188
1189/// Create a new modifiable buffer that represents the given POD vector.
1190/**
1191 * @returns A mutable_buffer value equivalent to:
1192 * @code mutable_buffer(
1193 * data.size() ? &data[0] : 0,
1194 * data.size() * sizeof(PodType)); @endcode
1195 *
1196 * @note The buffer is invalidated by any vector operation that would also
1197 * invalidate iterators.
1198 */
1199template <typename PodType, typename Allocator>
1200BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1201 std::vector<PodType, Allocator>& data) noexcept
1202{
1203 return BOOST_ASIO_MUTABLE_BUFFER(
1204 data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
1205#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1206 , detail::buffer_debug_check<
1207 typename std::vector<PodType, Allocator>::iterator
1208 >(data.begin())
1209#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1210 );
1211}
1212
1213/// Create a new modifiable buffer that represents the given POD vector.
1214/**
1215 * @returns A mutable_buffer value equivalent to:
1216 * @code mutable_buffer(
1217 * data.size() ? &data[0] : 0,
1218 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1219 *
1220 * @note The buffer is invalidated by any vector operation that would also
1221 * invalidate iterators.
1222 */
1223template <typename PodType, typename Allocator>
1224BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1225 std::vector<PodType, Allocator>& data,
1226 std::size_t max_size_in_bytes) noexcept
1227{
1228 return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,
1229 data.size() * sizeof(PodType) < max_size_in_bytes
1230 ? data.size() * sizeof(PodType) : max_size_in_bytes
1231#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1232 , detail::buffer_debug_check<
1233 typename std::vector<PodType, Allocator>::iterator
1234 >(data.begin())
1235#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1236 );
1237}
1238
1239/// Create a new non-modifiable buffer that represents the given POD vector.
1240/**
1241 * @returns A const_buffer value equivalent to:
1242 * @code const_buffer(
1243 * data.size() ? &data[0] : 0,
1244 * data.size() * sizeof(PodType)); @endcode
1245 *
1246 * @note The buffer is invalidated by any vector operation that would also
1247 * invalidate iterators.
1248 */
1249template <typename PodType, typename Allocator>
1250BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1251 const std::vector<PodType, Allocator>& data) noexcept
1252{
1253 return BOOST_ASIO_CONST_BUFFER(
1254 data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
1255#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1256 , detail::buffer_debug_check<
1257 typename std::vector<PodType, Allocator>::const_iterator
1258 >(data.begin())
1259#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1260 );
1261}
1262
1263/// Create a new non-modifiable buffer that represents the given POD vector.
1264/**
1265 * @returns A const_buffer value equivalent to:
1266 * @code const_buffer(
1267 * data.size() ? &data[0] : 0,
1268 * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1269 *
1270 * @note The buffer is invalidated by any vector operation that would also
1271 * invalidate iterators.
1272 */
1273template <typename PodType, typename Allocator>
1274BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1275 const std::vector<PodType, Allocator>& data,
1276 std::size_t max_size_in_bytes) noexcept
1277{
1278 return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,
1279 data.size() * sizeof(PodType) < max_size_in_bytes
1280 ? data.size() * sizeof(PodType) : max_size_in_bytes
1281#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1282 , detail::buffer_debug_check<
1283 typename std::vector<PodType, Allocator>::const_iterator
1284 >(data.begin())
1285#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1286 );
1287}
1288
1289/// Create a new modifiable buffer that represents the given string.
1290/**
1291 * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,
1292 * data.size() * sizeof(Elem))</tt>.
1293 *
1294 * @note The buffer is invalidated by any non-const operation called on the
1295 * given string object.
1296 */
1297template <typename Elem, typename Traits, typename Allocator>
1298BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1299 std::basic_string<Elem, Traits, Allocator>& data) noexcept
1300{
1301 return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,
1302 data.size() * sizeof(Elem)
1303#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1304 , detail::buffer_debug_check<
1305 typename std::basic_string<Elem, Traits, Allocator>::iterator
1306 >(data.begin())
1307#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1308 );
1309}
1310
1311/// Create a new modifiable buffer that represents the given string.
1312/**
1313 * @returns A mutable_buffer value equivalent to:
1314 * @code mutable_buffer(
1315 * data.size() ? &data[0] : 0,
1316 * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
1317 *
1318 * @note The buffer is invalidated by any non-const operation called on the
1319 * given string object.
1320 */
1321template <typename Elem, typename Traits, typename Allocator>
1322BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1323 std::basic_string<Elem, Traits, Allocator>& data,
1324 std::size_t max_size_in_bytes) noexcept
1325{
1326 return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,
1327 data.size() * sizeof(Elem) < max_size_in_bytes
1328 ? data.size() * sizeof(Elem) : max_size_in_bytes
1329#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1330 , detail::buffer_debug_check<
1331 typename std::basic_string<Elem, Traits, Allocator>::iterator
1332 >(data.begin())
1333#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1334 );
1335}
1336
1337/// Create a new non-modifiable buffer that represents the given string.
1338/**
1339 * @returns <tt>const_buffer(data.data(), data.size() * sizeof(Elem))</tt>.
1340 *
1341 * @note The buffer is invalidated by any non-const operation called on the
1342 * given string object.
1343 */
1344template <typename Elem, typename Traits, typename Allocator>
1345BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1346 const std::basic_string<Elem, Traits, Allocator>& data) noexcept
1347{
1348 return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem)
1349#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1350 , detail::buffer_debug_check<
1351 typename std::basic_string<Elem, Traits, Allocator>::const_iterator
1352 >(data.begin())
1353#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1354 );
1355}
1356
1357/// Create a new non-modifiable buffer that represents the given string.
1358/**
1359 * @returns A const_buffer value equivalent to:
1360 * @code const_buffer(
1361 * data.data(),
1362 * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
1363 *
1364 * @note The buffer is invalidated by any non-const operation called on the
1365 * given string object.
1366 */
1367template <typename Elem, typename Traits, typename Allocator>
1368BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1369 const std::basic_string<Elem, Traits, Allocator>& data,
1370 std::size_t max_size_in_bytes) noexcept
1371{
1372 return BOOST_ASIO_CONST_BUFFER(data.data(),
1373 data.size() * sizeof(Elem) < max_size_in_bytes
1374 ? data.size() * sizeof(Elem) : max_size_in_bytes
1375#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1376 , detail::buffer_debug_check<
1377 typename std::basic_string<Elem, Traits, Allocator>::const_iterator
1378 >(data.begin())
1379#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1380 );
1381}
1382
1383#if defined(BOOST_ASIO_HAS_STRING_VIEW) \
1384 || defined(GENERATING_DOCUMENTATION)
1385
1386/// Create a new non-modifiable buffer that represents the given string_view.
1387/**
1388 * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,
1389 * data.size() * sizeof(Elem))</tt>.
1390 */
1391template <typename Elem, typename Traits>
1392BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1393 basic_string_view<Elem, Traits> data) noexcept
1394{
1395 return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,
1396 data.size() * sizeof(Elem)
1397#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1398 , detail::buffer_debug_check<
1399 typename basic_string_view<Elem, Traits>::iterator
1400 >(data.begin())
1401#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1402 );
1403}
1404
1405/// Create a new non-modifiable buffer that represents the given string.
1406/**
1407 * @returns A mutable_buffer value equivalent to:
1408 * @code mutable_buffer(
1409 * data.size() ? &data[0] : 0,
1410 * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
1411 */
1412template <typename Elem, typename Traits>
1413BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1414 basic_string_view<Elem, Traits> data,
1415 std::size_t max_size_in_bytes) noexcept
1416{
1417 return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,
1418 data.size() * sizeof(Elem) < max_size_in_bytes
1419 ? data.size() * sizeof(Elem) : max_size_in_bytes
1420#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1421 , detail::buffer_debug_check<
1422 typename basic_string_view<Elem, Traits>::iterator
1423 >(data.begin())
1424#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1425 );
1426}
1427
1428#endif // defined(BOOST_ASIO_HAS_STRING_VIEW)
1429 // || defined(GENERATING_DOCUMENTATION)
1430
1431/// Create a new modifiable buffer from a contiguous container.
1432/**
1433 * @returns A mutable_buffer value equivalent to:
1434 * @code mutable_buffer(
1435 * data.size() ? &data[0] : 0,
1436 * data.size() * sizeof(typename T::value_type)); @endcode
1437 */
1438template <typename T>
1439BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1440 T& data,
1441 constraint_t<
1442 is_contiguous_iterator<typename T::iterator>::value,
1443 defaulted_constraint
1444 > = defaulted_constraint(),
1445 constraint_t<
1446 !is_convertible<T, const_buffer>::value,
1447 defaulted_constraint
1448 > = defaulted_constraint(),
1449 constraint_t<
1450 !is_convertible<T, mutable_buffer>::value,
1451 defaulted_constraint
1452 > = defaulted_constraint(),
1453 constraint_t<
1454 !is_const<
1455 remove_reference_t<
1456 typename std::iterator_traits<typename T::iterator>::reference
1457 >
1458 >::value,
1459 defaulted_constraint
1460 > = defaulted_constraint()) noexcept
1461{
1462 return BOOST_ASIO_MUTABLE_BUFFER(
1463 data.size() ? detail::to_address(data.begin()) : 0,
1464 data.size() * sizeof(typename T::value_type));
1465}
1466
1467/// Create a new modifiable buffer from a contiguous container.
1468/**
1469 * @returns A mutable_buffer value equivalent to:
1470 * @code mutable_buffer(
1471 * data.size() ? &data[0] : 0,
1472 * min(
1473 * data.size() * sizeof(typename T::value_type),
1474 * max_size_in_bytes)); @endcode
1475 */
1476template <typename T>
1477BOOST_ASIO_NODISCARD inline BOOST_ASIO_MUTABLE_BUFFER buffer(
1478 T& data, std::size_t max_size_in_bytes,
1479 constraint_t<
1480 is_contiguous_iterator<typename T::iterator>::value,
1481 defaulted_constraint
1482 > = defaulted_constraint(),
1483 constraint_t<
1484 !is_convertible<T, const_buffer>::value,
1485 defaulted_constraint
1486 > = defaulted_constraint(),
1487 constraint_t<
1488 !is_convertible<T, mutable_buffer>::value,
1489 defaulted_constraint
1490 > = defaulted_constraint(),
1491 constraint_t<
1492 !is_const<
1493 remove_reference_t<
1494 typename std::iterator_traits<typename T::iterator>::reference
1495 >
1496 >::value,
1497 defaulted_constraint
1498 > = defaulted_constraint()) noexcept
1499{
1500 return BOOST_ASIO_MUTABLE_BUFFER(
1501 data.size() ? detail::to_address(data.begin()) : 0,
1502 data.size() * sizeof(typename T::value_type) < max_size_in_bytes
1503 ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes);
1504}
1505
1506/// Create a new non-modifiable buffer from a contiguous container.
1507/**
1508 * @returns A const_buffer value equivalent to:
1509 * @code const_buffer(
1510 * data.size() ? &data[0] : 0,
1511 * data.size() * sizeof(typename T::value_type)); @endcode
1512 */
1513template <typename T>
1514BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1515 T& data,
1516 constraint_t<
1517 is_contiguous_iterator<typename T::iterator>::value,
1518 defaulted_constraint
1519 > = defaulted_constraint(),
1520 constraint_t<
1521 !is_convertible<T, const_buffer>::value,
1522 defaulted_constraint
1523 > = defaulted_constraint(),
1524 constraint_t<
1525 !is_convertible<T, mutable_buffer>::value,
1526 defaulted_constraint
1527 > = defaulted_constraint(),
1528 constraint_t<
1529 is_const<
1530 remove_reference_t<
1531 typename std::iterator_traits<typename T::iterator>::reference
1532 >
1533 >::value,
1534 defaulted_constraint
1535 > = defaulted_constraint()) noexcept
1536{
1537 return BOOST_ASIO_CONST_BUFFER(
1538 data.size() ? detail::to_address(data.begin()) : 0,
1539 data.size() * sizeof(typename T::value_type));
1540}
1541
1542/// Create a new non-modifiable buffer from a contiguous container.
1543/**
1544 * @returns A const_buffer value equivalent to:
1545 * @code const_buffer(
1546 * data.size() ? &data[0] : 0,
1547 * min(
1548 * data.size() * sizeof(typename T::value_type),
1549 * max_size_in_bytes)); @endcode
1550 */
1551template <typename T>
1552BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1553 T& data, std::size_t max_size_in_bytes,
1554 constraint_t<
1555 is_contiguous_iterator<typename T::iterator>::value,
1556 defaulted_constraint
1557 > = defaulted_constraint(),
1558 constraint_t<
1559 !is_convertible<T, const_buffer>::value,
1560 defaulted_constraint
1561 > = defaulted_constraint(),
1562 constraint_t<
1563 !is_convertible<T, mutable_buffer>::value,
1564 defaulted_constraint
1565 > = defaulted_constraint(),
1566 constraint_t<
1567 is_const<
1568 remove_reference_t<
1569 typename std::iterator_traits<typename T::iterator>::reference
1570 >
1571 >::value,
1572 defaulted_constraint
1573 > = defaulted_constraint()) noexcept
1574{
1575 return BOOST_ASIO_CONST_BUFFER(
1576 data.size() ? detail::to_address(data.begin()) : 0,
1577 data.size() * sizeof(typename T::value_type) < max_size_in_bytes
1578 ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes);
1579}
1580
1581/// Create a new non-modifiable buffer from a contiguous container.
1582/**
1583 * @returns A const_buffer value equivalent to:
1584 * @code const_buffer(
1585 * data.size() ? &data[0] : 0,
1586 * data.size() * sizeof(typename T::value_type)); @endcode
1587 */
1588template <typename T>
1589BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1590 const T& data,
1591 constraint_t<
1592 is_contiguous_iterator<typename T::const_iterator>::value,
1593 defaulted_constraint
1594 > = defaulted_constraint(),
1595 constraint_t<
1596 !is_convertible<T, const_buffer>::value,
1597 defaulted_constraint
1598 > = defaulted_constraint(),
1599 constraint_t<
1600 !is_convertible<T, mutable_buffer>::value,
1601 defaulted_constraint
1602 > = defaulted_constraint()) noexcept
1603{
1604 return BOOST_ASIO_CONST_BUFFER(
1605 data.size() ? detail::to_address(data.begin()) : 0,
1606 data.size() * sizeof(typename T::value_type));
1607}
1608
1609/// Create a new non-modifiable buffer from a contiguous container.
1610/**
1611 * @returns A const_buffer value equivalent to:
1612 * @code const_buffer(
1613 * data.size() ? &data[0] : 0,
1614 * min(
1615 * data.size() * sizeof(typename T::value_type),
1616 * max_size_in_bytes)); @endcode
1617 */
1618template <typename T>
1619BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONST_BUFFER buffer(
1620 const T& data, std::size_t max_size_in_bytes,
1621 constraint_t<
1622 is_contiguous_iterator<typename T::const_iterator>::value,
1623 defaulted_constraint
1624 > = defaulted_constraint(),
1625 constraint_t<
1626 !is_convertible<T, const_buffer>::value,
1627 defaulted_constraint
1628 > = defaulted_constraint(),
1629 constraint_t<
1630 !is_convertible<T, mutable_buffer>::value,
1631 defaulted_constraint
1632 > = defaulted_constraint()) noexcept
1633{
1634 return BOOST_ASIO_CONST_BUFFER(
1635 data.size() ? detail::to_address(data.begin()) : 0,
1636 data.size() * sizeof(typename T::value_type) < max_size_in_bytes
1637 ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes);
1638}
1639
1640/*@}*/
1641
1642/// Adapt a basic_string to the DynamicBuffer requirements.
1643/**
1644 * Requires that <tt>sizeof(Elem) == 1</tt>.
1645 */
1646template <typename Elem, typename Traits, typename Allocator>
1647class dynamic_string_buffer
1648{
1649public:
1650 /// The type used to represent a sequence of constant buffers that refers to
1651 /// the underlying memory.
1652 typedef BOOST_ASIO_CONST_BUFFER const_buffers_type;
1653
1654 /// The type used to represent a sequence of mutable buffers that refers to
1655 /// the underlying memory.
1656 typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type;
1657
1658 /// Construct a dynamic buffer from a string.
1659 /**
1660 * @param s The string to be used as backing storage for the dynamic buffer.
1661 * The object stores a reference to the string and the user is responsible
1662 * for ensuring that the string object remains valid while the
1663 * dynamic_string_buffer object, and copies of the object, are in use.
1664 *
1665 * @b DynamicBuffer_v1: Any existing data in the string is treated as the
1666 * dynamic buffer's input sequence.
1667 *
1668 * @param maximum_size Specifies a maximum size for the buffer, in bytes.
1669 */
1670 explicit dynamic_string_buffer(std::basic_string<Elem, Traits, Allocator>& s,
1671 std::size_t maximum_size =
1672 (std::numeric_limits<std::size_t>::max)()) noexcept
1673 : string_(s),
1674#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1675 size_((std::numeric_limits<std::size_t>::max)()),
1676#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1677 max_size_(maximum_size)
1678 {
1679 }
1680
1681 /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.
1682 dynamic_string_buffer(const dynamic_string_buffer& other) noexcept
1683 : string_(other.string_),
1684#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1685 size_(other.size_),
1686#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1687 max_size_(other.max_size_)
1688 {
1689 }
1690
1691 /// Move construct a dynamic buffer.
1692 dynamic_string_buffer(dynamic_string_buffer&& other) noexcept
1693 : string_(other.string_),
1694#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1695 size_(other.size_),
1696#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1697 max_size_(other.max_size_)
1698 {
1699 }
1700
1701 /// @b DynamicBuffer_v1: Get the size of the input sequence.
1702 /// @b DynamicBuffer_v2: Get the current size of the underlying memory.
1703 /**
1704 * @returns @b DynamicBuffer_v1 The current size of the input sequence.
1705 * @b DynamicBuffer_v2: The current size of the underlying string if less than
1706 * max_size(). Otherwise returns max_size().
1707 */
1708 std::size_t size() const noexcept
1709 {
1710#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1711 if (size_ != (std::numeric_limits<std::size_t>::max)())
1712 return size_;
1713#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1714 return (std::min)(string_.size(), max_size());
1715 }
1716
1717 /// Get the maximum size of the dynamic buffer.
1718 /**
1719 * @returns The allowed maximum size of the underlying memory.
1720 */
1721 std::size_t max_size() const noexcept
1722 {
1723 return max_size_;
1724 }
1725
1726 /// Get the maximum size that the buffer may grow to without triggering
1727 /// reallocation.
1728 /**
1729 * @returns The current capacity of the underlying string if less than
1730 * max_size(). Otherwise returns max_size().
1731 */
1732 std::size_t capacity() const noexcept
1733 {
1734 return (std::min)(string_.capacity(), max_size());
1735 }
1736
1737#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1738 /// @b DynamicBuffer_v1: Get a list of buffers that represents the input
1739 /// sequence.
1740 /**
1741 * @returns An object of type @c const_buffers_type that satisfies
1742 * ConstBufferSequence requirements, representing the basic_string memory in
1743 * the input sequence.
1744 *
1745 * @note The returned object is invalidated by any @c dynamic_string_buffer
1746 * or @c basic_string member function that resizes or erases the string.
1747 */
1748 const_buffers_type data() const noexcept
1749 {
1750 return const_buffers_type(boost::asio::buffer(string_, size_));
1751 }
1752#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1753
1754 /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
1755 /// underlying memory.
1756 /**
1757 * @param pos Position of the first byte to represent in the buffer sequence
1758 *
1759 * @param n The number of bytes to return in the buffer sequence. If the
1760 * underlying memory is shorter, the buffer sequence represents as many bytes
1761 * as are available.
1762 *
1763 * @returns An object of type @c mutable_buffers_type that satisfies
1764 * MutableBufferSequence requirements, representing the basic_string memory.
1765 *
1766 * @note The returned object is invalidated by any @c dynamic_string_buffer
1767 * or @c basic_string member function that resizes or erases the string.
1768 */
1769 mutable_buffers_type data(std::size_t pos, std::size_t n) noexcept
1770 {
1771 return mutable_buffers_type(boost::asio::buffer(
1772 boost::asio::buffer(string_, max_size_) + pos, n));
1773 }
1774
1775 /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
1776 /// underlying memory.
1777 /**
1778 * @param pos Position of the first byte to represent in the buffer sequence
1779 *
1780 * @param n The number of bytes to return in the buffer sequence. If the
1781 * underlying memory is shorter, the buffer sequence represents as many bytes
1782 * as are available.
1783 *
1784 * @note The returned object is invalidated by any @c dynamic_string_buffer
1785 * or @c basic_string member function that resizes or erases the string.
1786 */
1787 const_buffers_type data(std::size_t pos,
1788 std::size_t n) const noexcept
1789 {
1790 return const_buffers_type(boost::asio::buffer(
1791 boost::asio::buffer(string_, max_size_) + pos, n));
1792 }
1793
1794#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1795 /// @b DynamicBuffer_v1: Get a list of buffers that represents the output
1796 /// sequence, with the given size.
1797 /**
1798 * Ensures that the output sequence can accommodate @c n bytes, resizing the
1799 * basic_string object as necessary.
1800 *
1801 * @returns An object of type @c mutable_buffers_type that satisfies
1802 * MutableBufferSequence requirements, representing basic_string memory
1803 * at the start of the output sequence of size @c n.
1804 *
1805 * @throws std::length_error If <tt>size() + n > max_size()</tt>.
1806 *
1807 * @note The returned object is invalidated by any @c dynamic_string_buffer
1808 * or @c basic_string member function that modifies the input sequence or
1809 * output sequence.
1810 */
1811 mutable_buffers_type prepare(std::size_t n)
1812 {
1813 if (size() > max_size() || max_size() - size() < n)
1814 {
1815 std::length_error ex("dynamic_string_buffer too long");
1816 boost::asio::detail::throw_exception(e: ex);
1817 }
1818
1819 if (size_ == (std::numeric_limits<std::size_t>::max)())
1820 size_ = string_.size(); // Enable v1 behaviour.
1821
1822 string_.resize(size_ + n);
1823
1824 return boost::asio::buffer(boost::asio::buffer(string_) + size_, n);
1825 }
1826
1827 /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input
1828 /// sequence.
1829 /**
1830 * @param n The number of bytes to append from the start of the output
1831 * sequence to the end of the input sequence. The remainder of the output
1832 * sequence is discarded.
1833 *
1834 * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
1835 * no intervening operations that modify the input or output sequence.
1836 *
1837 * @note If @c n is greater than the size of the output sequence, the entire
1838 * output sequence is moved to the input sequence and no error is issued.
1839 */
1840 void commit(std::size_t n)
1841 {
1842 size_ += (std::min)(n, string_.size() - size_);
1843 string_.resize(size_);
1844 }
1845#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1846
1847 /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of
1848 /// bytes.
1849 /**
1850 * Resizes the string to accommodate an additional @c n bytes at the end.
1851 *
1852 * @throws std::length_error If <tt>size() + n > max_size()</tt>.
1853 */
1854 void grow(std::size_t n)
1855 {
1856 if (size() > max_size() || max_size() - size() < n)
1857 {
1858 std::length_error ex("dynamic_string_buffer too long");
1859 boost::asio::detail::throw_exception(e: ex);
1860 }
1861
1862 string_.resize(size() + n);
1863 }
1864
1865 /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number
1866 /// of bytes.
1867 /**
1868 * Erases @c n bytes from the end of the string by resizing the basic_string
1869 * object. If @c n is greater than the current size of the string, the string
1870 * is emptied.
1871 */
1872 void shrink(std::size_t n)
1873 {
1874 string_.resize(n > size() ? 0 : size() - n);
1875 }
1876
1877 /// @b DynamicBuffer_v1: Remove characters from the input sequence.
1878 /// @b DynamicBuffer_v2: Consume the specified number of bytes from the
1879 /// beginning of the underlying memory.
1880 /**
1881 * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the
1882 * input sequence. @note If @c n is greater than the size of the input
1883 * sequence, the entire input sequence is consumed and no error is issued.
1884 *
1885 * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the string.
1886 * If @c n is greater than the current size of the string, the string is
1887 * emptied.
1888 */
1889 void consume(std::size_t n)
1890 {
1891#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1892 if (size_ != (std::numeric_limits<std::size_t>::max)())
1893 {
1894 std::size_t consume_length = (std::min)(a: n, b: size_);
1895 string_.erase(0, consume_length);
1896 size_ -= consume_length;
1897 return;
1898 }
1899#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1900 string_.erase(0, n);
1901 }
1902
1903private:
1904 std::basic_string<Elem, Traits, Allocator>& string_;
1905#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1906 std::size_t size_;
1907#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1908 const std::size_t max_size_;
1909};
1910
1911/// Adapt a vector to the DynamicBuffer requirements.
1912/**
1913 * Requires that <tt>sizeof(Elem) == 1</tt>.
1914 */
1915template <typename Elem, typename Allocator>
1916class dynamic_vector_buffer
1917{
1918public:
1919 /// The type used to represent a sequence of constant buffers that refers to
1920 /// the underlying memory.
1921 typedef BOOST_ASIO_CONST_BUFFER const_buffers_type;
1922
1923 /// The type used to represent a sequence of mutable buffers that refers to
1924 /// the underlying memory.
1925 typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type;
1926
1927 /// Construct a dynamic buffer from a vector.
1928 /**
1929 * @param v The vector to be used as backing storage for the dynamic buffer.
1930 * The object stores a reference to the vector and the user is responsible
1931 * for ensuring that the vector object remains valid while the
1932 * dynamic_vector_buffer object, and copies of the object, are in use.
1933 *
1934 * @param maximum_size Specifies a maximum size for the buffer, in bytes.
1935 */
1936 explicit dynamic_vector_buffer(std::vector<Elem, Allocator>& v,
1937 std::size_t maximum_size =
1938 (std::numeric_limits<std::size_t>::max)()) noexcept
1939 : vector_(v),
1940#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1941 size_((std::numeric_limits<std::size_t>::max)()),
1942#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1943 max_size_(maximum_size)
1944 {
1945 }
1946
1947 /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.
1948 dynamic_vector_buffer(const dynamic_vector_buffer& other) noexcept
1949 : vector_(other.vector_),
1950#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1951 size_(other.size_),
1952#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1953 max_size_(other.max_size_)
1954 {
1955 }
1956
1957 /// Move construct a dynamic buffer.
1958 dynamic_vector_buffer(dynamic_vector_buffer&& other) noexcept
1959 : vector_(other.vector_),
1960#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1961 size_(other.size_),
1962#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1963 max_size_(other.max_size_)
1964 {
1965 }
1966
1967 /// @b DynamicBuffer_v1: Get the size of the input sequence.
1968 /// @b DynamicBuffer_v2: Get the current size of the underlying memory.
1969 /**
1970 * @returns @b DynamicBuffer_v1 The current size of the input sequence.
1971 * @b DynamicBuffer_v2: The current size of the underlying vector if less than
1972 * max_size(). Otherwise returns max_size().
1973 */
1974 std::size_t size() const noexcept
1975 {
1976#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1977 if (size_ != (std::numeric_limits<std::size_t>::max)())
1978 return size_;
1979#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1980 return (std::min)(vector_.size(), max_size());
1981 }
1982
1983 /// Get the maximum size of the dynamic buffer.
1984 /**
1985 * @returns @b DynamicBuffer_v1: The allowed maximum of the sum of the sizes
1986 * of the input sequence and output sequence. @b DynamicBuffer_v2: The allowed
1987 * maximum size of the underlying memory.
1988 */
1989 std::size_t max_size() const noexcept
1990 {
1991 return max_size_;
1992 }
1993
1994 /// Get the maximum size that the buffer may grow to without triggering
1995 /// reallocation.
1996 /**
1997 * @returns @b DynamicBuffer_v1: The current total capacity of the buffer,
1998 * i.e. for both the input sequence and output sequence. @b DynamicBuffer_v2:
1999 * The current capacity of the underlying vector if less than max_size().
2000 * Otherwise returns max_size().
2001 */
2002 std::size_t capacity() const noexcept
2003 {
2004 return (std::min)(vector_.capacity(), max_size());
2005 }
2006
2007#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2008 /// @b DynamicBuffer_v1: Get a list of buffers that represents the input
2009 /// sequence.
2010 /**
2011 * @returns An object of type @c const_buffers_type that satisfies
2012 * ConstBufferSequence requirements, representing the vector memory in the
2013 * input sequence.
2014 *
2015 * @note The returned object is invalidated by any @c dynamic_vector_buffer
2016 * or @c vector member function that modifies the input sequence or output
2017 * sequence.
2018 */
2019 const_buffers_type data() const noexcept
2020 {
2021 return const_buffers_type(boost::asio::buffer(vector_, size_));
2022 }
2023#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2024
2025 /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
2026 /// underlying memory.
2027 /**
2028 * @param pos Position of the first byte to represent in the buffer sequence
2029 *
2030 * @param n The number of bytes to return in the buffer sequence. If the
2031 * underlying memory is shorter, the buffer sequence represents as many bytes
2032 * as are available.
2033 *
2034 * @returns An object of type @c mutable_buffers_type that satisfies
2035 * MutableBufferSequence requirements, representing the vector memory.
2036 *
2037 * @note The returned object is invalidated by any @c dynamic_vector_buffer
2038 * or @c vector member function that resizes or erases the vector.
2039 */
2040 mutable_buffers_type data(std::size_t pos, std::size_t n) noexcept
2041 {
2042 return mutable_buffers_type(boost::asio::buffer(
2043 boost::asio::buffer(vector_, max_size_) + pos, n));
2044 }
2045
2046 /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
2047 /// underlying memory.
2048 /**
2049 * @param pos Position of the first byte to represent in the buffer sequence
2050 *
2051 * @param n The number of bytes to return in the buffer sequence. If the
2052 * underlying memory is shorter, the buffer sequence represents as many bytes
2053 * as are available.
2054 *
2055 * @note The returned object is invalidated by any @c dynamic_vector_buffer
2056 * or @c vector member function that resizes or erases the vector.
2057 */
2058 const_buffers_type data(std::size_t pos,
2059 std::size_t n) const noexcept
2060 {
2061 return const_buffers_type(boost::asio::buffer(
2062 boost::asio::buffer(vector_, max_size_) + pos, n));
2063 }
2064
2065#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2066 /// @b DynamicBuffer_v1: Get a list of buffers that represents the output
2067 /// sequence, with the given size.
2068 /**
2069 * Ensures that the output sequence can accommodate @c n bytes, resizing the
2070 * vector object as necessary.
2071 *
2072 * @returns An object of type @c mutable_buffers_type that satisfies
2073 * MutableBufferSequence requirements, representing vector memory at the
2074 * start of the output sequence of size @c n.
2075 *
2076 * @throws std::length_error If <tt>size() + n > max_size()</tt>.
2077 *
2078 * @note The returned object is invalidated by any @c dynamic_vector_buffer
2079 * or @c vector member function that modifies the input sequence or output
2080 * sequence.
2081 */
2082 mutable_buffers_type prepare(std::size_t n)
2083 {
2084 if (size () > max_size() || max_size() - size() < n)
2085 {
2086 std::length_error ex("dynamic_vector_buffer too long");
2087 boost::asio::detail::throw_exception(e: ex);
2088 }
2089
2090 if (size_ == (std::numeric_limits<std::size_t>::max)())
2091 size_ = vector_.size(); // Enable v1 behaviour.
2092
2093 vector_.resize(size_ + n);
2094
2095 return boost::asio::buffer(boost::asio::buffer(vector_) + size_, n);
2096 }
2097
2098 /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input
2099 /// sequence.
2100 /**
2101 * @param n The number of bytes to append from the start of the output
2102 * sequence to the end of the input sequence. The remainder of the output
2103 * sequence is discarded.
2104 *
2105 * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
2106 * no intervening operations that modify the input or output sequence.
2107 *
2108 * @note If @c n is greater than the size of the output sequence, the entire
2109 * output sequence is moved to the input sequence and no error is issued.
2110 */
2111 void commit(std::size_t n)
2112 {
2113 size_ += (std::min)(n, vector_.size() - size_);
2114 vector_.resize(size_);
2115 }
2116#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2117
2118 /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of
2119 /// bytes.
2120 /**
2121 * Resizes the vector to accommodate an additional @c n bytes at the end.
2122 *
2123 * @throws std::length_error If <tt>size() + n > max_size()</tt>.
2124 */
2125 void grow(std::size_t n)
2126 {
2127 if (size() > max_size() || max_size() - size() < n)
2128 {
2129 std::length_error ex("dynamic_vector_buffer too long");
2130 boost::asio::detail::throw_exception(e: ex);
2131 }
2132
2133 vector_.resize(size() + n);
2134 }
2135
2136 /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number
2137 /// of bytes.
2138 /**
2139 * Erases @c n bytes from the end of the vector by resizing the vector
2140 * object. If @c n is greater than the current size of the vector, the vector
2141 * is emptied.
2142 */
2143 void shrink(std::size_t n)
2144 {
2145 vector_.resize(n > size() ? 0 : size() - n);
2146 }
2147
2148 /// @b DynamicBuffer_v1: Remove characters from the input sequence.
2149 /// @b DynamicBuffer_v2: Consume the specified number of bytes from the
2150 /// beginning of the underlying memory.
2151 /**
2152 * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the
2153 * input sequence. @note If @c n is greater than the size of the input
2154 * sequence, the entire input sequence is consumed and no error is issued.
2155 *
2156 * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the vector.
2157 * If @c n is greater than the current size of the vector, the vector is
2158 * emptied.
2159 */
2160 void consume(std::size_t n)
2161 {
2162#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2163 if (size_ != (std::numeric_limits<std::size_t>::max)())
2164 {
2165 std::size_t consume_length = (std::min)(a: n, b: size_);
2166 vector_.erase(vector_.begin(), vector_.begin() + consume_length);
2167 size_ -= consume_length;
2168 return;
2169 }
2170#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2171 vector_.erase(vector_.begin(), vector_.begin() + (std::min)(size(), n));
2172 }
2173
2174private:
2175 std::vector<Elem, Allocator>& vector_;
2176#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2177 std::size_t size_;
2178#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2179 const std::size_t max_size_;
2180};
2181
2182/** @defgroup dynamic_buffer boost::asio::dynamic_buffer
2183 *
2184 * @brief The boost::asio::dynamic_buffer function is used to create a
2185 * dynamically resized buffer from a @c std::basic_string or @c std::vector.
2186 */
2187/*@{*/
2188
2189/// Create a new dynamic buffer that represents the given string.
2190/**
2191 * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>.
2192 */
2193template <typename Elem, typename Traits, typename Allocator>
2194BOOST_ASIO_NODISCARD inline
2195dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(
2196 std::basic_string<Elem, Traits, Allocator>& data) noexcept
2197{
2198 return dynamic_string_buffer<Elem, Traits, Allocator>(data);
2199}
2200
2201/// Create a new dynamic buffer that represents the given string.
2202/**
2203 * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data,
2204 * max_size)</tt>.
2205 */
2206template <typename Elem, typename Traits, typename Allocator>
2207BOOST_ASIO_NODISCARD inline
2208dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(
2209 std::basic_string<Elem, Traits, Allocator>& data,
2210 std::size_t max_size) noexcept
2211{
2212 return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size);
2213}
2214
2215/// Create a new dynamic buffer that represents the given vector.
2216/**
2217 * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>.
2218 */
2219template <typename Elem, typename Allocator>
2220BOOST_ASIO_NODISCARD inline
2221dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(
2222 std::vector<Elem, Allocator>& data) noexcept
2223{
2224 return dynamic_vector_buffer<Elem, Allocator>(data);
2225}
2226
2227/// Create a new dynamic buffer that represents the given vector.
2228/**
2229 * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>.
2230 */
2231template <typename Elem, typename Allocator>
2232BOOST_ASIO_NODISCARD inline
2233dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(
2234 std::vector<Elem, Allocator>& data,
2235 std::size_t max_size) noexcept
2236{
2237 return dynamic_vector_buffer<Elem, Allocator>(data, max_size);
2238}
2239
2240/*@}*/
2241
2242/** @defgroup buffer_copy boost::asio::buffer_copy
2243 *
2244 * @brief The boost::asio::buffer_copy function is used to copy bytes from a
2245 * source buffer (or buffer sequence) to a target buffer (or buffer sequence).
2246 *
2247 * The @c buffer_copy function is available in two forms:
2248 *
2249 * @li A 2-argument form: @c buffer_copy(target, source)
2250 *
2251 * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy)
2252 *
2253 * Both forms return the number of bytes actually copied. The number of bytes
2254 * copied is the lesser of:
2255 *
2256 * @li @c buffer_size(target)
2257 *
2258 * @li @c buffer_size(source)
2259 *
2260 * @li @c If specified, @c max_bytes_to_copy.
2261 *
2262 * This prevents buffer overflow, regardless of the buffer sizes used in the
2263 * copy operation.
2264 *
2265 * Note that @ref buffer_copy is implemented in terms of @c memcpy, and
2266 * consequently it cannot be used to copy between overlapping memory regions.
2267 */
2268/*@{*/
2269
2270namespace detail {
2271
2272inline std::size_t buffer_copy_1(const mutable_buffer& target,
2273 const const_buffer& source)
2274{
2275 using namespace std; // For memcpy.
2276 std::size_t target_size = target.size();
2277 std::size_t source_size = source.size();
2278 std::size_t n = target_size < source_size ? target_size : source_size;
2279 if (n > 0)
2280 memcpy(dest: target.data(), src: source.data(), n: n);
2281 return n;
2282}
2283
2284template <typename TargetIterator, typename SourceIterator>
2285inline std::size_t buffer_copy(one_buffer, one_buffer,
2286 TargetIterator target_begin, TargetIterator,
2287 SourceIterator source_begin, SourceIterator) noexcept
2288{
2289 return (buffer_copy_1)(target: *target_begin, source: *source_begin);
2290}
2291
2292template <typename TargetIterator, typename SourceIterator>
2293inline std::size_t buffer_copy(one_buffer, one_buffer,
2294 TargetIterator target_begin, TargetIterator,
2295 SourceIterator source_begin, SourceIterator,
2296 std::size_t max_bytes_to_copy) noexcept
2297{
2298 return (buffer_copy_1)(target: *target_begin,
2299 source: boost::asio::buffer(*source_begin, max_bytes_to_copy));
2300}
2301
2302template <typename TargetIterator, typename SourceIterator>
2303std::size_t buffer_copy(one_buffer, multiple_buffers,
2304 TargetIterator target_begin, TargetIterator,
2305 SourceIterator source_begin, SourceIterator source_end,
2306 std::size_t max_bytes_to_copy
2307 = (std::numeric_limits<std::size_t>::max)()) noexcept
2308{
2309 std::size_t total_bytes_copied = 0;
2310 SourceIterator source_iter = source_begin;
2311
2312 for (mutable_buffer target_buffer(
2313 boost::asio::buffer(*target_begin, max_bytes_to_copy));
2314 target_buffer.size() && source_iter != source_end; ++source_iter)
2315 {
2316 const_buffer source_buffer(*source_iter);
2317 std::size_t bytes_copied = (buffer_copy_1)(target: target_buffer, source: source_buffer);
2318 total_bytes_copied += bytes_copied;
2319 target_buffer += bytes_copied;
2320 }
2321
2322 return total_bytes_copied;
2323}
2324
2325template <typename TargetIterator, typename SourceIterator>
2326std::size_t buffer_copy(multiple_buffers, one_buffer,
2327 TargetIterator target_begin, TargetIterator target_end,
2328 SourceIterator source_begin, SourceIterator,
2329 std::size_t max_bytes_to_copy
2330 = (std::numeric_limits<std::size_t>::max)()) noexcept
2331{
2332 std::size_t total_bytes_copied = 0;
2333 TargetIterator target_iter = target_begin;
2334
2335 for (const_buffer source_buffer(
2336 boost::asio::buffer(*source_begin, max_bytes_to_copy));
2337 source_buffer.size() && target_iter != target_end; ++target_iter)
2338 {
2339 mutable_buffer target_buffer(*target_iter);
2340 std::size_t bytes_copied = (buffer_copy_1)(target: target_buffer, source: source_buffer);
2341 total_bytes_copied += bytes_copied;
2342 source_buffer += bytes_copied;
2343 }
2344
2345 return total_bytes_copied;
2346}
2347
2348template <typename TargetIterator, typename SourceIterator>
2349std::size_t buffer_copy(multiple_buffers, multiple_buffers,
2350 TargetIterator target_begin, TargetIterator target_end,
2351 SourceIterator source_begin, SourceIterator source_end) noexcept
2352{
2353 std::size_t total_bytes_copied = 0;
2354
2355 TargetIterator target_iter = target_begin;
2356 std::size_t target_buffer_offset = 0;
2357
2358 SourceIterator source_iter = source_begin;
2359 std::size_t source_buffer_offset = 0;
2360
2361 while (target_iter != target_end && source_iter != source_end)
2362 {
2363 mutable_buffer target_buffer =
2364 mutable_buffer(*target_iter) + target_buffer_offset;
2365
2366 const_buffer source_buffer =
2367 const_buffer(*source_iter) + source_buffer_offset;
2368
2369 std::size_t bytes_copied = (buffer_copy_1)(target: target_buffer, source: source_buffer);
2370 total_bytes_copied += bytes_copied;
2371
2372 if (bytes_copied == target_buffer.size())
2373 {
2374 ++target_iter;
2375 target_buffer_offset = 0;
2376 }
2377 else
2378 target_buffer_offset += bytes_copied;
2379
2380 if (bytes_copied == source_buffer.size())
2381 {
2382 ++source_iter;
2383 source_buffer_offset = 0;
2384 }
2385 else
2386 source_buffer_offset += bytes_copied;
2387 }
2388
2389 return total_bytes_copied;
2390}
2391
2392template <typename TargetIterator, typename SourceIterator>
2393std::size_t buffer_copy(multiple_buffers, multiple_buffers,
2394 TargetIterator target_begin, TargetIterator target_end,
2395 SourceIterator source_begin, SourceIterator source_end,
2396 std::size_t max_bytes_to_copy) noexcept
2397{
2398 std::size_t total_bytes_copied = 0;
2399
2400 TargetIterator target_iter = target_begin;
2401 std::size_t target_buffer_offset = 0;
2402
2403 SourceIterator source_iter = source_begin;
2404 std::size_t source_buffer_offset = 0;
2405
2406 while (total_bytes_copied != max_bytes_to_copy
2407 && target_iter != target_end && source_iter != source_end)
2408 {
2409 mutable_buffer target_buffer =
2410 mutable_buffer(*target_iter) + target_buffer_offset;
2411
2412 const_buffer source_buffer =
2413 const_buffer(*source_iter) + source_buffer_offset;
2414
2415 std::size_t bytes_copied = (buffer_copy_1)(
2416 target: target_buffer, source: boost::asio::buffer(b: source_buffer,
2417 max_size_in_bytes: max_bytes_to_copy - total_bytes_copied));
2418 total_bytes_copied += bytes_copied;
2419
2420 if (bytes_copied == target_buffer.size())
2421 {
2422 ++target_iter;
2423 target_buffer_offset = 0;
2424 }
2425 else
2426 target_buffer_offset += bytes_copied;
2427
2428 if (bytes_copied == source_buffer.size())
2429 {
2430 ++source_iter;
2431 source_buffer_offset = 0;
2432 }
2433 else
2434 source_buffer_offset += bytes_copied;
2435 }
2436
2437 return total_bytes_copied;
2438}
2439
2440} // namespace detail
2441
2442/// Copies bytes from a source buffer sequence to a target buffer sequence.
2443/**
2444 * @param target A modifiable buffer sequence representing the memory regions to
2445 * which the bytes will be copied.
2446 *
2447 * @param source A non-modifiable buffer sequence representing the memory
2448 * regions from which the bytes will be copied.
2449 *
2450 * @returns The number of bytes copied.
2451 *
2452 * @note The number of bytes copied is the lesser of:
2453 *
2454 * @li @c buffer_size(target)
2455 *
2456 * @li @c buffer_size(source)
2457 *
2458 * This function is implemented in terms of @c memcpy, and consequently it
2459 * cannot be used to copy between overlapping memory regions.
2460 */
2461template <typename MutableBufferSequence, typename ConstBufferSequence>
2462inline std::size_t buffer_copy(const MutableBufferSequence& target,
2463 const ConstBufferSequence& source) noexcept
2464{
2465 return detail::buffer_copy(
2466 detail::buffer_sequence_cardinality<MutableBufferSequence>(),
2467 detail::buffer_sequence_cardinality<ConstBufferSequence>(),
2468 boost::asio::buffer_sequence_begin(target),
2469 boost::asio::buffer_sequence_end(target),
2470 boost::asio::buffer_sequence_begin(source),
2471 boost::asio::buffer_sequence_end(source));
2472}
2473
2474/// Copies a limited number of bytes from a source buffer sequence to a target
2475/// buffer sequence.
2476/**
2477 * @param target A modifiable buffer sequence representing the memory regions to
2478 * which the bytes will be copied.
2479 *
2480 * @param source A non-modifiable buffer sequence representing the memory
2481 * regions from which the bytes will be copied.
2482 *
2483 * @param max_bytes_to_copy The maximum number of bytes to be copied.
2484 *
2485 * @returns The number of bytes copied.
2486 *
2487 * @note The number of bytes copied is the lesser of:
2488 *
2489 * @li @c buffer_size(target)
2490 *
2491 * @li @c buffer_size(source)
2492 *
2493 * @li @c max_bytes_to_copy
2494 *
2495 * This function is implemented in terms of @c memcpy, and consequently it
2496 * cannot be used to copy between overlapping memory regions.
2497 */
2498template <typename MutableBufferSequence, typename ConstBufferSequence>
2499inline std::size_t buffer_copy(const MutableBufferSequence& target,
2500 const ConstBufferSequence& source,
2501 std::size_t max_bytes_to_copy) noexcept
2502{
2503 return detail::buffer_copy(
2504 detail::buffer_sequence_cardinality<MutableBufferSequence>(),
2505 detail::buffer_sequence_cardinality<ConstBufferSequence>(),
2506 boost::asio::buffer_sequence_begin(target),
2507 boost::asio::buffer_sequence_end(target),
2508 boost::asio::buffer_sequence_begin(source),
2509 boost::asio::buffer_sequence_end(source), max_bytes_to_copy);
2510}
2511
2512/*@}*/
2513
2514} // namespace asio
2515} // namespace boost
2516
2517#include <boost/asio/detail/pop_options.hpp>
2518#include <boost/asio/detail/is_buffer_sequence.hpp>
2519#include <boost/asio/detail/push_options.hpp>
2520
2521namespace boost {
2522namespace asio {
2523
2524/// Trait to determine whether a type satisfies the MutableBufferSequence
2525/// requirements.
2526template <typename T>
2527struct is_mutable_buffer_sequence
2528#if defined(GENERATING_DOCUMENTATION)
2529 : integral_constant<bool, automatically_determined>
2530#else // defined(GENERATING_DOCUMENTATION)
2531 : boost::asio::detail::is_buffer_sequence<T, mutable_buffer>
2532#endif // defined(GENERATING_DOCUMENTATION)
2533{
2534};
2535
2536/// Trait to determine whether a type satisfies the ConstBufferSequence
2537/// requirements.
2538template <typename T>
2539struct is_const_buffer_sequence
2540#if defined(GENERATING_DOCUMENTATION)
2541 : integral_constant<bool, automatically_determined>
2542#else // defined(GENERATING_DOCUMENTATION)
2543 : boost::asio::detail::is_buffer_sequence<T, const_buffer>
2544#endif // defined(GENERATING_DOCUMENTATION)
2545{
2546};
2547
2548#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2549/// Trait to determine whether a type satisfies the DynamicBuffer_v1
2550/// requirements.
2551template <typename T>
2552struct is_dynamic_buffer_v1
2553#if defined(GENERATING_DOCUMENTATION)
2554 : integral_constant<bool, automatically_determined>
2555#else // defined(GENERATING_DOCUMENTATION)
2556 : boost::asio::detail::is_dynamic_buffer_v1<T>
2557#endif // defined(GENERATING_DOCUMENTATION)
2558{
2559};
2560#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2561
2562/// Trait to determine whether a type satisfies the DynamicBuffer_v2
2563/// requirements.
2564template <typename T>
2565struct is_dynamic_buffer_v2
2566#if defined(GENERATING_DOCUMENTATION)
2567 : integral_constant<bool, automatically_determined>
2568#else // defined(GENERATING_DOCUMENTATION)
2569 : boost::asio::detail::is_dynamic_buffer_v2<T>
2570#endif // defined(GENERATING_DOCUMENTATION)
2571{
2572};
2573
2574/// Trait to determine whether a type satisfies the DynamicBuffer requirements.
2575/**
2576 * If @c BOOST_ASIO_NO_DYNAMIC_BUFFER_V1 is not defined, determines whether the
2577 * type satisfies the DynamicBuffer_v1 requirements. Otherwise, if @c
2578 * BOOST_ASIO_NO_DYNAMIC_BUFFER_V1 is defined, determines whether the type
2579 * satisfies the DynamicBuffer_v2 requirements.
2580 */
2581template <typename T>
2582struct is_dynamic_buffer
2583#if defined(GENERATING_DOCUMENTATION)
2584 : integral_constant<bool, automatically_determined>
2585#elif defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2586 : boost::asio::is_dynamic_buffer_v2<T>
2587#else // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2588 : boost::asio::is_dynamic_buffer_v1<T>
2589#endif // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2590{
2591};
2592
2593namespace buffer_literals {
2594namespace detail {
2595
2596template <char... Chars>
2597struct chars {};
2598
2599template <unsigned char... Bytes>
2600struct bytes {};
2601
2602// Literal processor that converts binary literals to an array of bytes.
2603
2604template <typename Bytes, char... Chars>
2605struct bin_literal;
2606
2607template <unsigned char... Bytes>
2608struct bin_literal<bytes<Bytes...>>
2609{
2610 static const std::size_t size = sizeof...(Bytes);
2611 static const unsigned char data[sizeof...(Bytes)];
2612};
2613
2614template <unsigned char... Bytes>
2615const unsigned char bin_literal<bytes<Bytes...>>::data[sizeof...(Bytes)]
2616 = { Bytes... };
2617
2618template <unsigned char... Bytes, char Bit7, char Bit6, char Bit5,
2619 char Bit4, char Bit3, char Bit2, char Bit1, char Bit0, char... Chars>
2620struct bin_literal<bytes<Bytes...>, Bit7, Bit6,
2621 Bit5, Bit4, Bit3, Bit2, Bit1, Bit0, Chars...> :
2622 bin_literal<
2623 bytes<Bytes...,
2624 static_cast<unsigned char>(
2625 (Bit7 == '1' ? 0x80 : 0) |
2626 (Bit6 == '1' ? 0x40 : 0) |
2627 (Bit5 == '1' ? 0x20 : 0) |
2628 (Bit4 == '1' ? 0x10 : 0) |
2629 (Bit3 == '1' ? 0x08 : 0) |
2630 (Bit2 == '1' ? 0x04 : 0) |
2631 (Bit1 == '1' ? 0x02 : 0) |
2632 (Bit0 == '1' ? 0x01 : 0))
2633 >, Chars...> {};
2634
2635template <unsigned char... Bytes, char... Chars>
2636struct bin_literal<bytes<Bytes...>, Chars...>
2637{
2638 static_assert(sizeof...(Chars) == 0,
2639 "number of digits in a binary buffer literal must be a multiple of 8");
2640
2641 static const std::size_t size = 0;
2642 static const unsigned char data[1];
2643};
2644
2645template <unsigned char... Bytes, char... Chars>
2646const unsigned char bin_literal<bytes<Bytes...>, Chars...>::data[1] = {};
2647
2648// Literal processor that converts hexadecimal literals to an array of bytes.
2649
2650template <typename Bytes, char... Chars>
2651struct hex_literal;
2652
2653template <unsigned char... Bytes>
2654struct hex_literal<bytes<Bytes...>>
2655{
2656 static const std::size_t size = sizeof...(Bytes);
2657 static const unsigned char data[sizeof...(Bytes)];
2658};
2659
2660template <unsigned char... Bytes>
2661const unsigned char hex_literal<bytes<Bytes...>>::data[sizeof...(Bytes)]
2662 = { Bytes... };
2663
2664template <unsigned char... Bytes, char Hi, char Lo, char... Chars>
2665struct hex_literal<bytes<Bytes...>, Hi, Lo, Chars...> :
2666 hex_literal<
2667 bytes<Bytes...,
2668 static_cast<unsigned char>(
2669 Lo >= 'A' && Lo <= 'F' ? Lo - 'A' + 10 :
2670 (Lo >= 'a' && Lo <= 'f' ? Lo - 'a' + 10 : Lo - '0')) |
2671 ((static_cast<unsigned char>(
2672 Hi >= 'A' && Hi <= 'F' ? Hi - 'A' + 10 :
2673 (Hi >= 'a' && Hi <= 'f' ? Hi - 'a' + 10 : Hi - '0'))) << 4)
2674 >, Chars...> {};
2675
2676template <unsigned char... Bytes, char Char>
2677struct hex_literal<bytes<Bytes...>, Char>
2678{
2679 static_assert(!Char,
2680 "a hexadecimal buffer literal must have an even number of digits");
2681
2682 static const std::size_t size = 0;
2683 static const unsigned char data[1];
2684};
2685
2686template <unsigned char... Bytes, char Char>
2687const unsigned char hex_literal<bytes<Bytes...>, Char>::data[1] = {};
2688
2689// Helper template that removes digit separators and then passes the cleaned
2690// variadic pack of characters to the literal processor.
2691
2692template <template <typename, char...> class Literal,
2693 typename Clean, char... Raw>
2694struct remove_separators;
2695
2696template <template <typename, char...> class Literal,
2697 char... Clean, char... Raw>
2698struct remove_separators<Literal, chars<Clean...>, '\'', Raw...> :
2699 remove_separators<Literal, chars<Clean...>, Raw...> {};
2700
2701template <template <typename, char...> class Literal,
2702 char... Clean, char C, char... Raw>
2703struct remove_separators<Literal, chars<Clean...>, C, Raw...> :
2704 remove_separators<Literal, chars<Clean..., C>, Raw...> {};
2705
2706template <template <typename, char...> class Literal, char... Clean>
2707struct remove_separators<Literal, chars<Clean...>> :
2708 Literal<bytes<>, Clean...> {};
2709
2710// Helper template to determine the literal type based on the prefix.
2711
2712template <char... Chars>
2713struct literal;
2714
2715template <char... Chars>
2716struct literal<'0', 'b', Chars...> :
2717 remove_separators<bin_literal, chars<>, Chars...>{};
2718
2719template <char... Chars>
2720struct literal<'0', 'B', Chars...> :
2721 remove_separators<bin_literal, chars<>, Chars...>{};
2722
2723template <char... Chars>
2724struct literal<'0', 'x', Chars...> :
2725 remove_separators<hex_literal, chars<>, Chars...>{};
2726
2727template <char... Chars>
2728struct literal<'0', 'X', Chars...> :
2729 remove_separators<hex_literal, chars<>, Chars...>{};
2730
2731} // namespace detail
2732
2733/// Literal operator for creating const_buffer objects from string literals.
2734inline BOOST_ASIO_CONST_BUFFER operator ""_buf(const char* data, std::size_t n)
2735{
2736 return BOOST_ASIO_CONST_BUFFER(data, n);
2737}
2738
2739/// Literal operator for creating const_buffer objects from unbounded binary or
2740/// hexadecimal integer literals.
2741template <char... Chars>
2742inline BOOST_ASIO_CONST_BUFFER operator ""_buf()
2743{
2744 return BOOST_ASIO_CONST_BUFFER(
2745 +detail::literal<Chars...>::data,
2746 detail::literal<Chars...>::size);
2747}
2748
2749} // namespace buffer_literals
2750} // namespace asio
2751} // namespace boost
2752
2753#include <boost/asio/detail/pop_options.hpp>
2754
2755#endif // BOOST_ASIO_BUFFER_HPP
2756

source code of boost/libs/asio/include/boost/asio/buffer.hpp