Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-20 08:38:41

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