Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:35:36

0001 //
0002 // buffer.hpp
0003 // ~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_BUFFER_HPP
0012 #define BOOST_ASIO_BUFFER_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <cstddef>
0020 #include <cstring>
0021 #include <limits>
0022 #include <stdexcept>
0023 #include <string>
0024 #include <vector>
0025 #include <boost/asio/detail/array_fwd.hpp>
0026 #include <boost/asio/detail/memory.hpp>
0027 #include <boost/asio/detail/string_view.hpp>
0028 #include <boost/asio/detail/throw_exception.hpp>
0029 #include <boost/asio/detail/type_traits.hpp>
0030 #include <boost/asio/is_contiguous_iterator.hpp>
0031 
0032 #if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700)
0033 # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
0034 #  if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
0035 #   define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0036 #  endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
0037 # endif // defined(_HAS_ITERATOR_DEBUGGING)
0038 #endif // defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700)
0039 
0040 #if defined(__GNUC__)
0041 # if defined(_GLIBCXX_DEBUG)
0042 #  if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
0043 #   define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0044 #  endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING)
0045 # endif // defined(_GLIBCXX_DEBUG)
0046 #endif // defined(__GNUC__)
0047 
0048 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0049 # include <boost/asio/detail/functional.hpp>
0050 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0051 
0052 #include <boost/asio/detail/push_options.hpp>
0053 
0054 namespace boost {
0055 namespace asio {
0056 namespace detail {
0057 
0058 #if defined(BOOST_ASIO_MSVC)
0059 
0060 struct span_memfns_base
0061 {
0062   void subspan();
0063 };
0064 
0065 template <typename T>
0066 struct span_memfns_derived : T, span_memfns_base
0067 {
0068 };
0069 
0070 template <typename T, T>
0071 struct span_memfns_check
0072 {
0073 };
0074 
0075 template <typename>
0076 char (&subspan_memfn_helper(...))[2];
0077 
0078 template <typename T>
0079 char subspan_memfn_helper(
0080     span_memfns_check<
0081       void (span_memfns_base::*)(),
0082       &span_memfns_derived<T>::subspan>*);
0083 
0084 template <typename T>
0085 struct has_subspan_memfn :
0086   integral_constant<bool, sizeof(subspan_memfn_helper<T>(0)) != 1>
0087 {
0088 };
0089 
0090 #endif // defined(BOOST_ASIO_MSVC)
0091 
0092 } // namespace detail
0093 
0094 class mutable_buffer;
0095 class const_buffer;
0096 
0097 /// Holds a buffer that can be modified.
0098 /**
0099  * The mutable_buffer class provides a safe representation of a buffer that can
0100  * be modified. It does not own the underlying data, and so is cheap to copy or
0101  * assign.
0102  *
0103  * @par Accessing Buffer Contents
0104  *
0105  * The contents of a buffer may be accessed using the @c data() and @c size()
0106  * member functions:
0107  *
0108  * @code boost::asio::mutable_buffer b1 = ...;
0109  * std::size_t s1 = b1.size();
0110  * unsigned char* p1 = static_cast<unsigned char*>(b1.data());
0111  * @endcode
0112  *
0113  * The @c data() member function permits violations of type safety, so uses of
0114  * it in application code should be carefully considered.
0115  */
0116 class mutable_buffer
0117 {
0118 public:
0119   /// Construct an empty buffer.
0120   mutable_buffer() noexcept
0121     : data_(0),
0122       size_(0)
0123   {
0124   }
0125 
0126   /// Construct a buffer to represent a given memory range.
0127   mutable_buffer(void* data, std::size_t size) noexcept
0128     : data_(data),
0129       size_(size)
0130   {
0131   }
0132 
0133   /// Construct a buffer from a span of bytes.
0134   template <template <typename, std::size_t> class Span,
0135       typename T, std::size_t Extent>
0136   mutable_buffer(const Span<T, Extent>& span,
0137       constraint_t<
0138         !is_const<T>::value,
0139         defaulted_constraint
0140       > = defaulted_constraint(),
0141       constraint_t<
0142         sizeof(T) == 1,
0143         defaulted_constraint
0144       > = defaulted_constraint(),
0145       constraint_t<
0146 #if defined(BOOST_ASIO_MSVC)
0147         detail::has_subspan_memfn<Span<T, Extent>>::value,
0148 #else // defined(BOOST_ASIO_MSVC)
0149         is_same<
0150           decltype(span.subspan(0, 0)),
0151           Span<T, static_cast<std::size_t>(-1)>
0152         >::value,
0153 #endif // defined(BOOST_ASIO_MSVC)
0154         defaulted_constraint
0155       > = defaulted_constraint())
0156     : data_(span.data()),
0157       size_(span.size())
0158   {
0159   }
0160 
0161 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0162   mutable_buffer(void* data, std::size_t size,
0163       boost::asio::detail::function<void()> debug_check)
0164     : data_(data),
0165       size_(size),
0166       debug_check_(debug_check)
0167   {
0168   }
0169 
0170   const boost::asio::detail::function<void()>& get_debug_check() const
0171   {
0172     return debug_check_;
0173   }
0174 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0175 
0176   /// Get a pointer to the beginning of the memory range.
0177   void* data() const noexcept
0178   {
0179 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0180     if (size_ && debug_check_)
0181       debug_check_();
0182 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0183     return data_;
0184   }
0185 
0186   /// Get the size of the memory range.
0187   std::size_t size() const noexcept
0188   {
0189     return size_;
0190   }
0191 
0192   /// Move the start of the buffer by the specified number of bytes.
0193   mutable_buffer& operator+=(std::size_t n) noexcept
0194   {
0195     std::size_t offset = n < size_ ? n : size_;
0196     data_ = static_cast<char*>(data_) + offset;
0197     size_ -= offset;
0198     return *this;
0199   }
0200 
0201 private:
0202   void* data_;
0203   std::size_t size_;
0204 
0205 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0206   boost::asio::detail::function<void()> debug_check_;
0207 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0208 };
0209 
0210 /// Holds a buffer that cannot be modified.
0211 /**
0212  * The const_buffer class provides a safe representation of a buffer that cannot
0213  * be modified. It does not own the underlying data, and so is cheap to copy or
0214  * assign.
0215  *
0216  * @par Accessing Buffer Contents
0217  *
0218  * The contents of a buffer may be accessed using the @c data() and @c size()
0219  * member functions:
0220  *
0221  * @code boost::asio::const_buffer b1 = ...;
0222  * std::size_t s1 = b1.size();
0223  * const unsigned char* p1 = static_cast<const unsigned char*>(b1.data());
0224  * @endcode
0225  *
0226  * The @c data() member function permits violations of type safety, so uses of
0227  * it in application code should be carefully considered.
0228  */
0229 class const_buffer
0230 {
0231 public:
0232   /// Construct an empty buffer.
0233   const_buffer() noexcept
0234     : data_(0),
0235       size_(0)
0236   {
0237   }
0238 
0239   /// Construct a buffer to represent a given memory range.
0240   const_buffer(const void* data, std::size_t size) noexcept
0241     : data_(data),
0242       size_(size)
0243   {
0244   }
0245 
0246   /// Construct a non-modifiable buffer from a modifiable one.
0247   const_buffer(const mutable_buffer& b) noexcept
0248     : data_(b.data()),
0249       size_(b.size())
0250 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0251       , debug_check_(b.get_debug_check())
0252 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0253   {
0254   }
0255 
0256   /// Construct a buffer from a span of bytes.
0257   template <template <typename, std::size_t> class Span,
0258       typename T, std::size_t Extent>
0259   const_buffer(const Span<T, Extent>& span,
0260       constraint_t<
0261         sizeof(T) == 1,
0262         defaulted_constraint
0263       > = defaulted_constraint(),
0264       constraint_t<
0265 #if defined(BOOST_ASIO_MSVC)
0266         detail::has_subspan_memfn<Span<T, Extent>>::value,
0267 #else // defined(BOOST_ASIO_MSVC)
0268         is_same<
0269           decltype(span.subspan(0, 0)),
0270           Span<T, static_cast<std::size_t>(-1)>
0271         >::value,
0272 #endif // defined(BOOST_ASIO_MSVC)
0273         defaulted_constraint
0274       > = defaulted_constraint())
0275     : data_(span.data()),
0276       size_(span.size())
0277   {
0278   }
0279 
0280 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0281   const_buffer(const void* data, std::size_t size,
0282       boost::asio::detail::function<void()> debug_check)
0283     : data_(data),
0284       size_(size),
0285       debug_check_(debug_check)
0286   {
0287   }
0288 
0289   const boost::asio::detail::function<void()>& get_debug_check() const
0290   {
0291     return debug_check_;
0292   }
0293 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0294 
0295   /// Get a pointer to the beginning of the memory range.
0296   const void* data() const noexcept
0297   {
0298 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0299     if (size_ && debug_check_)
0300       debug_check_();
0301 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0302     return data_;
0303   }
0304 
0305   /// Get the size of the memory range.
0306   std::size_t size() const noexcept
0307   {
0308     return size_;
0309   }
0310 
0311   /// Move the start of the buffer by the specified number of bytes.
0312   const_buffer& operator+=(std::size_t n) noexcept
0313   {
0314     std::size_t offset = n < size_ ? n : size_;
0315     data_ = static_cast<const char*>(data_) + offset;
0316     size_ -= offset;
0317     return *this;
0318   }
0319 
0320 private:
0321   const void* data_;
0322   std::size_t size_;
0323 
0324 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0325   boost::asio::detail::function<void()> debug_check_;
0326 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0327 };
0328 
0329 /// (Deprecated: Use the socket/descriptor wait() and async_wait() member
0330 /// functions.) An implementation of both the ConstBufferSequence and
0331 /// MutableBufferSequence concepts to represent a null buffer sequence.
0332 class null_buffers
0333 {
0334 public:
0335   /// The type for each element in the list of buffers.
0336   typedef mutable_buffer value_type;
0337 
0338   /// A random-access iterator type that may be used to read elements.
0339   typedef const mutable_buffer* const_iterator;
0340 
0341   /// Get a random-access iterator to the first element.
0342   const_iterator begin() const noexcept
0343   {
0344     return &buf_;
0345   }
0346 
0347   /// Get a random-access iterator for one past the last element.
0348   const_iterator end() const noexcept
0349   {
0350     return &buf_;
0351   }
0352 
0353 private:
0354   mutable_buffer buf_;
0355 };
0356 
0357 /** @defgroup buffer_sequence_begin boost::asio::buffer_sequence_begin
0358  *
0359  * @brief The boost::asio::buffer_sequence_begin function returns an iterator
0360  * pointing to the first element in a buffer sequence.
0361  */
0362 /*@{*/
0363 
0364 /// Get an iterator to the first element in a buffer sequence.
0365 template <typename MutableBuffer>
0366 inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b,
0367     constraint_t<
0368       is_convertible<const MutableBuffer*, const mutable_buffer*>::value
0369     > = 0) noexcept
0370 {
0371   return static_cast<const mutable_buffer*>(detail::addressof(b));
0372 }
0373 
0374 /// Get an iterator to the first element in a buffer sequence.
0375 template <typename ConstBuffer>
0376 inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b,
0377     constraint_t<
0378       is_convertible<const ConstBuffer*, const const_buffer*>::value
0379     > = 0) noexcept
0380 {
0381   return static_cast<const const_buffer*>(detail::addressof(b));
0382 }
0383 
0384 /// Get an iterator to the first element in a buffer sequence.
0385 template <typename ConvertibleToBuffer>
0386 inline const ConvertibleToBuffer* buffer_sequence_begin(
0387     const ConvertibleToBuffer& b,
0388     constraint_t<
0389       !is_convertible<const ConvertibleToBuffer*, const mutable_buffer*>::value
0390     > = 0,
0391     constraint_t<
0392       !is_convertible<const ConvertibleToBuffer*, const const_buffer*>::value
0393     > = 0,
0394     constraint_t<
0395       is_convertible<ConvertibleToBuffer, mutable_buffer>::value
0396         || is_convertible<ConvertibleToBuffer, const_buffer>::value
0397     > = 0) noexcept
0398 {
0399   return detail::addressof(b);
0400 }
0401 
0402 /// Get an iterator to the first element in a buffer sequence.
0403 template <typename C>
0404 inline auto buffer_sequence_begin(C& c,
0405     constraint_t<
0406       !is_convertible<const C*, const mutable_buffer*>::value
0407     > = 0,
0408     constraint_t<
0409       !is_convertible<const C*, const const_buffer*>::value
0410     > = 0,
0411     constraint_t<
0412       !is_convertible<C, mutable_buffer>::value
0413     > = 0,
0414     constraint_t<
0415       !is_convertible<C, const_buffer>::value
0416     > = 0) noexcept -> decltype(c.begin())
0417 {
0418   return c.begin();
0419 }
0420 
0421 /// Get an iterator to the first element in a buffer sequence.
0422 template <typename C>
0423 inline auto buffer_sequence_begin(const C& c,
0424     constraint_t<
0425       !is_convertible<const C*, const mutable_buffer*>::value
0426     > = 0,
0427     constraint_t<
0428       !is_convertible<const C*, const const_buffer*>::value
0429     > = 0,
0430     constraint_t<
0431       !is_convertible<C, mutable_buffer>::value
0432     > = 0,
0433     constraint_t<
0434       !is_convertible<C, const_buffer>::value
0435     > = 0) noexcept -> decltype(c.begin())
0436 {
0437   return c.begin();
0438 }
0439 
0440 /*@}*/
0441 
0442 /** @defgroup buffer_sequence_end boost::asio::buffer_sequence_end
0443  *
0444  * @brief The boost::asio::buffer_sequence_end function returns an iterator
0445  * pointing to one past the end element in a buffer sequence.
0446  */
0447 /*@{*/
0448 
0449 /// Get an iterator to one past the end element in a buffer sequence.
0450 template <typename MutableBuffer>
0451 inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b,
0452     constraint_t<
0453       is_convertible<const MutableBuffer*, const mutable_buffer*>::value
0454     > = 0) noexcept
0455 {
0456   return static_cast<const mutable_buffer*>(detail::addressof(b)) + 1;
0457 }
0458 
0459 /// Get an iterator to one past the end element in a buffer sequence.
0460 template <typename ConstBuffer>
0461 inline const const_buffer* buffer_sequence_end(const ConstBuffer& b,
0462     constraint_t<
0463       is_convertible<const ConstBuffer*, const const_buffer*>::value
0464     > = 0) noexcept
0465 {
0466   return static_cast<const const_buffer*>(detail::addressof(b)) + 1;
0467 }
0468 
0469 /// Get an iterator to one past the end element in a buffer sequence.
0470 template <typename ConvertibleToBuffer>
0471 inline const ConvertibleToBuffer* buffer_sequence_end(
0472     const ConvertibleToBuffer& b,
0473     constraint_t<
0474       !is_convertible<const ConvertibleToBuffer*, const mutable_buffer*>::value
0475     > = 0,
0476     constraint_t<
0477       !is_convertible<const ConvertibleToBuffer*, const const_buffer*>::value
0478     > = 0,
0479     constraint_t<
0480       is_convertible<ConvertibleToBuffer, mutable_buffer>::value
0481         || is_convertible<ConvertibleToBuffer, const_buffer>::value
0482     > = 0) noexcept
0483 {
0484   return detail::addressof(b) + 1;
0485 }
0486 
0487 /// Get an iterator to one past the end element in a buffer sequence.
0488 template <typename C>
0489 inline auto buffer_sequence_end(C& c,
0490     constraint_t<
0491       !is_convertible<const C*, const mutable_buffer*>::value
0492     > = 0,
0493     constraint_t<
0494       !is_convertible<const C*, const const_buffer*>::value
0495     > = 0,
0496     constraint_t<
0497       !is_convertible<C, mutable_buffer>::value
0498     > = 0,
0499     constraint_t<
0500       !is_convertible<C, const_buffer>::value
0501     > = 0) noexcept -> decltype(c.end())
0502 {
0503   return c.end();
0504 }
0505 
0506 /// Get an iterator to one past the end element in a buffer sequence.
0507 template <typename C>
0508 inline auto buffer_sequence_end(const C& c,
0509     constraint_t<
0510       !is_convertible<const C*, const mutable_buffer*>::value
0511     > = 0,
0512     constraint_t<
0513       !is_convertible<const C*, const const_buffer*>::value
0514     > = 0,
0515     constraint_t<
0516       !is_convertible<C, mutable_buffer>::value
0517     > = 0,
0518     constraint_t<
0519       !is_convertible<C, const_buffer>::value
0520     > = 0) noexcept -> decltype(c.end())
0521 {
0522   return c.end();
0523 }
0524 
0525 /*@}*/
0526 
0527 namespace detail {
0528 
0529 // Tag types used to select appropriately optimised overloads.
0530 struct one_buffer {};
0531 struct multiple_buffers {};
0532 
0533 // Helper trait to detect single buffers.
0534 template <typename BufferSequence>
0535 struct buffer_sequence_cardinality :
0536   conditional_t<
0537     is_same<BufferSequence, mutable_buffer>::value
0538       || is_same<BufferSequence, const_buffer>::value,
0539     one_buffer, multiple_buffers> {};
0540 
0541 template <typename Iterator>
0542 inline std::size_t buffer_size(one_buffer,
0543     Iterator begin, Iterator) noexcept
0544 {
0545   return const_buffer(*begin).size();
0546 }
0547 
0548 template <typename Iterator>
0549 inline std::size_t buffer_size(multiple_buffers,
0550     Iterator begin, Iterator end) noexcept
0551 {
0552   std::size_t total_buffer_size = 0;
0553 
0554   Iterator iter = begin;
0555   for (; iter != end; ++iter)
0556   {
0557     const_buffer b(*iter);
0558     total_buffer_size += b.size();
0559   }
0560 
0561   return total_buffer_size;
0562 }
0563 
0564 } // namespace detail
0565 
0566 /// Get the total number of bytes in a buffer sequence.
0567 /**
0568  * The @c buffer_size function determines the total size of all buffers in the
0569  * buffer sequence, as if computed as follows:
0570  *
0571  * @code size_t total_size = 0;
0572  * auto i = boost::asio::buffer_sequence_begin(buffers);
0573  * auto end = boost::asio::buffer_sequence_end(buffers);
0574  * for (; i != end; ++i)
0575  * {
0576  *   const_buffer b(*i);
0577  *   total_size += b.size();
0578  * }
0579  * return total_size; @endcode
0580  *
0581  * The @c BufferSequence template parameter may meet either of the @c
0582  * ConstBufferSequence or @c MutableBufferSequence type requirements.
0583  */
0584 template <typename BufferSequence>
0585 inline std::size_t buffer_size(const BufferSequence& b) noexcept
0586 {
0587   return detail::buffer_size(
0588       detail::buffer_sequence_cardinality<BufferSequence>(),
0589       boost::asio::buffer_sequence_begin(b),
0590       boost::asio::buffer_sequence_end(b));
0591 }
0592 
0593 /// Create a new modifiable buffer that is offset from the start of another.
0594 /**
0595  * @relates mutable_buffer
0596  */
0597 inline mutable_buffer operator+(const mutable_buffer& b,
0598     std::size_t n) noexcept
0599 {
0600   std::size_t offset = n < b.size() ? n : b.size();
0601   char* new_data = static_cast<char*>(b.data()) + offset;
0602   std::size_t new_size = b.size() - offset;
0603   return mutable_buffer(new_data, new_size
0604 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0605       , b.get_debug_check()
0606 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0607       );
0608 }
0609 
0610 /// Create a new modifiable buffer that is offset from the start of another.
0611 /**
0612  * @relates mutable_buffer
0613  */
0614 inline mutable_buffer operator+(std::size_t n,
0615     const mutable_buffer& b) noexcept
0616 {
0617   return b + n;
0618 }
0619 
0620 /// Create a new non-modifiable buffer that is offset from the start of another.
0621 /**
0622  * @relates const_buffer
0623  */
0624 inline const_buffer operator+(const const_buffer& b,
0625     std::size_t n) noexcept
0626 {
0627   std::size_t offset = n < b.size() ? n : b.size();
0628   const char* new_data = static_cast<const char*>(b.data()) + offset;
0629   std::size_t new_size = b.size() - offset;
0630   return const_buffer(new_data, new_size
0631 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0632       , b.get_debug_check()
0633 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0634       );
0635 }
0636 
0637 /// Create a new non-modifiable buffer that is offset from the start of another.
0638 /**
0639  * @relates const_buffer
0640  */
0641 inline const_buffer operator+(std::size_t n,
0642     const const_buffer& b) noexcept
0643 {
0644   return b + n;
0645 }
0646 
0647 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0648 namespace detail {
0649 
0650 template <typename Iterator>
0651 class buffer_debug_check
0652 {
0653 public:
0654   buffer_debug_check(Iterator iter)
0655     : iter_(iter)
0656   {
0657   }
0658 
0659   ~buffer_debug_check()
0660   {
0661 #if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC == 1400)
0662     // MSVC 8's string iterator checking may crash in a std::string::iterator
0663     // object's destructor when the iterator points to an already-destroyed
0664     // std::string object, unless the iterator is cleared first.
0665     iter_ = Iterator();
0666 #endif // defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC == 1400)
0667   }
0668 
0669   void operator()()
0670   {
0671     (void)*iter_;
0672   }
0673 
0674 private:
0675   Iterator iter_;
0676 };
0677 
0678 } // namespace detail
0679 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0680 
0681 /** @defgroup buffer boost::asio::buffer
0682  *
0683  * @brief The boost::asio::buffer function is used to create a buffer object to
0684  * represent raw memory, an array of POD elements, a vector of POD elements,
0685  * or a std::string.
0686  *
0687  * A buffer object represents a contiguous region of memory as a 2-tuple
0688  * consisting of a pointer and size in bytes. A tuple of the form <tt>{void*,
0689  * size_t}</tt> specifies a mutable (modifiable) region of memory. Similarly, a
0690  * tuple of the form <tt>{const void*, size_t}</tt> specifies a const
0691  * (non-modifiable) region of memory. These two forms correspond to the classes
0692  * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion
0693  * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the
0694  * opposite conversion is not permitted.
0695  *
0696  * The simplest use case involves reading or writing a single buffer of a
0697  * specified size:
0698  *
0699  * @code sock.send(boost::asio::buffer(data, size)); @endcode
0700  *
0701  * In the above example, the return value of boost::asio::buffer meets the
0702  * requirements of the ConstBufferSequence concept so that it may be directly
0703  * passed to the socket's write function. A buffer created for modifiable
0704  * memory also meets the requirements of the MutableBufferSequence concept.
0705  *
0706  * An individual buffer may be created from a builtin array, std::vector,
0707  * std::array or boost::array of POD elements. This helps prevent buffer
0708  * overruns by automatically determining the size of the buffer:
0709  *
0710  * @code char d1[128];
0711  * size_t bytes_transferred = sock.receive(boost::asio::buffer(d1));
0712  *
0713  * std::vector<char> d2(128);
0714  * bytes_transferred = sock.receive(boost::asio::buffer(d2));
0715  *
0716  * std::array<char, 128> d3;
0717  * bytes_transferred = sock.receive(boost::asio::buffer(d3));
0718  *
0719  * boost::array<char, 128> d4;
0720  * bytes_transferred = sock.receive(boost::asio::buffer(d4)); @endcode
0721  *
0722  * In all three cases above, the buffers created are exactly 128 bytes long.
0723  * Note that a vector is @e never automatically resized when creating or using
0724  * a buffer. The buffer size is determined using the vector's <tt>size()</tt>
0725  * member function, and not its capacity.
0726  *
0727  * @par Accessing Buffer Contents
0728  *
0729  * The contents of a buffer may be accessed using the @c data() and @c size()
0730  * member functions:
0731  *
0732  * @code boost::asio::mutable_buffer b1 = ...;
0733  * std::size_t s1 = b1.size();
0734  * unsigned char* p1 = static_cast<unsigned char*>(b1.data());
0735  *
0736  * boost::asio::const_buffer b2 = ...;
0737  * std::size_t s2 = b2.size();
0738  * const void* p2 = b2.data(); @endcode
0739  *
0740  * The @c data() member function permits violations of type safety, so
0741  * uses of it in application code should be carefully considered.
0742  *
0743  * For convenience, a @ref buffer_size function is provided that works with
0744  * both buffers and buffer sequences (that is, types meeting the
0745  * ConstBufferSequence or MutableBufferSequence type requirements). In this
0746  * case, the function returns the total size of all buffers in the sequence.
0747  *
0748  * @par Buffer Copying
0749  *
0750  * The @ref buffer_copy function may be used to copy raw bytes between
0751  * individual buffers and buffer sequences.
0752 *
0753  * In particular, when used with the @ref buffer_size function, the @ref
0754  * buffer_copy function can be used to linearise a sequence of buffers. For
0755  * example:
0756  *
0757  * @code vector<const_buffer> buffers = ...;
0758  *
0759  * vector<unsigned char> data(boost::asio::buffer_size(buffers));
0760  * boost::asio::buffer_copy(boost::asio::buffer(data), buffers); @endcode
0761  *
0762  * Note that @ref buffer_copy is implemented in terms of @c memcpy, and
0763  * consequently it cannot be used to copy between overlapping memory regions.
0764  *
0765  * @par Buffer Invalidation
0766  *
0767  * A buffer object does not have any ownership of the memory it refers to. It
0768  * is the responsibility of the application to ensure the memory region remains
0769  * valid until it is no longer required for an I/O operation. When the memory
0770  * is no longer available, the buffer is said to have been invalidated.
0771  *
0772  * For the boost::asio::buffer overloads that accept an argument of type
0773  * std::vector, the buffer objects returned are invalidated by any vector
0774  * operation that also invalidates all references, pointers and iterators
0775  * referring to the elements in the sequence (C++ Std, 23.2.4)
0776  *
0777  * For the boost::asio::buffer overloads that accept an argument of type
0778  * std::basic_string, the buffer objects returned are invalidated according to
0779  * the rules defined for invalidation of references, pointers and iterators
0780  * referring to elements of the sequence (C++ Std, 21.3).
0781  *
0782  * @par Buffer Arithmetic
0783  *
0784  * Buffer objects may be manipulated using simple arithmetic in a safe way
0785  * which helps prevent buffer overruns. Consider an array initialised as
0786  * follows:
0787  *
0788  * @code boost::array<char, 6> a = { 'a', 'b', 'c', 'd', 'e' }; @endcode
0789  *
0790  * A buffer object @c b1 created using:
0791  *
0792  * @code b1 = boost::asio::buffer(a); @endcode
0793  *
0794  * represents the entire array, <tt>{ 'a', 'b', 'c', 'd', 'e' }</tt>. An
0795  * optional second argument to the boost::asio::buffer function may be used to
0796  * limit the size, in bytes, of the buffer:
0797  *
0798  * @code b2 = boost::asio::buffer(a, 3); @endcode
0799  *
0800  * such that @c b2 represents the data <tt>{ 'a', 'b', 'c' }</tt>. Even if the
0801  * size argument exceeds the actual size of the array, the size of the buffer
0802  * object created will be limited to the array size.
0803  *
0804  * An offset may be applied to an existing buffer to create a new one:
0805  *
0806  * @code b3 = b1 + 2; @endcode
0807  *
0808  * where @c b3 will set to represent <tt>{ 'c', 'd', 'e' }</tt>. If the offset
0809  * exceeds the size of the existing buffer, the newly created buffer will be
0810  * empty.
0811  *
0812  * Both an offset and size may be specified to create a buffer that corresponds
0813  * to a specific range of bytes within an existing buffer:
0814  *
0815  * @code b4 = boost::asio::buffer(b1 + 1, 3); @endcode
0816  *
0817  * so that @c b4 will refer to the bytes <tt>{ 'b', 'c', 'd' }</tt>.
0818  *
0819  * @par Buffers and Scatter-Gather I/O
0820  *
0821  * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple
0822  * buffer objects may be assigned into a container that supports the
0823  * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts:
0824  *
0825  * @code
0826  * char d1[128];
0827  * std::vector<char> d2(128);
0828  * boost::array<char, 128> d3;
0829  *
0830  * boost::array<mutable_buffer, 3> bufs1 = {
0831  *   boost::asio::buffer(d1),
0832  *   boost::asio::buffer(d2),
0833  *   boost::asio::buffer(d3) };
0834  * bytes_transferred = sock.receive(bufs1);
0835  *
0836  * std::vector<const_buffer> bufs2;
0837  * bufs2.push_back(boost::asio::buffer(d1));
0838  * bufs2.push_back(boost::asio::buffer(d2));
0839  * bufs2.push_back(boost::asio::buffer(d3));
0840  * bytes_transferred = sock.send(bufs2); @endcode
0841  *
0842  * @par Buffer Literals
0843  *
0844  * The `_buf` literal suffix, defined in namespace
0845  * <tt>boost::asio::buffer_literals</tt>, may be used to create @c const_buffer
0846  * objects from string, binary integer, and hexadecimal integer literals.
0847  * For example:
0848  *
0849  * @code
0850  * using namespace boost::asio::buffer_literals;
0851  *
0852  * boost::asio::const_buffer b1 = "hello"_buf;
0853  * boost::asio::const_buffer b2 = 0xdeadbeef_buf;
0854  * boost::asio::const_buffer b3 = 0x0123456789abcdef0123456789abcdef_buf;
0855  * boost::asio::const_buffer b4 = 0b1010101011001100_buf; @endcode
0856  *
0857  * Note that the memory associated with a buffer literal is valid for the
0858  * lifetime of the program. This means that the buffer can be safely used with
0859  * asynchronous operations.
0860  */
0861 /*@{*/
0862 
0863 /// Create a new modifiable buffer from an existing buffer.
0864 /**
0865  * @returns <tt>mutable_buffer(b)</tt>.
0866  */
0867 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
0868     const mutable_buffer& b) noexcept
0869 {
0870   return mutable_buffer(b);
0871 }
0872 
0873 /// Create a new modifiable buffer from an existing buffer.
0874 /**
0875  * @returns A mutable_buffer value equivalent to:
0876  * @code mutable_buffer(
0877  *     b.data(),
0878  *     min(b.size(), max_size_in_bytes)); @endcode
0879  */
0880 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
0881     const mutable_buffer& b,
0882     std::size_t max_size_in_bytes) noexcept
0883 {
0884   return mutable_buffer(
0885       mutable_buffer(b.data(),
0886         b.size() < max_size_in_bytes
0887         ? b.size() : max_size_in_bytes
0888 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0889         , b.get_debug_check()
0890 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0891         ));
0892 }
0893 
0894 /// Create a new non-modifiable buffer from an existing buffer.
0895 /**
0896  * @returns <tt>const_buffer(b)</tt>.
0897  */
0898 BOOST_ASIO_NODISCARD inline const_buffer buffer(
0899     const const_buffer& b) noexcept
0900 {
0901   return const_buffer(b);
0902 }
0903 
0904 /// Create a new non-modifiable buffer from an existing buffer.
0905 /**
0906  * @returns A const_buffer value equivalent to:
0907  * @code const_buffer(
0908  *     b.data(),
0909  *     min(b.size(), max_size_in_bytes)); @endcode
0910  */
0911 BOOST_ASIO_NODISCARD inline const_buffer buffer(
0912     const const_buffer& b,
0913     std::size_t max_size_in_bytes) noexcept
0914 {
0915   return const_buffer(b.data(),
0916       b.size() < max_size_in_bytes
0917       ? b.size() : max_size_in_bytes
0918 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
0919       , b.get_debug_check()
0920 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
0921       );
0922 }
0923 
0924 /// Create a new modifiable buffer that represents the given memory range.
0925 /**
0926  * @returns <tt>mutable_buffer(data, size_in_bytes)</tt>.
0927  */
0928 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
0929     void* data, std::size_t size_in_bytes) noexcept
0930 {
0931   return mutable_buffer(data, size_in_bytes);
0932 }
0933 
0934 /// Create a new non-modifiable buffer that represents the given memory range.
0935 /**
0936  * @returns <tt>const_buffer(data, size_in_bytes)</tt>.
0937  */
0938 BOOST_ASIO_NODISCARD inline const_buffer buffer(
0939     const void* data, std::size_t size_in_bytes) noexcept
0940 {
0941   return const_buffer(data, size_in_bytes);
0942 }
0943 
0944 /// Create a new modifiable buffer that represents the given POD array.
0945 /**
0946  * @returns A mutable_buffer value equivalent to:
0947  * @code mutable_buffer(
0948  *     static_cast<void*>(data),
0949  *     N * sizeof(PodType)); @endcode
0950  */
0951 template <typename PodType, std::size_t N>
0952 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
0953     PodType (&data)[N]) noexcept
0954 {
0955   return mutable_buffer(data, N * sizeof(PodType));
0956 }
0957 
0958 /// Create a new modifiable buffer that represents the given POD array.
0959 /**
0960  * @returns A mutable_buffer value equivalent to:
0961  * @code mutable_buffer(
0962  *     static_cast<void*>(data),
0963  *     min(N * sizeof(PodType), max_size_in_bytes)); @endcode
0964  */
0965 template <typename PodType, std::size_t N>
0966 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
0967     PodType (&data)[N],
0968     std::size_t max_size_in_bytes) noexcept
0969 {
0970   return mutable_buffer(data,
0971       N * sizeof(PodType) < max_size_in_bytes
0972       ? N * sizeof(PodType) : max_size_in_bytes);
0973 }
0974 
0975 /// Create a new non-modifiable buffer that represents the given POD array.
0976 /**
0977  * @returns A const_buffer value equivalent to:
0978  * @code const_buffer(
0979  *     static_cast<const void*>(data),
0980  *     N * sizeof(PodType)); @endcode
0981  */
0982 template <typename PodType, std::size_t N>
0983 BOOST_ASIO_NODISCARD inline const_buffer buffer(
0984     const PodType (&data)[N]) noexcept
0985 {
0986   return const_buffer(data, N * sizeof(PodType));
0987 }
0988 
0989 /// Create a new non-modifiable buffer that represents the given POD array.
0990 /**
0991  * @returns A const_buffer value equivalent to:
0992  * @code const_buffer(
0993  *     static_cast<const void*>(data),
0994  *     min(N * sizeof(PodType), max_size_in_bytes)); @endcode
0995  */
0996 template <typename PodType, std::size_t N>
0997 BOOST_ASIO_NODISCARD inline const_buffer buffer(
0998     const PodType (&data)[N],
0999     std::size_t max_size_in_bytes) noexcept
1000 {
1001   return const_buffer(data,
1002       N * sizeof(PodType) < max_size_in_bytes
1003       ? N * sizeof(PodType) : max_size_in_bytes);
1004 }
1005 
1006 /// Create a new modifiable buffer that represents the given POD array.
1007 /**
1008  * @returns A mutable_buffer value equivalent to:
1009  * @code mutable_buffer(
1010  *     data.data(),
1011  *     data.size() * sizeof(PodType)); @endcode
1012  */
1013 template <typename PodType, std::size_t N>
1014 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1015     boost::array<PodType, N>& data) noexcept
1016 {
1017   return mutable_buffer(
1018       data.c_array(), data.size() * sizeof(PodType));
1019 }
1020 
1021 /// Create a new modifiable buffer that represents the given POD array.
1022 /**
1023  * @returns A mutable_buffer value equivalent to:
1024  * @code mutable_buffer(
1025  *     data.data(),
1026  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1027  */
1028 template <typename PodType, std::size_t N>
1029 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1030     boost::array<PodType, N>& data,
1031     std::size_t max_size_in_bytes) noexcept
1032 {
1033   return mutable_buffer(data.c_array(),
1034       data.size() * sizeof(PodType) < max_size_in_bytes
1035       ? data.size() * sizeof(PodType) : max_size_in_bytes);
1036 }
1037 
1038 /// Create a new non-modifiable buffer that represents the given POD array.
1039 /**
1040  * @returns A const_buffer value equivalent to:
1041  * @code const_buffer(
1042  *     data.data(),
1043  *     data.size() * sizeof(PodType)); @endcode
1044  */
1045 template <typename PodType, std::size_t N>
1046 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1047     boost::array<const PodType, N>& data) noexcept
1048 {
1049   return const_buffer(data.data(), data.size() * sizeof(PodType));
1050 }
1051 
1052 /// Create a new non-modifiable buffer that represents the given POD array.
1053 /**
1054  * @returns A const_buffer value equivalent to:
1055  * @code const_buffer(
1056  *     data.data(),
1057  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1058  */
1059 template <typename PodType, std::size_t N>
1060 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1061     boost::array<const PodType, N>& data,
1062     std::size_t max_size_in_bytes) noexcept
1063 {
1064   return const_buffer(data.data(),
1065       data.size() * sizeof(PodType) < max_size_in_bytes
1066       ? data.size() * sizeof(PodType) : max_size_in_bytes);
1067 }
1068 
1069 /// Create a new non-modifiable buffer that represents the given POD array.
1070 /**
1071  * @returns A const_buffer value equivalent to:
1072  * @code const_buffer(
1073  *     data.data(),
1074  *     data.size() * sizeof(PodType)); @endcode
1075  */
1076 template <typename PodType, std::size_t N>
1077 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1078     const boost::array<PodType, N>& data) noexcept
1079 {
1080   return const_buffer(data.data(), data.size() * sizeof(PodType));
1081 }
1082 
1083 /// Create a new non-modifiable buffer that represents the given POD array.
1084 /**
1085  * @returns A const_buffer value equivalent to:
1086  * @code const_buffer(
1087  *     data.data(),
1088  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1089  */
1090 template <typename PodType, std::size_t N>
1091 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1092     const boost::array<PodType, N>& data,
1093     std::size_t max_size_in_bytes) noexcept
1094 {
1095   return const_buffer(data.data(),
1096       data.size() * sizeof(PodType) < max_size_in_bytes
1097       ? data.size() * sizeof(PodType) : max_size_in_bytes);
1098 }
1099 
1100 /// Create a new modifiable buffer that represents the given POD array.
1101 /**
1102  * @returns A mutable_buffer value equivalent to:
1103  * @code mutable_buffer(
1104  *     data.data(),
1105  *     data.size() * sizeof(PodType)); @endcode
1106  */
1107 template <typename PodType, std::size_t N>
1108 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1109     std::array<PodType, N>& data) noexcept
1110 {
1111   return mutable_buffer(data.data(), data.size() * sizeof(PodType));
1112 }
1113 
1114 /// Create a new modifiable buffer that represents the given POD array.
1115 /**
1116  * @returns A mutable_buffer value equivalent to:
1117  * @code mutable_buffer(
1118  *     data.data(),
1119  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1120  */
1121 template <typename PodType, std::size_t N>
1122 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1123     std::array<PodType, N>& data,
1124     std::size_t max_size_in_bytes) noexcept
1125 {
1126   return mutable_buffer(data.data(),
1127       data.size() * sizeof(PodType) < max_size_in_bytes
1128       ? data.size() * sizeof(PodType) : max_size_in_bytes);
1129 }
1130 
1131 /// Create a new non-modifiable buffer that represents the given POD array.
1132 /**
1133  * @returns A const_buffer value equivalent to:
1134  * @code const_buffer(
1135  *     data.data(),
1136  *     data.size() * sizeof(PodType)); @endcode
1137  */
1138 template <typename PodType, std::size_t N>
1139 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1140     std::array<const PodType, N>& data) noexcept
1141 {
1142   return const_buffer(data.data(), data.size() * sizeof(PodType));
1143 }
1144 
1145 /// Create a new non-modifiable buffer that represents the given POD array.
1146 /**
1147  * @returns A const_buffer value equivalent to:
1148  * @code const_buffer(
1149  *     data.data(),
1150  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1151  */
1152 template <typename PodType, std::size_t N>
1153 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1154     std::array<const PodType, N>& data,
1155     std::size_t max_size_in_bytes) noexcept
1156 {
1157   return const_buffer(data.data(),
1158       data.size() * sizeof(PodType) < max_size_in_bytes
1159       ? data.size() * sizeof(PodType) : max_size_in_bytes);
1160 }
1161 
1162 /// Create a new non-modifiable buffer that represents the given POD array.
1163 /**
1164  * @returns A const_buffer value equivalent to:
1165  * @code const_buffer(
1166  *     data.data(),
1167  *     data.size() * sizeof(PodType)); @endcode
1168  */
1169 template <typename PodType, std::size_t N>
1170 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1171     const std::array<PodType, N>& data) noexcept
1172 {
1173   return const_buffer(data.data(), data.size() * sizeof(PodType));
1174 }
1175 
1176 /// Create a new non-modifiable buffer that represents the given POD array.
1177 /**
1178  * @returns A const_buffer value equivalent to:
1179  * @code const_buffer(
1180  *     data.data(),
1181  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1182  */
1183 template <typename PodType, std::size_t N>
1184 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1185     const std::array<PodType, N>& data,
1186     std::size_t max_size_in_bytes) noexcept
1187 {
1188   return const_buffer(data.data(),
1189       data.size() * sizeof(PodType) < max_size_in_bytes
1190       ? data.size() * sizeof(PodType) : max_size_in_bytes);
1191 }
1192 
1193 /// Create a new modifiable buffer that represents the given POD vector.
1194 /**
1195  * @returns A mutable_buffer value equivalent to:
1196  * @code mutable_buffer(
1197  *     data.size() ? &data[0] : 0,
1198  *     data.size() * sizeof(PodType)); @endcode
1199  *
1200  * @note The buffer is invalidated by any vector operation that would also
1201  * invalidate iterators.
1202  */
1203 template <typename PodType, typename Allocator>
1204 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1205     std::vector<PodType, Allocator>& data) noexcept
1206 {
1207   return mutable_buffer(
1208       data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
1209 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1210       , detail::buffer_debug_check<
1211           typename std::vector<PodType, Allocator>::iterator
1212         >(data.begin())
1213 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1214       );
1215 }
1216 
1217 /// Create a new modifiable buffer that represents the given POD vector.
1218 /**
1219  * @returns A mutable_buffer value equivalent to:
1220  * @code mutable_buffer(
1221  *     data.size() ? &data[0] : 0,
1222  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1223  *
1224  * @note The buffer is invalidated by any vector operation that would also
1225  * invalidate iterators.
1226  */
1227 template <typename PodType, typename Allocator>
1228 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1229     std::vector<PodType, Allocator>& data,
1230     std::size_t max_size_in_bytes) noexcept
1231 {
1232   return mutable_buffer(data.size() ? &data[0] : 0,
1233       data.size() * sizeof(PodType) < max_size_in_bytes
1234       ? data.size() * sizeof(PodType) : max_size_in_bytes
1235 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1236       , detail::buffer_debug_check<
1237           typename std::vector<PodType, Allocator>::iterator
1238         >(data.begin())
1239 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1240       );
1241 }
1242 
1243 /// Create a new non-modifiable buffer that represents the given POD vector.
1244 /**
1245  * @returns A const_buffer value equivalent to:
1246  * @code const_buffer(
1247  *     data.size() ? &data[0] : 0,
1248  *     data.size() * sizeof(PodType)); @endcode
1249  *
1250  * @note The buffer is invalidated by any vector operation that would also
1251  * invalidate iterators.
1252  */
1253 template <typename PodType, typename Allocator>
1254 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1255     const std::vector<PodType, Allocator>& data) noexcept
1256 {
1257   return const_buffer(
1258       data.size() ? &data[0] : 0, data.size() * sizeof(PodType)
1259 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1260       , detail::buffer_debug_check<
1261           typename std::vector<PodType, Allocator>::const_iterator
1262         >(data.begin())
1263 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1264       );
1265 }
1266 
1267 /// Create a new non-modifiable buffer that represents the given POD vector.
1268 /**
1269  * @returns A const_buffer value equivalent to:
1270  * @code const_buffer(
1271  *     data.size() ? &data[0] : 0,
1272  *     min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode
1273  *
1274  * @note The buffer is invalidated by any vector operation that would also
1275  * invalidate iterators.
1276  */
1277 template <typename PodType, typename Allocator>
1278 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1279     const std::vector<PodType, Allocator>& data,
1280     std::size_t max_size_in_bytes) noexcept
1281 {
1282   return const_buffer(data.size() ? &data[0] : 0,
1283       data.size() * sizeof(PodType) < max_size_in_bytes
1284       ? data.size() * sizeof(PodType) : max_size_in_bytes
1285 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1286       , detail::buffer_debug_check<
1287           typename std::vector<PodType, Allocator>::const_iterator
1288         >(data.begin())
1289 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1290       );
1291 }
1292 
1293 /// Create a new modifiable buffer that represents the given string.
1294 /**
1295  * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,
1296  * data.size() * sizeof(Elem))</tt>.
1297  *
1298  * @note The buffer is invalidated by any non-const operation called on the
1299  * given string object.
1300  */
1301 template <typename Elem, typename Traits, typename Allocator>
1302 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1303     std::basic_string<Elem, Traits, Allocator>& data) noexcept
1304 {
1305   return mutable_buffer(data.size() ? &data[0] : 0,
1306       data.size() * sizeof(Elem)
1307 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1308       , detail::buffer_debug_check<
1309           typename std::basic_string<Elem, Traits, Allocator>::iterator
1310         >(data.begin())
1311 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1312       );
1313 }
1314 
1315 /// Create a new modifiable buffer that represents the given string.
1316 /**
1317  * @returns A mutable_buffer value equivalent to:
1318  * @code mutable_buffer(
1319  *     data.size() ? &data[0] : 0,
1320  *     min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
1321  *
1322  * @note The buffer is invalidated by any non-const operation called on the
1323  * given string object.
1324  */
1325 template <typename Elem, typename Traits, typename Allocator>
1326 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1327     std::basic_string<Elem, Traits, Allocator>& data,
1328     std::size_t max_size_in_bytes) noexcept
1329 {
1330   return mutable_buffer(data.size() ? &data[0] : 0,
1331       data.size() * sizeof(Elem) < max_size_in_bytes
1332       ? data.size() * sizeof(Elem) : max_size_in_bytes
1333 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1334       , detail::buffer_debug_check<
1335           typename std::basic_string<Elem, Traits, Allocator>::iterator
1336         >(data.begin())
1337 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1338       );
1339 }
1340 
1341 /// Create a new non-modifiable buffer that represents the given string.
1342 /**
1343  * @returns <tt>const_buffer(data.data(), data.size() * sizeof(Elem))</tt>.
1344  *
1345  * @note The buffer is invalidated by any non-const operation called on the
1346  * given string object.
1347  */
1348 template <typename Elem, typename Traits, typename Allocator>
1349 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1350     const std::basic_string<Elem, Traits, Allocator>& data) noexcept
1351 {
1352   return const_buffer(data.data(), data.size() * sizeof(Elem)
1353 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1354       , detail::buffer_debug_check<
1355           typename std::basic_string<Elem, Traits, Allocator>::const_iterator
1356         >(data.begin())
1357 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1358       );
1359 }
1360 
1361 /// Create a new non-modifiable buffer that represents the given string.
1362 /**
1363  * @returns A const_buffer value equivalent to:
1364  * @code const_buffer(
1365  *     data.data(),
1366  *     min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
1367  *
1368  * @note The buffer is invalidated by any non-const operation called on the
1369  * given string object.
1370  */
1371 template <typename Elem, typename Traits, typename Allocator>
1372 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1373     const std::basic_string<Elem, Traits, Allocator>& data,
1374     std::size_t max_size_in_bytes) noexcept
1375 {
1376   return const_buffer(data.data(),
1377       data.size() * sizeof(Elem) < max_size_in_bytes
1378       ? data.size() * sizeof(Elem) : max_size_in_bytes
1379 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1380       , detail::buffer_debug_check<
1381           typename std::basic_string<Elem, Traits, Allocator>::const_iterator
1382         >(data.begin())
1383 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1384       );
1385 }
1386 
1387 #if defined(BOOST_ASIO_HAS_STRING_VIEW) \
1388   || defined(GENERATING_DOCUMENTATION)
1389 
1390 /// Create a new non-modifiable buffer that represents the given string_view.
1391 /**
1392  * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,
1393  * data.size() * sizeof(Elem))</tt>.
1394  */
1395 template <typename Elem, typename Traits>
1396 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1397     basic_string_view<Elem, Traits> data) noexcept
1398 {
1399   return const_buffer(data.size() ? &data[0] : 0,
1400       data.size() * sizeof(Elem)
1401 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1402       , detail::buffer_debug_check<
1403           typename basic_string_view<Elem, Traits>::iterator
1404         >(data.begin())
1405 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1406       );
1407 }
1408 
1409 /// Create a new non-modifiable buffer that represents the given string.
1410 /**
1411  * @returns A mutable_buffer value equivalent to:
1412  * @code mutable_buffer(
1413  *     data.size() ? &data[0] : 0,
1414  *     min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode
1415  */
1416 template <typename Elem, typename Traits>
1417 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1418     basic_string_view<Elem, Traits> data,
1419     std::size_t max_size_in_bytes) noexcept
1420 {
1421   return const_buffer(data.size() ? &data[0] : 0,
1422       data.size() * sizeof(Elem) < max_size_in_bytes
1423       ? data.size() * sizeof(Elem) : max_size_in_bytes
1424 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1425       , detail::buffer_debug_check<
1426           typename basic_string_view<Elem, Traits>::iterator
1427         >(data.begin())
1428 #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING
1429       );
1430 }
1431 
1432 #endif // defined(BOOST_ASIO_HAS_STRING_VIEW)
1433        //  || defined(GENERATING_DOCUMENTATION)
1434 
1435 /// Create a new modifiable buffer from a contiguous container.
1436 /**
1437  * @returns A mutable_buffer value equivalent to:
1438  * @code mutable_buffer(
1439  *     data.size() ? &data[0] : 0,
1440  *     data.size() * sizeof(typename T::value_type)); @endcode
1441  */
1442 template <typename T>
1443 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1444     T& data,
1445     constraint_t<
1446       is_contiguous_iterator<typename T::iterator>::value,
1447       defaulted_constraint
1448     > = defaulted_constraint(),
1449     constraint_t<
1450       !is_convertible<T, const_buffer>::value,
1451       defaulted_constraint
1452     > = defaulted_constraint(),
1453     constraint_t<
1454       !is_convertible<T, mutable_buffer>::value,
1455       defaulted_constraint
1456     > = defaulted_constraint(),
1457     constraint_t<
1458       !is_const<
1459         remove_reference_t<
1460           typename std::iterator_traits<typename T::iterator>::reference
1461         >
1462       >::value,
1463       defaulted_constraint
1464     > = defaulted_constraint()) noexcept
1465 {
1466   return mutable_buffer(
1467       data.size() ? detail::to_address(data.begin()) : 0,
1468       data.size() * sizeof(typename T::value_type));
1469 }
1470 
1471 /// Create a new modifiable buffer from a contiguous container.
1472 /**
1473  * @returns A mutable_buffer value equivalent to:
1474  * @code mutable_buffer(
1475  *     data.size() ? &data[0] : 0,
1476  *     min(
1477  *       data.size() * sizeof(typename T::value_type),
1478  *       max_size_in_bytes)); @endcode
1479  */
1480 template <typename T>
1481 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1482     T& data, std::size_t max_size_in_bytes,
1483     constraint_t<
1484       is_contiguous_iterator<typename T::iterator>::value,
1485       defaulted_constraint
1486     > = defaulted_constraint(),
1487     constraint_t<
1488       !is_convertible<T, const_buffer>::value,
1489       defaulted_constraint
1490     > = defaulted_constraint(),
1491     constraint_t<
1492       !is_convertible<T, mutable_buffer>::value,
1493       defaulted_constraint
1494     > = defaulted_constraint(),
1495     constraint_t<
1496       !is_const<
1497         remove_reference_t<
1498           typename std::iterator_traits<typename T::iterator>::reference
1499         >
1500       >::value,
1501       defaulted_constraint
1502     > = defaulted_constraint()) noexcept
1503 {
1504   return mutable_buffer(
1505       data.size() ? detail::to_address(data.begin()) : 0,
1506       data.size() * sizeof(typename T::value_type) < max_size_in_bytes
1507       ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes);
1508 }
1509 
1510 /// Create a new non-modifiable buffer from a contiguous container.
1511 /**
1512  * @returns A const_buffer value equivalent to:
1513  * @code const_buffer(
1514  *     data.size() ? &data[0] : 0,
1515  *     data.size() * sizeof(typename T::value_type)); @endcode
1516  */
1517 template <typename T>
1518 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1519     T& data,
1520     constraint_t<
1521       is_contiguous_iterator<typename T::iterator>::value,
1522       defaulted_constraint
1523     > = defaulted_constraint(),
1524     constraint_t<
1525       !is_convertible<T, const_buffer>::value,
1526       defaulted_constraint
1527     > = defaulted_constraint(),
1528     constraint_t<
1529       !is_convertible<T, mutable_buffer>::value,
1530       defaulted_constraint
1531     > = defaulted_constraint(),
1532     constraint_t<
1533       is_const<
1534         remove_reference_t<
1535           typename std::iterator_traits<typename T::iterator>::reference
1536         >
1537       >::value,
1538       defaulted_constraint
1539     > = defaulted_constraint()) noexcept
1540 {
1541   return const_buffer(
1542       data.size() ? detail::to_address(data.begin()) : 0,
1543       data.size() * sizeof(typename T::value_type));
1544 }
1545 
1546 /// Create a new non-modifiable buffer from a contiguous container.
1547 /**
1548  * @returns A const_buffer value equivalent to:
1549  * @code const_buffer(
1550  *     data.size() ? &data[0] : 0,
1551  *     min(
1552  *       data.size() * sizeof(typename T::value_type),
1553  *       max_size_in_bytes)); @endcode
1554  */
1555 template <typename T>
1556 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1557     T& data, std::size_t max_size_in_bytes,
1558     constraint_t<
1559       is_contiguous_iterator<typename T::iterator>::value,
1560       defaulted_constraint
1561     > = defaulted_constraint(),
1562     constraint_t<
1563       !is_convertible<T, const_buffer>::value,
1564       defaulted_constraint
1565     > = defaulted_constraint(),
1566     constraint_t<
1567       !is_convertible<T, mutable_buffer>::value,
1568       defaulted_constraint
1569     > = defaulted_constraint(),
1570     constraint_t<
1571       is_const<
1572         remove_reference_t<
1573           typename std::iterator_traits<typename T::iterator>::reference
1574         >
1575       >::value,
1576       defaulted_constraint
1577     > = defaulted_constraint()) noexcept
1578 {
1579   return const_buffer(
1580       data.size() ? detail::to_address(data.begin()) : 0,
1581       data.size() * sizeof(typename T::value_type) < max_size_in_bytes
1582       ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes);
1583 }
1584 
1585 /// Create a new non-modifiable buffer from a contiguous container.
1586 /**
1587  * @returns A const_buffer value equivalent to:
1588  * @code const_buffer(
1589  *     data.size() ? &data[0] : 0,
1590  *     data.size() * sizeof(typename T::value_type)); @endcode
1591  */
1592 template <typename T>
1593 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1594     const T& data,
1595     constraint_t<
1596       is_contiguous_iterator<typename T::const_iterator>::value,
1597       defaulted_constraint
1598     > = defaulted_constraint(),
1599     constraint_t<
1600       !is_convertible<T, const_buffer>::value,
1601       defaulted_constraint
1602     > = defaulted_constraint(),
1603     constraint_t<
1604       !is_convertible<T, mutable_buffer>::value,
1605       defaulted_constraint
1606     > = defaulted_constraint()) noexcept
1607 {
1608   return const_buffer(
1609       data.size() ? detail::to_address(data.begin()) : 0,
1610       data.size() * sizeof(typename T::value_type));
1611 }
1612 
1613 /// Create a new non-modifiable buffer from a contiguous container.
1614 /**
1615  * @returns A const_buffer value equivalent to:
1616  * @code const_buffer(
1617  *     data.size() ? &data[0] : 0,
1618  *     min(
1619  *       data.size() * sizeof(typename T::value_type),
1620  *       max_size_in_bytes)); @endcode
1621  */
1622 template <typename T>
1623 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1624     const T& data, std::size_t max_size_in_bytes,
1625     constraint_t<
1626       is_contiguous_iterator<typename T::const_iterator>::value,
1627       defaulted_constraint
1628     > = defaulted_constraint(),
1629     constraint_t<
1630       !is_convertible<T, const_buffer>::value,
1631       defaulted_constraint
1632     > = defaulted_constraint(),
1633     constraint_t<
1634       !is_convertible<T, mutable_buffer>::value,
1635       defaulted_constraint
1636     > = defaulted_constraint()) noexcept
1637 {
1638   return const_buffer(
1639       data.size() ? detail::to_address(data.begin()) : 0,
1640       data.size() * sizeof(typename T::value_type) < max_size_in_bytes
1641       ? data.size() * sizeof(typename T::value_type) : max_size_in_bytes);
1642 }
1643 
1644 /// Create a new modifiable buffer from a span.
1645 /**
1646  * @returns <tt>mutable_buffer(span)</tt>.
1647  */
1648 template <template <typename, std::size_t> class Span,
1649     typename T, std::size_t Extent>
1650 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1651     const Span<T, Extent>& span,
1652     constraint_t<
1653       !is_const<T>::value,
1654       defaulted_constraint
1655     > = defaulted_constraint(),
1656     constraint_t<
1657       sizeof(T) == 1,
1658       defaulted_constraint
1659     > = defaulted_constraint(),
1660     constraint_t<
1661 #if defined(BOOST_ASIO_MSVC)
1662       detail::has_subspan_memfn<Span<T, Extent>>::value,
1663 #else // defined(BOOST_ASIO_MSVC)
1664       is_same<
1665         decltype(span.subspan(0, 0)),
1666         Span<T, static_cast<std::size_t>(-1)>
1667       >::value,
1668 #endif // defined(BOOST_ASIO_MSVC)
1669       defaulted_constraint
1670     > = defaulted_constraint()) noexcept
1671 {
1672   return mutable_buffer(span);
1673 }
1674 
1675 /// Create a new modifiable buffer from a span.
1676 /**
1677  * @returns A mutable_buffer value equivalent to:
1678  * @code mutable_buffer b(span);
1679  * mutable_buffer(
1680  *     b.data(),
1681  *     min(b.size(), max_size_in_bytes)); @endcode
1682  */
1683 template <template <typename, std::size_t> class Span,
1684     typename T, std::size_t Extent>
1685 BOOST_ASIO_NODISCARD inline mutable_buffer buffer(
1686     const Span<T, Extent>& span,
1687     std::size_t max_size_in_bytes,
1688     constraint_t<
1689       !is_const<T>::value,
1690       defaulted_constraint
1691     > = defaulted_constraint(),
1692     constraint_t<
1693       sizeof(T) == 1,
1694       defaulted_constraint
1695     > = defaulted_constraint(),
1696     constraint_t<
1697 #if defined(BOOST_ASIO_MSVC)
1698       detail::has_subspan_memfn<Span<T, Extent>>::value,
1699 #else // defined(BOOST_ASIO_MSVC)
1700       is_same<
1701         decltype(span.subspan(0, 0)),
1702         Span<T, static_cast<std::size_t>(-1)>
1703       >::value,
1704 #endif // defined(BOOST_ASIO_MSVC)
1705       defaulted_constraint
1706     > = defaulted_constraint()) noexcept
1707 {
1708   return buffer(mutable_buffer(span), max_size_in_bytes);
1709 }
1710 
1711 /// Create a new non-modifiable buffer from a span.
1712 /**
1713  * @returns <tt>const_buffer(span)</tt>.
1714  */
1715 template <template <typename, std::size_t> class Span,
1716     typename T, std::size_t Extent>
1717 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1718     const Span<const T, Extent>& span,
1719     constraint_t<
1720       sizeof(T) == 1,
1721       defaulted_constraint
1722     > = defaulted_constraint(),
1723     constraint_t<
1724 #if defined(BOOST_ASIO_MSVC)
1725       detail::has_subspan_memfn<Span<const T, Extent>>::value,
1726 #else // defined(BOOST_ASIO_MSVC)
1727       is_same<
1728         decltype(span.subspan(0, 0)),
1729         Span<T, static_cast<std::size_t>(-1)>
1730       >::value,
1731 #endif // defined(BOOST_ASIO_MSVC)
1732       defaulted_constraint
1733     > = defaulted_constraint()) noexcept
1734 {
1735   return const_buffer(span);
1736 }
1737 
1738 /// Create a new non-modifiable buffer from a span.
1739 /**
1740  * @returns A const_buffer value equivalent to:
1741  * @code const_buffer b1(b);
1742  * const_buffer(
1743  *     b1.data(),
1744  *     min(b1.size(), max_size_in_bytes)); @endcode
1745  */
1746 template <template <typename, std::size_t> class Span,
1747     typename T, std::size_t Extent>
1748 BOOST_ASIO_NODISCARD inline const_buffer buffer(
1749     const Span<const T, Extent>& span,
1750     std::size_t max_size_in_bytes,
1751     constraint_t<
1752       sizeof(T) == 1,
1753       defaulted_constraint
1754     > = defaulted_constraint(),
1755     constraint_t<
1756 #if defined(BOOST_ASIO_MSVC)
1757       detail::has_subspan_memfn<Span<const T, Extent>>::value,
1758 #else // defined(BOOST_ASIO_MSVC)
1759       is_same<
1760         decltype(span.subspan(0, 0)),
1761         Span<T, static_cast<std::size_t>(-1)>
1762       >::value,
1763 #endif // defined(BOOST_ASIO_MSVC)
1764       defaulted_constraint
1765     > = defaulted_constraint()) noexcept
1766 {
1767   return buffer(const_buffer(span), max_size_in_bytes);
1768 }
1769 
1770 /*@}*/
1771 
1772 /// Adapt a basic_string to the DynamicBuffer requirements.
1773 /**
1774  * Requires that <tt>sizeof(Elem) == 1</tt>.
1775  */
1776 template <typename Elem, typename Traits, typename Allocator>
1777 class dynamic_string_buffer
1778 {
1779 public:
1780   /// The type used to represent a sequence of constant buffers that refers to
1781   /// the underlying memory.
1782   typedef const_buffer const_buffers_type;
1783 
1784   /// The type used to represent a sequence of mutable buffers that refers to
1785   /// the underlying memory.
1786   typedef mutable_buffer mutable_buffers_type;
1787 
1788   /// Construct a dynamic buffer from a string.
1789   /**
1790    * @param s The string to be used as backing storage for the dynamic buffer.
1791    * The object stores a reference to the string and the user is responsible
1792    * for ensuring that the string object remains valid while the
1793    * dynamic_string_buffer object, and copies of the object, are in use.
1794    *
1795    * @b DynamicBuffer_v1: Any existing data in the string is treated as the
1796    * dynamic buffer's input sequence.
1797    *
1798    * @param maximum_size Specifies a maximum size for the buffer, in bytes.
1799    */
1800   explicit dynamic_string_buffer(std::basic_string<Elem, Traits, Allocator>& s,
1801       std::size_t maximum_size =
1802         (std::numeric_limits<std::size_t>::max)()) noexcept
1803     : string_(s),
1804 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1805       size_((std::numeric_limits<std::size_t>::max)()),
1806 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1807       max_size_(maximum_size)
1808   {
1809   }
1810 
1811   /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.
1812   dynamic_string_buffer(const dynamic_string_buffer& other) noexcept
1813     : string_(other.string_),
1814 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1815       size_(other.size_),
1816 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1817       max_size_(other.max_size_)
1818   {
1819   }
1820 
1821   /// Move construct a dynamic buffer.
1822   dynamic_string_buffer(dynamic_string_buffer&& other) noexcept
1823     : string_(other.string_),
1824 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1825       size_(other.size_),
1826 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1827       max_size_(other.max_size_)
1828   {
1829   }
1830 
1831   /// @b DynamicBuffer_v1: Get the size of the input sequence.
1832   /// @b DynamicBuffer_v2: Get the current size of the underlying memory.
1833   /**
1834    * @returns @b DynamicBuffer_v1 The current size of the input sequence.
1835    * @b DynamicBuffer_v2: The current size of the underlying string if less than
1836    * max_size(). Otherwise returns max_size().
1837    */
1838   std::size_t size() const noexcept
1839   {
1840 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1841     if (size_ != (std::numeric_limits<std::size_t>::max)())
1842       return size_;
1843 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1844     return (std::min)(string_.size(), max_size());
1845   }
1846 
1847   /// Get the maximum size of the dynamic buffer.
1848   /**
1849    * @returns The allowed maximum size of the underlying memory.
1850    */
1851   std::size_t max_size() const noexcept
1852   {
1853     return max_size_;
1854   }
1855 
1856   /// Get the maximum size that the buffer may grow to without triggering
1857   /// reallocation.
1858   /**
1859    * @returns The current capacity of the underlying string if less than
1860    * max_size(). Otherwise returns max_size().
1861    */
1862   std::size_t capacity() const noexcept
1863   {
1864     return (std::min)(string_.capacity(), max_size());
1865   }
1866 
1867 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1868   /// @b DynamicBuffer_v1: Get a list of buffers that represents the input
1869   /// sequence.
1870   /**
1871    * @returns An object of type @c const_buffers_type that satisfies
1872    * ConstBufferSequence requirements, representing the basic_string memory in
1873    * the input sequence.
1874    *
1875    * @note The returned object is invalidated by any @c dynamic_string_buffer
1876    * or @c basic_string member function that resizes or erases the string.
1877    */
1878   const_buffers_type data() const noexcept
1879   {
1880     return const_buffers_type(boost::asio::buffer(string_, size_));
1881   }
1882 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1883 
1884   /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
1885   /// underlying memory.
1886   /**
1887    * @param pos Position of the first byte to represent in the buffer sequence
1888    *
1889    * @param n The number of bytes to return in the buffer sequence. If the
1890    * underlying memory is shorter, the buffer sequence represents as many bytes
1891    * as are available.
1892    *
1893    * @returns An object of type @c mutable_buffers_type that satisfies
1894    * MutableBufferSequence requirements, representing the basic_string memory.
1895    *
1896    * @note The returned object is invalidated by any @c dynamic_string_buffer
1897    * or @c basic_string member function that resizes or erases the string.
1898    */
1899   mutable_buffers_type data(std::size_t pos, std::size_t n) noexcept
1900   {
1901     return mutable_buffers_type(boost::asio::buffer(
1902           boost::asio::buffer(string_, max_size_) + pos, n));
1903   }
1904 
1905   /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
1906   /// underlying memory.
1907   /**
1908    * @param pos Position of the first byte to represent in the buffer sequence
1909    *
1910    * @param n The number of bytes to return in the buffer sequence. If the
1911    * underlying memory is shorter, the buffer sequence represents as many bytes
1912    * as are available.
1913    *
1914    * @note The returned object is invalidated by any @c dynamic_string_buffer
1915    * or @c basic_string member function that resizes or erases the string.
1916    */
1917   const_buffers_type data(std::size_t pos,
1918       std::size_t n) const noexcept
1919   {
1920     return const_buffers_type(boost::asio::buffer(
1921           boost::asio::buffer(string_, max_size_) + pos, n));
1922   }
1923 
1924 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1925   /// @b DynamicBuffer_v1: Get a list of buffers that represents the output
1926   /// sequence, with the given size.
1927   /**
1928    * Ensures that the output sequence can accommodate @c n bytes, resizing the
1929    * basic_string object as necessary.
1930    *
1931    * @returns An object of type @c mutable_buffers_type that satisfies
1932    * MutableBufferSequence requirements, representing basic_string memory
1933    * at the start of the output sequence of size @c n.
1934    *
1935    * @throws std::length_error If <tt>size() + n > max_size()</tt>.
1936    *
1937    * @note The returned object is invalidated by any @c dynamic_string_buffer
1938    * or @c basic_string member function that modifies the input sequence or
1939    * output sequence.
1940    */
1941   mutable_buffers_type prepare(std::size_t n)
1942   {
1943     if (size() > max_size() || max_size() - size() < n)
1944     {
1945       std::length_error ex("dynamic_string_buffer too long");
1946       boost::asio::detail::throw_exception(ex);
1947     }
1948 
1949     if (size_ == (std::numeric_limits<std::size_t>::max)())
1950       size_ = string_.size(); // Enable v1 behaviour.
1951 
1952     string_.resize(size_ + n);
1953 
1954     return boost::asio::buffer(boost::asio::buffer(string_) + size_, n);
1955   }
1956 
1957   /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input
1958   /// sequence.
1959   /**
1960    * @param n The number of bytes to append from the start of the output
1961    * sequence to the end of the input sequence. The remainder of the output
1962    * sequence is discarded.
1963    *
1964    * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
1965    * no intervening operations that modify the input or output sequence.
1966    *
1967    * @note If @c n is greater than the size of the output sequence, the entire
1968    * output sequence is moved to the input sequence and no error is issued.
1969    */
1970   void commit(std::size_t n)
1971   {
1972     size_ += (std::min)(n, string_.size() - size_);
1973     string_.resize(size_);
1974   }
1975 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1976 
1977   /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of
1978   /// bytes.
1979   /**
1980    * Resizes the string to accommodate an additional @c n bytes at the end.
1981    *
1982    * @throws std::length_error If <tt>size() + n > max_size()</tt>.
1983    */
1984   void grow(std::size_t n)
1985   {
1986     if (size() > max_size() || max_size() - size() < n)
1987     {
1988       std::length_error ex("dynamic_string_buffer too long");
1989       boost::asio::detail::throw_exception(ex);
1990     }
1991 
1992     string_.resize(size() + n);
1993   }
1994 
1995   /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number
1996   /// of bytes.
1997   /**
1998    * Erases @c n bytes from the end of the string by resizing the basic_string
1999    * object. If @c n is greater than the current size of the string, the string
2000    * is emptied.
2001    */
2002   void shrink(std::size_t n)
2003   {
2004     string_.resize(n > size() ? 0 : size() - n);
2005   }
2006 
2007   /// @b DynamicBuffer_v1: Remove characters from the input sequence.
2008   /// @b DynamicBuffer_v2: Consume the specified number of bytes from the
2009   /// beginning of the underlying memory.
2010   /**
2011    * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the
2012    * input sequence. @note If @c n is greater than the size of the input
2013    * sequence, the entire input sequence is consumed and no error is issued.
2014    *
2015    * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the string.
2016    * If @c n is greater than the current size of the string, the string is
2017    * emptied.
2018    */
2019   void consume(std::size_t n)
2020   {
2021 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2022     if (size_ != (std::numeric_limits<std::size_t>::max)())
2023     {
2024       std::size_t consume_length = (std::min)(n, size_);
2025       string_.erase(0, consume_length);
2026       size_ -= consume_length;
2027       return;
2028     }
2029 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2030     string_.erase(0, n);
2031   }
2032 
2033 private:
2034   std::basic_string<Elem, Traits, Allocator>& string_;
2035 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2036   std::size_t size_;
2037 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2038   const std::size_t max_size_;
2039 };
2040 
2041 /// Adapt a vector to the DynamicBuffer requirements.
2042 /**
2043  * Requires that <tt>sizeof(Elem) == 1</tt>.
2044  */
2045 template <typename Elem, typename Allocator>
2046 class dynamic_vector_buffer
2047 {
2048 public:
2049   /// The type used to represent a sequence of constant buffers that refers to
2050   /// the underlying memory.
2051   typedef const_buffer const_buffers_type;
2052 
2053   /// The type used to represent a sequence of mutable buffers that refers to
2054   /// the underlying memory.
2055   typedef mutable_buffer mutable_buffers_type;
2056 
2057   /// Construct a dynamic buffer from a vector.
2058   /**
2059    * @param v The vector to be used as backing storage for the dynamic buffer.
2060    * The object stores a reference to the vector and the user is responsible
2061    * for ensuring that the vector object remains valid while the
2062    * dynamic_vector_buffer object, and copies of the object, are in use.
2063    *
2064    * @param maximum_size Specifies a maximum size for the buffer, in bytes.
2065    */
2066   explicit dynamic_vector_buffer(std::vector<Elem, Allocator>& v,
2067       std::size_t maximum_size =
2068         (std::numeric_limits<std::size_t>::max)()) noexcept
2069     : vector_(v),
2070 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2071       size_((std::numeric_limits<std::size_t>::max)()),
2072 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2073       max_size_(maximum_size)
2074   {
2075   }
2076 
2077   /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.
2078   dynamic_vector_buffer(const dynamic_vector_buffer& other) noexcept
2079     : vector_(other.vector_),
2080 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2081       size_(other.size_),
2082 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2083       max_size_(other.max_size_)
2084   {
2085   }
2086 
2087   /// Move construct a dynamic buffer.
2088   dynamic_vector_buffer(dynamic_vector_buffer&& other) noexcept
2089     : vector_(other.vector_),
2090 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2091       size_(other.size_),
2092 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2093       max_size_(other.max_size_)
2094   {
2095   }
2096 
2097   /// @b DynamicBuffer_v1: Get the size of the input sequence.
2098   /// @b DynamicBuffer_v2: Get the current size of the underlying memory.
2099   /**
2100    * @returns @b DynamicBuffer_v1 The current size of the input sequence.
2101    * @b DynamicBuffer_v2: The current size of the underlying vector if less than
2102    * max_size(). Otherwise returns max_size().
2103    */
2104   std::size_t size() const noexcept
2105   {
2106 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2107     if (size_ != (std::numeric_limits<std::size_t>::max)())
2108       return size_;
2109 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2110     return (std::min)(vector_.size(), max_size());
2111   }
2112 
2113   /// Get the maximum size of the dynamic buffer.
2114   /**
2115    * @returns @b DynamicBuffer_v1: The allowed maximum of the sum of the sizes
2116    * of the input sequence and output sequence. @b DynamicBuffer_v2: The allowed
2117    * maximum size of the underlying memory.
2118    */
2119   std::size_t max_size() const noexcept
2120   {
2121     return max_size_;
2122   }
2123 
2124   /// Get the maximum size that the buffer may grow to without triggering
2125   /// reallocation.
2126   /**
2127    * @returns @b DynamicBuffer_v1: The current total capacity of the buffer,
2128    * i.e. for both the input sequence and output sequence. @b DynamicBuffer_v2:
2129    * The current capacity of the underlying vector if less than max_size().
2130    * Otherwise returns max_size().
2131    */
2132   std::size_t capacity() const noexcept
2133   {
2134     return (std::min)(vector_.capacity(), max_size());
2135   }
2136 
2137 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2138   /// @b DynamicBuffer_v1: Get a list of buffers that represents the input
2139   /// sequence.
2140   /**
2141    * @returns An object of type @c const_buffers_type that satisfies
2142    * ConstBufferSequence requirements, representing the vector memory in the
2143    * input sequence.
2144    *
2145    * @note The returned object is invalidated by any @c dynamic_vector_buffer
2146    * or @c vector member function that modifies the input sequence or output
2147    * sequence.
2148    */
2149   const_buffers_type data() const noexcept
2150   {
2151     return const_buffers_type(boost::asio::buffer(vector_, size_));
2152   }
2153 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2154 
2155   /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
2156   /// underlying memory.
2157   /**
2158    * @param pos Position of the first byte to represent in the buffer sequence
2159    *
2160    * @param n The number of bytes to return in the buffer sequence. If the
2161    * underlying memory is shorter, the buffer sequence represents as many bytes
2162    * as are available.
2163    *
2164    * @returns An object of type @c mutable_buffers_type that satisfies
2165    * MutableBufferSequence requirements, representing the vector memory.
2166    *
2167    * @note The returned object is invalidated by any @c dynamic_vector_buffer
2168    * or @c vector member function that resizes or erases the vector.
2169    */
2170   mutable_buffers_type data(std::size_t pos, std::size_t n) noexcept
2171   {
2172     return mutable_buffers_type(boost::asio::buffer(
2173           boost::asio::buffer(vector_, max_size_) + pos, n));
2174   }
2175 
2176   /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the
2177   /// underlying memory.
2178   /**
2179    * @param pos Position of the first byte to represent in the buffer sequence
2180    *
2181    * @param n The number of bytes to return in the buffer sequence. If the
2182    * underlying memory is shorter, the buffer sequence represents as many bytes
2183    * as are available.
2184    *
2185    * @note The returned object is invalidated by any @c dynamic_vector_buffer
2186    * or @c vector member function that resizes or erases the vector.
2187    */
2188   const_buffers_type data(std::size_t pos,
2189       std::size_t n) const noexcept
2190   {
2191     return const_buffers_type(boost::asio::buffer(
2192           boost::asio::buffer(vector_, max_size_) + pos, n));
2193   }
2194 
2195 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2196   /// @b DynamicBuffer_v1: Get a list of buffers that represents the output
2197   /// sequence, with the given size.
2198   /**
2199    * Ensures that the output sequence can accommodate @c n bytes, resizing the
2200    * vector object as necessary.
2201    *
2202    * @returns An object of type @c mutable_buffers_type that satisfies
2203    * MutableBufferSequence requirements, representing vector memory at the
2204    * start of the output sequence of size @c n.
2205    *
2206    * @throws std::length_error If <tt>size() + n > max_size()</tt>.
2207    *
2208    * @note The returned object is invalidated by any @c dynamic_vector_buffer
2209    * or @c vector member function that modifies the input sequence or output
2210    * sequence.
2211    */
2212   mutable_buffers_type prepare(std::size_t n)
2213   {
2214     if (size () > max_size() || max_size() - size() < n)
2215     {
2216       std::length_error ex("dynamic_vector_buffer too long");
2217       boost::asio::detail::throw_exception(ex);
2218     }
2219 
2220     if (size_ == (std::numeric_limits<std::size_t>::max)())
2221       size_ = vector_.size(); // Enable v1 behaviour.
2222 
2223     vector_.resize(size_ + n);
2224 
2225     return boost::asio::buffer(boost::asio::buffer(vector_) + size_, n);
2226   }
2227 
2228   /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input
2229   /// sequence.
2230   /**
2231    * @param n The number of bytes to append from the start of the output
2232    * sequence to the end of the input sequence. The remainder of the output
2233    * sequence is discarded.
2234    *
2235    * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
2236    * no intervening operations that modify the input or output sequence.
2237    *
2238    * @note If @c n is greater than the size of the output sequence, the entire
2239    * output sequence is moved to the input sequence and no error is issued.
2240    */
2241   void commit(std::size_t n)
2242   {
2243     size_ += (std::min)(n, vector_.size() - size_);
2244     vector_.resize(size_);
2245   }
2246 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2247 
2248   /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of
2249   /// bytes.
2250   /**
2251    * Resizes the vector to accommodate an additional @c n bytes at the end.
2252    *
2253    * @throws std::length_error If <tt>size() + n > max_size()</tt>.
2254    */
2255   void grow(std::size_t n)
2256   {
2257     if (size() > max_size() || max_size() - size() < n)
2258     {
2259       std::length_error ex("dynamic_vector_buffer too long");
2260       boost::asio::detail::throw_exception(ex);
2261     }
2262 
2263     vector_.resize(size() + n);
2264   }
2265 
2266   /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number
2267   /// of bytes.
2268   /**
2269    * Erases @c n bytes from the end of the vector by resizing the vector
2270    * object. If @c n is greater than the current size of the vector, the vector
2271    * is emptied.
2272    */
2273   void shrink(std::size_t n)
2274   {
2275     vector_.resize(n > size() ? 0 : size() - n);
2276   }
2277 
2278   /// @b DynamicBuffer_v1: Remove characters from the input sequence.
2279   /// @b DynamicBuffer_v2: Consume the specified number of bytes from the
2280   /// beginning of the underlying memory.
2281   /**
2282    * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the
2283    * input sequence. @note If @c n is greater than the size of the input
2284    * sequence, the entire input sequence is consumed and no error is issued.
2285    *
2286    * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the vector.
2287    * If @c n is greater than the current size of the vector, the vector is
2288    * emptied.
2289    */
2290   void consume(std::size_t n)
2291   {
2292 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2293     if (size_ != (std::numeric_limits<std::size_t>::max)())
2294     {
2295       std::size_t consume_length = (std::min)(n, size_);
2296       vector_.erase(vector_.begin(), vector_.begin() + consume_length);
2297       size_ -= consume_length;
2298       return;
2299     }
2300 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2301     vector_.erase(vector_.begin(), vector_.begin() + (std::min)(size(), n));
2302   }
2303 
2304 private:
2305   std::vector<Elem, Allocator>& vector_;
2306 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2307   std::size_t size_;
2308 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2309   const std::size_t max_size_;
2310 };
2311 
2312 /** @defgroup dynamic_buffer boost::asio::dynamic_buffer
2313  *
2314  * @brief The boost::asio::dynamic_buffer function is used to create a
2315  * dynamically resized buffer from a @c std::basic_string or @c std::vector.
2316  */
2317 /*@{*/
2318 
2319 /// Create a new dynamic buffer that represents the given string.
2320 /**
2321  * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>.
2322  */
2323 template <typename Elem, typename Traits, typename Allocator>
2324 BOOST_ASIO_NODISCARD inline
2325 dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(
2326     std::basic_string<Elem, Traits, Allocator>& data) noexcept
2327 {
2328   return dynamic_string_buffer<Elem, Traits, Allocator>(data);
2329 }
2330 
2331 /// Create a new dynamic buffer that represents the given string.
2332 /**
2333  * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data,
2334  * max_size)</tt>.
2335  */
2336 template <typename Elem, typename Traits, typename Allocator>
2337 BOOST_ASIO_NODISCARD inline
2338 dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(
2339     std::basic_string<Elem, Traits, Allocator>& data,
2340     std::size_t max_size) noexcept
2341 {
2342   return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size);
2343 }
2344 
2345 /// Create a new dynamic buffer that represents the given vector.
2346 /**
2347  * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>.
2348  */
2349 template <typename Elem, typename Allocator>
2350 BOOST_ASIO_NODISCARD inline
2351 dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(
2352     std::vector<Elem, Allocator>& data) noexcept
2353 {
2354   return dynamic_vector_buffer<Elem, Allocator>(data);
2355 }
2356 
2357 /// Create a new dynamic buffer that represents the given vector.
2358 /**
2359  * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>.
2360  */
2361 template <typename Elem, typename Allocator>
2362 BOOST_ASIO_NODISCARD inline
2363 dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(
2364     std::vector<Elem, Allocator>& data,
2365     std::size_t max_size) noexcept
2366 {
2367   return dynamic_vector_buffer<Elem, Allocator>(data, max_size);
2368 }
2369 
2370 /*@}*/
2371 
2372 /** @defgroup buffer_copy boost::asio::buffer_copy
2373  *
2374  * @brief The boost::asio::buffer_copy function is used to copy bytes from a
2375  * source buffer (or buffer sequence) to a target buffer (or buffer sequence).
2376  *
2377  * The @c buffer_copy function is available in two forms:
2378  *
2379  * @li A 2-argument form: @c buffer_copy(target, source)
2380  *
2381  * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy)
2382  *
2383  * Both forms return the number of bytes actually copied. The number of bytes
2384  * copied is the lesser of:
2385  *
2386  * @li @c buffer_size(target)
2387  *
2388  * @li @c buffer_size(source)
2389  *
2390  * @li @c If specified, @c max_bytes_to_copy.
2391  *
2392  * This prevents buffer overflow, regardless of the buffer sizes used in the
2393  * copy operation.
2394  *
2395  * Note that @ref buffer_copy is implemented in terms of @c memcpy, and
2396  * consequently it cannot be used to copy between overlapping memory regions.
2397  */
2398 /*@{*/
2399 
2400 namespace detail {
2401 
2402 inline std::size_t buffer_copy_1(const mutable_buffer& target,
2403     const const_buffer& source)
2404 {
2405   using namespace std; // For memcpy.
2406   std::size_t target_size = target.size();
2407   std::size_t source_size = source.size();
2408   std::size_t n = target_size < source_size ? target_size : source_size;
2409   if (n > 0)
2410     memcpy(target.data(), source.data(), n);
2411   return n;
2412 }
2413 
2414 template <typename TargetIterator, typename SourceIterator>
2415 inline std::size_t buffer_copy(one_buffer, one_buffer,
2416     TargetIterator target_begin, TargetIterator,
2417     SourceIterator source_begin, SourceIterator) noexcept
2418 {
2419   return (buffer_copy_1)(*target_begin, *source_begin);
2420 }
2421 
2422 template <typename TargetIterator, typename SourceIterator>
2423 inline std::size_t buffer_copy(one_buffer, one_buffer,
2424     TargetIterator target_begin, TargetIterator,
2425     SourceIterator source_begin, SourceIterator,
2426     std::size_t max_bytes_to_copy) noexcept
2427 {
2428   return (buffer_copy_1)(*target_begin,
2429       boost::asio::buffer(*source_begin, max_bytes_to_copy));
2430 }
2431 
2432 template <typename TargetIterator, typename SourceIterator>
2433 std::size_t buffer_copy(one_buffer, multiple_buffers,
2434     TargetIterator target_begin, TargetIterator,
2435     SourceIterator source_begin, SourceIterator source_end,
2436     std::size_t max_bytes_to_copy
2437       = (std::numeric_limits<std::size_t>::max)()) noexcept
2438 {
2439   std::size_t total_bytes_copied = 0;
2440   SourceIterator source_iter = source_begin;
2441 
2442   for (mutable_buffer target_buffer(
2443         boost::asio::buffer(*target_begin, max_bytes_to_copy));
2444       target_buffer.size() && source_iter != source_end; ++source_iter)
2445   {
2446     const_buffer source_buffer(*source_iter);
2447     std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);
2448     total_bytes_copied += bytes_copied;
2449     target_buffer += bytes_copied;
2450   }
2451 
2452   return total_bytes_copied;
2453 }
2454 
2455 template <typename TargetIterator, typename SourceIterator>
2456 std::size_t buffer_copy(multiple_buffers, one_buffer,
2457     TargetIterator target_begin, TargetIterator target_end,
2458     SourceIterator source_begin, SourceIterator,
2459     std::size_t max_bytes_to_copy
2460       = (std::numeric_limits<std::size_t>::max)()) noexcept
2461 {
2462   std::size_t total_bytes_copied = 0;
2463   TargetIterator target_iter = target_begin;
2464 
2465   for (const_buffer source_buffer(
2466         boost::asio::buffer(*source_begin, max_bytes_to_copy));
2467       source_buffer.size() && target_iter != target_end; ++target_iter)
2468   {
2469     mutable_buffer target_buffer(*target_iter);
2470     std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);
2471     total_bytes_copied += bytes_copied;
2472     source_buffer += bytes_copied;
2473   }
2474 
2475   return total_bytes_copied;
2476 }
2477 
2478 template <typename TargetIterator, typename SourceIterator>
2479 std::size_t buffer_copy(multiple_buffers, multiple_buffers,
2480     TargetIterator target_begin, TargetIterator target_end,
2481     SourceIterator source_begin, SourceIterator source_end) noexcept
2482 {
2483   std::size_t total_bytes_copied = 0;
2484 
2485   TargetIterator target_iter = target_begin;
2486   std::size_t target_buffer_offset = 0;
2487 
2488   SourceIterator source_iter = source_begin;
2489   std::size_t source_buffer_offset = 0;
2490 
2491   while (target_iter != target_end && source_iter != source_end)
2492   {
2493     mutable_buffer target_buffer =
2494       mutable_buffer(*target_iter) + target_buffer_offset;
2495 
2496     const_buffer source_buffer =
2497       const_buffer(*source_iter) + source_buffer_offset;
2498 
2499     std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);
2500     total_bytes_copied += bytes_copied;
2501 
2502     if (bytes_copied == target_buffer.size())
2503     {
2504       ++target_iter;
2505       target_buffer_offset = 0;
2506     }
2507     else
2508       target_buffer_offset += bytes_copied;
2509 
2510     if (bytes_copied == source_buffer.size())
2511     {
2512       ++source_iter;
2513       source_buffer_offset = 0;
2514     }
2515     else
2516       source_buffer_offset += bytes_copied;
2517   }
2518 
2519   return total_bytes_copied;
2520 }
2521 
2522 template <typename TargetIterator, typename SourceIterator>
2523 std::size_t buffer_copy(multiple_buffers, multiple_buffers,
2524     TargetIterator target_begin, TargetIterator target_end,
2525     SourceIterator source_begin, SourceIterator source_end,
2526     std::size_t max_bytes_to_copy) noexcept
2527 {
2528   std::size_t total_bytes_copied = 0;
2529 
2530   TargetIterator target_iter = target_begin;
2531   std::size_t target_buffer_offset = 0;
2532 
2533   SourceIterator source_iter = source_begin;
2534   std::size_t source_buffer_offset = 0;
2535 
2536   while (total_bytes_copied != max_bytes_to_copy
2537       && target_iter != target_end && source_iter != source_end)
2538   {
2539     mutable_buffer target_buffer =
2540       mutable_buffer(*target_iter) + target_buffer_offset;
2541 
2542     const_buffer source_buffer =
2543       const_buffer(*source_iter) + source_buffer_offset;
2544 
2545     std::size_t bytes_copied = (buffer_copy_1)(
2546         target_buffer, boost::asio::buffer(source_buffer,
2547           max_bytes_to_copy - total_bytes_copied));
2548     total_bytes_copied += bytes_copied;
2549 
2550     if (bytes_copied == target_buffer.size())
2551     {
2552       ++target_iter;
2553       target_buffer_offset = 0;
2554     }
2555     else
2556       target_buffer_offset += bytes_copied;
2557 
2558     if (bytes_copied == source_buffer.size())
2559     {
2560       ++source_iter;
2561       source_buffer_offset = 0;
2562     }
2563     else
2564       source_buffer_offset += bytes_copied;
2565   }
2566 
2567   return total_bytes_copied;
2568 }
2569 
2570 } // namespace detail
2571 
2572 /// Copies bytes from a source buffer sequence to a target buffer sequence.
2573 /**
2574  * @param target A modifiable buffer sequence representing the memory regions to
2575  * which the bytes will be copied.
2576  *
2577  * @param source A non-modifiable buffer sequence representing the memory
2578  * regions from which the bytes will be copied.
2579  *
2580  * @returns The number of bytes copied.
2581  *
2582  * @note The number of bytes copied is the lesser of:
2583  *
2584  * @li @c buffer_size(target)
2585  *
2586  * @li @c buffer_size(source)
2587  *
2588  * This function is implemented in terms of @c memcpy, and consequently it
2589  * cannot be used to copy between overlapping memory regions.
2590  */
2591 template <typename MutableBufferSequence, typename ConstBufferSequence>
2592 inline std::size_t buffer_copy(const MutableBufferSequence& target,
2593     const ConstBufferSequence& source) noexcept
2594 {
2595   return detail::buffer_copy(
2596       detail::buffer_sequence_cardinality<MutableBufferSequence>(),
2597       detail::buffer_sequence_cardinality<ConstBufferSequence>(),
2598       boost::asio::buffer_sequence_begin(target),
2599       boost::asio::buffer_sequence_end(target),
2600       boost::asio::buffer_sequence_begin(source),
2601       boost::asio::buffer_sequence_end(source));
2602 }
2603 
2604 /// Copies a limited number of bytes from a source buffer sequence to a target
2605 /// buffer sequence.
2606 /**
2607  * @param target A modifiable buffer sequence representing the memory regions to
2608  * which the bytes will be copied.
2609  *
2610  * @param source A non-modifiable buffer sequence representing the memory
2611  * regions from which the bytes will be copied.
2612  *
2613  * @param max_bytes_to_copy The maximum number of bytes to be copied.
2614  *
2615  * @returns The number of bytes copied.
2616  *
2617  * @note The number of bytes copied is the lesser of:
2618  *
2619  * @li @c buffer_size(target)
2620  *
2621  * @li @c buffer_size(source)
2622  *
2623  * @li @c max_bytes_to_copy
2624  *
2625  * This function is implemented in terms of @c memcpy, and consequently it
2626  * cannot be used to copy between overlapping memory regions.
2627  */
2628 template <typename MutableBufferSequence, typename ConstBufferSequence>
2629 inline std::size_t buffer_copy(const MutableBufferSequence& target,
2630     const ConstBufferSequence& source,
2631     std::size_t max_bytes_to_copy) noexcept
2632 {
2633   return detail::buffer_copy(
2634       detail::buffer_sequence_cardinality<MutableBufferSequence>(),
2635       detail::buffer_sequence_cardinality<ConstBufferSequence>(),
2636       boost::asio::buffer_sequence_begin(target),
2637       boost::asio::buffer_sequence_end(target),
2638       boost::asio::buffer_sequence_begin(source),
2639       boost::asio::buffer_sequence_end(source), max_bytes_to_copy);
2640 }
2641 
2642 /*@}*/
2643 
2644 } // namespace asio
2645 } // namespace boost
2646 
2647 #include <boost/asio/detail/pop_options.hpp>
2648 #include <boost/asio/detail/is_buffer_sequence.hpp>
2649 #include <boost/asio/detail/push_options.hpp>
2650 
2651 namespace boost {
2652 namespace asio {
2653 
2654 /// Trait to determine whether a type satisfies the MutableBufferSequence
2655 /// requirements.
2656 template <typename T>
2657 struct is_mutable_buffer_sequence
2658 #if defined(GENERATING_DOCUMENTATION)
2659   : integral_constant<bool, automatically_determined>
2660 #else // defined(GENERATING_DOCUMENTATION)
2661   : boost::asio::detail::is_buffer_sequence<T, mutable_buffer>
2662 #endif // defined(GENERATING_DOCUMENTATION)
2663 {
2664 };
2665 
2666 /// Trait to determine whether a type satisfies the ConstBufferSequence
2667 /// requirements.
2668 template <typename T>
2669 struct is_const_buffer_sequence
2670 #if defined(GENERATING_DOCUMENTATION)
2671   : integral_constant<bool, automatically_determined>
2672 #else // defined(GENERATING_DOCUMENTATION)
2673   : boost::asio::detail::is_buffer_sequence<T, const_buffer>
2674 #endif // defined(GENERATING_DOCUMENTATION)
2675 {
2676 };
2677 
2678 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2679 /// Trait to determine whether a type satisfies the DynamicBuffer_v1
2680 /// requirements.
2681 template <typename T>
2682 struct is_dynamic_buffer_v1
2683 #if defined(GENERATING_DOCUMENTATION)
2684   : integral_constant<bool, automatically_determined>
2685 #else // defined(GENERATING_DOCUMENTATION)
2686   : boost::asio::detail::is_dynamic_buffer_v1<T>
2687 #endif // defined(GENERATING_DOCUMENTATION)
2688 {
2689 };
2690 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2691 
2692 /// Trait to determine whether a type satisfies the DynamicBuffer_v2
2693 /// requirements.
2694 template <typename T>
2695 struct is_dynamic_buffer_v2
2696 #if defined(GENERATING_DOCUMENTATION)
2697   : integral_constant<bool, automatically_determined>
2698 #else // defined(GENERATING_DOCUMENTATION)
2699   : boost::asio::detail::is_dynamic_buffer_v2<T>
2700 #endif // defined(GENERATING_DOCUMENTATION)
2701 {
2702 };
2703 
2704 /// Trait to determine whether a type satisfies the DynamicBuffer requirements.
2705 /**
2706  * If @c BOOST_ASIO_NO_DYNAMIC_BUFFER_V1 is not defined, determines whether the
2707  * type satisfies the DynamicBuffer_v1 requirements. Otherwise, if @c
2708  * BOOST_ASIO_NO_DYNAMIC_BUFFER_V1 is defined, determines whether the type
2709  * satisfies the DynamicBuffer_v2 requirements.
2710  */
2711 template <typename T>
2712 struct is_dynamic_buffer
2713 #if defined(GENERATING_DOCUMENTATION)
2714   : integral_constant<bool, automatically_determined>
2715 #elif defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2716   : boost::asio::is_dynamic_buffer_v2<T>
2717 #else // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2718   : boost::asio::is_dynamic_buffer_v1<T>
2719 #endif // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
2720 {
2721 };
2722 
2723 namespace buffer_literals {
2724 namespace detail {
2725 
2726 template <char... Chars>
2727 struct chars {};
2728 
2729 template <unsigned char... Bytes>
2730 struct bytes {};
2731 
2732 // Literal processor that converts binary literals to an array of bytes.
2733 
2734 template <typename Bytes, char... Chars>
2735 struct bin_literal;
2736 
2737 template <unsigned char... Bytes>
2738 struct bin_literal<bytes<Bytes...>>
2739 {
2740   static const std::size_t size = sizeof...(Bytes);
2741   static const unsigned char data[sizeof...(Bytes)];
2742 };
2743 
2744 template <unsigned char... Bytes>
2745 const unsigned char bin_literal<bytes<Bytes...>>::data[sizeof...(Bytes)]
2746   = { Bytes... };
2747 
2748 template <unsigned char... Bytes, char Bit7, char Bit6, char Bit5,
2749     char Bit4, char Bit3, char Bit2, char Bit1, char Bit0, char... Chars>
2750 struct bin_literal<bytes<Bytes...>, Bit7, Bit6,
2751     Bit5, Bit4, Bit3, Bit2, Bit1, Bit0, Chars...> :
2752   bin_literal<
2753     bytes<Bytes...,
2754       static_cast<unsigned char>(
2755       (Bit7 == '1' ? 0x80 : 0) |
2756         (Bit6 == '1' ? 0x40 : 0) |
2757         (Bit5 == '1' ? 0x20 : 0) |
2758         (Bit4 == '1' ? 0x10 : 0) |
2759         (Bit3 == '1' ? 0x08 : 0) |
2760         (Bit2 == '1' ? 0x04 : 0) |
2761         (Bit1 == '1' ? 0x02 : 0) |
2762         (Bit0 == '1' ? 0x01 : 0))
2763     >, Chars...> {};
2764 
2765 template <unsigned char... Bytes, char... Chars>
2766 struct bin_literal<bytes<Bytes...>, Chars...>
2767 {
2768   static_assert(sizeof...(Chars) == 0,
2769       "number of digits in a binary buffer literal must be a multiple of 8");
2770 
2771   static const std::size_t size = 0;
2772   static const unsigned char data[1];
2773 };
2774 
2775 template <unsigned char... Bytes, char... Chars>
2776 const unsigned char bin_literal<bytes<Bytes...>, Chars...>::data[1] = {};
2777 
2778 // Literal processor that converts hexadecimal literals to an array of bytes.
2779 
2780 template <typename Bytes, char... Chars>
2781 struct hex_literal;
2782 
2783 template <unsigned char... Bytes>
2784 struct hex_literal<bytes<Bytes...>>
2785 {
2786   static const std::size_t size = sizeof...(Bytes);
2787   static const unsigned char data[sizeof...(Bytes)];
2788 };
2789 
2790 template <unsigned char... Bytes>
2791 const unsigned char hex_literal<bytes<Bytes...>>::data[sizeof...(Bytes)]
2792   = { Bytes... };
2793 
2794 template <unsigned char... Bytes, char Hi, char Lo, char... Chars>
2795 struct hex_literal<bytes<Bytes...>, Hi, Lo, Chars...> :
2796   hex_literal<
2797     bytes<Bytes...,
2798       static_cast<unsigned char>(
2799         Lo >= 'A' && Lo <= 'F' ? Lo - 'A' + 10 :
2800           (Lo >= 'a' && Lo <= 'f' ? Lo - 'a' + 10 : Lo - '0')) |
2801       ((static_cast<unsigned char>(
2802         Hi >= 'A' && Hi <= 'F' ? Hi - 'A' + 10 :
2803           (Hi >= 'a' && Hi <= 'f' ? Hi - 'a' + 10 : Hi - '0'))) << 4)
2804     >, Chars...> {};
2805 
2806 template <unsigned char... Bytes, char Char>
2807 struct hex_literal<bytes<Bytes...>, Char>
2808 {
2809   static_assert(!Char,
2810       "a hexadecimal buffer literal must have an even number of digits");
2811 
2812   static const std::size_t size = 0;
2813   static const unsigned char data[1];
2814 };
2815 
2816 template <unsigned char... Bytes, char Char>
2817 const unsigned char hex_literal<bytes<Bytes...>, Char>::data[1] = {};
2818 
2819 // Helper template that removes digit separators and then passes the cleaned
2820 // variadic pack of characters to the literal processor.
2821 
2822 template <template <typename, char...> class Literal,
2823     typename Clean, char... Raw>
2824 struct remove_separators;
2825 
2826 template <template <typename, char...> class Literal,
2827     char... Clean, char... Raw>
2828 struct remove_separators<Literal, chars<Clean...>, '\'', Raw...> :
2829   remove_separators<Literal, chars<Clean...>, Raw...> {};
2830 
2831 template <template <typename, char...> class Literal,
2832     char... Clean, char C, char... Raw>
2833 struct remove_separators<Literal, chars<Clean...>, C, Raw...> :
2834   remove_separators<Literal, chars<Clean..., C>, Raw...> {};
2835 
2836 template <template <typename, char...> class Literal, char... Clean>
2837 struct remove_separators<Literal, chars<Clean...>> :
2838   Literal<bytes<>, Clean...> {};
2839 
2840 // Helper template to determine the literal type based on the prefix.
2841 
2842 template <char... Chars>
2843 struct literal;
2844 
2845 template <char... Chars>
2846 struct literal<'0', 'b', Chars...> :
2847   remove_separators<bin_literal, chars<>, Chars...>{};
2848 
2849 template <char... Chars>
2850 struct literal<'0', 'B', Chars...> :
2851   remove_separators<bin_literal, chars<>, Chars...>{};
2852 
2853 template <char... Chars>
2854 struct literal<'0', 'x', Chars...> :
2855   remove_separators<hex_literal, chars<>, Chars...>{};
2856 
2857 template <char... Chars>
2858 struct literal<'0', 'X', Chars...> :
2859   remove_separators<hex_literal, chars<>, Chars...>{};
2860 
2861 } // namespace detail
2862 
2863 /// Literal operator for creating const_buffer objects from string literals.
2864 inline const_buffer operator ""_buf(const char* data, std::size_t n)
2865 {
2866   return const_buffer(data, n);
2867 }
2868 
2869 /// Literal operator for creating const_buffer objects from unbounded binary or
2870 /// hexadecimal integer literals.
2871 template <char... Chars>
2872 inline const_buffer operator ""_buf()
2873 {
2874   return const_buffer(
2875       +detail::literal<Chars...>::data,
2876       detail::literal<Chars...>::size);
2877 }
2878 
2879 } // namespace buffer_literals
2880 } // namespace asio
2881 } // namespace boost
2882 
2883 #include <boost/asio/detail/pop_options.hpp>
2884 
2885 #endif // BOOST_ASIO_BUFFER_HPP