Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:33:43

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