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