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