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