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