1//
2// detail/buffer_sequence_adapter.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_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
12#define BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_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 <boost/asio/buffer.hpp>
20#include <boost/asio/detail/array_fwd.hpp>
21#include <boost/asio/detail/socket_types.hpp>
22#include <boost/asio/registered_buffer.hpp>
23
24#include <boost/asio/detail/push_options.hpp>
25
26namespace boost {
27namespace asio {
28namespace detail {
29
30class buffer_sequence_adapter_base
31{
32#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
33public:
34 // The maximum number of buffers to support in a single operation.
35 enum { max_buffers = 1 };
36
37protected:
38 typedef Windows::Storage::Streams::IBuffer^ native_buffer_type;
39
40 BOOST_ASIO_DECL static void init_native_buffer(
41 native_buffer_type& buf,
42 const boost::asio::mutable_buffer& buffer);
43
44 BOOST_ASIO_DECL static void init_native_buffer(
45 native_buffer_type& buf,
46 const boost::asio::const_buffer& buffer);
47#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
48public:
49 // The maximum number of buffers to support in a single operation.
50 enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
51
52protected:
53 typedef WSABUF native_buffer_type;
54
55 static void init_native_buffer(WSABUF& buf,
56 const boost::asio::mutable_buffer& buffer)
57 {
58 buf.buf = static_cast<char*>(buffer.data());
59 buf.len = static_cast<ULONG>(buffer.size());
60 }
61
62 static void init_native_buffer(WSABUF& buf,
63 const boost::asio::const_buffer& buffer)
64 {
65 buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data()));
66 buf.len = static_cast<ULONG>(buffer.size());
67 }
68#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
69public:
70 // The maximum number of buffers to support in a single operation.
71 enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
72
73protected:
74 typedef iovec native_buffer_type;
75
76 static void init_iov_base(void*& base, void* addr)
77 {
78 base = addr;
79 }
80
81 template <typename T>
82 static void init_iov_base(T& base, void* addr)
83 {
84 base = static_cast<T>(addr);
85 }
86
87 static void init_native_buffer(iovec& iov,
88 const boost::asio::mutable_buffer& buffer)
89 {
90 init_iov_base(base&: iov.iov_base, addr: buffer.data());
91 iov.iov_len = buffer.size();
92 }
93
94 static void init_native_buffer(iovec& iov,
95 const boost::asio::const_buffer& buffer)
96 {
97 init_iov_base(base&: iov.iov_base, addr: const_cast<void*>(buffer.data()));
98 iov.iov_len = buffer.size();
99 }
100#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
101};
102
103// Helper class to translate buffers into the native buffer representation.
104template <typename Buffer, typename Buffers>
105class buffer_sequence_adapter
106 : buffer_sequence_adapter_base
107{
108public:
109 enum { is_single_buffer = false };
110 enum { is_registered_buffer = false };
111
112 explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
113 : count_(0), total_buffer_size_(0)
114 {
115 buffer_sequence_adapter::init(
116 boost::asio::buffer_sequence_begin(buffer_sequence),
117 boost::asio::buffer_sequence_end(buffer_sequence));
118 }
119
120 native_buffer_type* buffers()
121 {
122 return buffers_;
123 }
124
125 std::size_t count() const
126 {
127 return count_;
128 }
129
130 std::size_t total_size() const
131 {
132 return total_buffer_size_;
133 }
134
135 registered_buffer_id registered_id() const
136 {
137 return registered_buffer_id();
138 }
139
140 bool all_empty() const
141 {
142 return total_buffer_size_ == 0;
143 }
144
145 static bool all_empty(const Buffers& buffer_sequence)
146 {
147 return buffer_sequence_adapter::all_empty(
148 boost::asio::buffer_sequence_begin(buffer_sequence),
149 boost::asio::buffer_sequence_end(buffer_sequence));
150 }
151
152 static void validate(const Buffers& buffer_sequence)
153 {
154 buffer_sequence_adapter::validate(
155 boost::asio::buffer_sequence_begin(buffer_sequence),
156 boost::asio::buffer_sequence_end(buffer_sequence));
157 }
158
159 static Buffer first(const Buffers& buffer_sequence)
160 {
161 return buffer_sequence_adapter::first(
162 boost::asio::buffer_sequence_begin(buffer_sequence),
163 boost::asio::buffer_sequence_end(buffer_sequence));
164 }
165
166 enum { linearisation_storage_size = 8192 };
167
168 static Buffer linearise(const Buffers& buffer_sequence,
169 const boost::asio::mutable_buffer& storage)
170 {
171 return buffer_sequence_adapter::linearise(
172 boost::asio::buffer_sequence_begin(buffer_sequence),
173 boost::asio::buffer_sequence_end(buffer_sequence), storage);
174 }
175
176private:
177 template <typename Iterator>
178 void init(Iterator begin, Iterator end)
179 {
180 Iterator iter = begin;
181 for (; iter != end && count_ < max_buffers; ++iter, ++count_)
182 {
183 Buffer buffer(*iter);
184 init_native_buffer(buffers_[count_], buffer);
185 total_buffer_size_ += buffer.size();
186 }
187 }
188
189 template <typename Iterator>
190 static bool all_empty(Iterator begin, Iterator end)
191 {
192 Iterator iter = begin;
193 std::size_t i = 0;
194 for (; iter != end && i < max_buffers; ++iter, ++i)
195 if (Buffer(*iter).size() > 0)
196 return false;
197 return true;
198 }
199
200 template <typename Iterator>
201 static void validate(Iterator begin, Iterator end)
202 {
203 Iterator iter = begin;
204 for (; iter != end; ++iter)
205 {
206 Buffer buffer(*iter);
207 buffer.data();
208 }
209 }
210
211 template <typename Iterator>
212 static Buffer first(Iterator begin, Iterator end)
213 {
214 Iterator iter = begin;
215 for (; iter != end; ++iter)
216 {
217 Buffer buffer(*iter);
218 if (buffer.size() != 0)
219 return buffer;
220 }
221 return Buffer();
222 }
223
224 template <typename Iterator>
225 static Buffer linearise(Iterator begin, Iterator end,
226 const boost::asio::mutable_buffer& storage)
227 {
228 boost::asio::mutable_buffer unused_storage = storage;
229 Iterator iter = begin;
230 while (iter != end && unused_storage.size() != 0)
231 {
232 Buffer buffer(*iter);
233 ++iter;
234 if (buffer.size() == 0)
235 continue;
236 if (unused_storage.size() == storage.size())
237 {
238 if (iter == end)
239 return buffer;
240 if (buffer.size() >= unused_storage.size())
241 return buffer;
242 }
243 unused_storage += boost::asio::buffer_copy(unused_storage, buffer);
244 }
245 return Buffer(storage.data(), storage.size() - unused_storage.size());
246 }
247
248 native_buffer_type buffers_[max_buffers];
249 std::size_t count_;
250 std::size_t total_buffer_size_;
251};
252
253template <typename Buffer>
254class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer>
255 : buffer_sequence_adapter_base
256{
257public:
258 enum { is_single_buffer = true };
259 enum { is_registered_buffer = false };
260
261 explicit buffer_sequence_adapter(
262 const boost::asio::mutable_buffer& buffer_sequence)
263 {
264 init_native_buffer(buffer_, Buffer(buffer_sequence));
265 total_buffer_size_ = buffer_sequence.size();
266 }
267
268 native_buffer_type* buffers()
269 {
270 return &buffer_;
271 }
272
273 std::size_t count() const
274 {
275 return 1;
276 }
277
278 std::size_t total_size() const
279 {
280 return total_buffer_size_;
281 }
282
283 registered_buffer_id registered_id() const
284 {
285 return registered_buffer_id();
286 }
287
288 bool all_empty() const
289 {
290 return total_buffer_size_ == 0;
291 }
292
293 static bool all_empty(const boost::asio::mutable_buffer& buffer_sequence)
294 {
295 return buffer_sequence.size() == 0;
296 }
297
298 static void validate(const boost::asio::mutable_buffer& buffer_sequence)
299 {
300 buffer_sequence.data();
301 }
302
303 static Buffer first(const boost::asio::mutable_buffer& buffer_sequence)
304 {
305 return Buffer(buffer_sequence);
306 }
307
308 enum { linearisation_storage_size = 1 };
309
310 static Buffer linearise(const boost::asio::mutable_buffer& buffer_sequence,
311 const Buffer&)
312 {
313 return Buffer(buffer_sequence);
314 }
315
316private:
317 native_buffer_type buffer_;
318 std::size_t total_buffer_size_;
319};
320
321template <typename Buffer>
322class buffer_sequence_adapter<Buffer, boost::asio::const_buffer>
323 : buffer_sequence_adapter_base
324{
325public:
326 enum { is_single_buffer = true };
327 enum { is_registered_buffer = false };
328
329 explicit buffer_sequence_adapter(
330 const boost::asio::const_buffer& buffer_sequence)
331 {
332 init_native_buffer(buffer_, Buffer(buffer_sequence));
333 total_buffer_size_ = buffer_sequence.size();
334 }
335
336 native_buffer_type* buffers()
337 {
338 return &buffer_;
339 }
340
341 std::size_t count() const
342 {
343 return 1;
344 }
345
346 std::size_t total_size() const
347 {
348 return total_buffer_size_;
349 }
350
351 registered_buffer_id registered_id() const
352 {
353 return registered_buffer_id();
354 }
355
356 bool all_empty() const
357 {
358 return total_buffer_size_ == 0;
359 }
360
361 static bool all_empty(const boost::asio::const_buffer& buffer_sequence)
362 {
363 return buffer_sequence.size() == 0;
364 }
365
366 static void validate(const boost::asio::const_buffer& buffer_sequence)
367 {
368 buffer_sequence.data();
369 }
370
371 static Buffer first(const boost::asio::const_buffer& buffer_sequence)
372 {
373 return Buffer(buffer_sequence);
374 }
375
376 enum { linearisation_storage_size = 1 };
377
378 static Buffer linearise(const boost::asio::const_buffer& buffer_sequence,
379 const Buffer&)
380 {
381 return Buffer(buffer_sequence);
382 }
383
384private:
385 native_buffer_type buffer_;
386 std::size_t total_buffer_size_;
387};
388
389#if !defined(BOOST_ASIO_NO_DEPRECATED)
390
391template <typename Buffer>
392class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1>
393 : buffer_sequence_adapter_base
394{
395public:
396 enum { is_single_buffer = true };
397 enum { is_registered_buffer = false };
398
399 explicit buffer_sequence_adapter(
400 const boost::asio::mutable_buffers_1& buffer_sequence)
401 {
402 init_native_buffer(buffer_, Buffer(buffer_sequence));
403 total_buffer_size_ = buffer_sequence.size();
404 }
405
406 native_buffer_type* buffers()
407 {
408 return &buffer_;
409 }
410
411 std::size_t count() const
412 {
413 return 1;
414 }
415
416 std::size_t total_size() const
417 {
418 return total_buffer_size_;
419 }
420
421 registered_buffer_id registered_id() const
422 {
423 return registered_buffer_id();
424 }
425
426 bool all_empty() const
427 {
428 return total_buffer_size_ == 0;
429 }
430
431 static bool all_empty(const boost::asio::mutable_buffers_1& buffer_sequence)
432 {
433 return buffer_sequence.size() == 0;
434 }
435
436 static void validate(const boost::asio::mutable_buffers_1& buffer_sequence)
437 {
438 buffer_sequence.data();
439 }
440
441 static Buffer first(const boost::asio::mutable_buffers_1& buffer_sequence)
442 {
443 return Buffer(buffer_sequence);
444 }
445
446 enum { linearisation_storage_size = 1 };
447
448 static Buffer linearise(const boost::asio::mutable_buffers_1& buffer_sequence,
449 const Buffer&)
450 {
451 return Buffer(buffer_sequence);
452 }
453
454private:
455 native_buffer_type buffer_;
456 std::size_t total_buffer_size_;
457};
458
459template <typename Buffer>
460class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1>
461 : buffer_sequence_adapter_base
462{
463public:
464 enum { is_single_buffer = true };
465 enum { is_registered_buffer = false };
466
467 explicit buffer_sequence_adapter(
468 const boost::asio::const_buffers_1& buffer_sequence)
469 {
470 init_native_buffer(buffer_, Buffer(buffer_sequence));
471 total_buffer_size_ = buffer_sequence.size();
472 }
473
474 native_buffer_type* buffers()
475 {
476 return &buffer_;
477 }
478
479 std::size_t count() const
480 {
481 return 1;
482 }
483
484 std::size_t total_size() const
485 {
486 return total_buffer_size_;
487 }
488
489 registered_buffer_id registered_id() const
490 {
491 return registered_buffer_id();
492 }
493
494 bool all_empty() const
495 {
496 return total_buffer_size_ == 0;
497 }
498
499 static bool all_empty(const boost::asio::const_buffers_1& buffer_sequence)
500 {
501 return buffer_sequence.size() == 0;
502 }
503
504 static void validate(const boost::asio::const_buffers_1& buffer_sequence)
505 {
506 buffer_sequence.data();
507 }
508
509 static Buffer first(const boost::asio::const_buffers_1& buffer_sequence)
510 {
511 return Buffer(buffer_sequence);
512 }
513
514 enum { linearisation_storage_size = 1 };
515
516 static Buffer linearise(const boost::asio::const_buffers_1& buffer_sequence,
517 const Buffer&)
518 {
519 return Buffer(buffer_sequence);
520 }
521
522private:
523 native_buffer_type buffer_;
524 std::size_t total_buffer_size_;
525};
526
527#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
528
529template <typename Buffer>
530class buffer_sequence_adapter<Buffer, boost::asio::mutable_registered_buffer>
531 : buffer_sequence_adapter_base
532{
533public:
534 enum { is_single_buffer = true };
535 enum { is_registered_buffer = true };
536
537 explicit buffer_sequence_adapter(
538 const boost::asio::mutable_registered_buffer& buffer_sequence)
539 {
540 init_native_buffer(iov&: buffer_, buffer: buffer_sequence.buffer());
541 total_buffer_size_ = buffer_sequence.size();
542 registered_id_ = buffer_sequence.id();
543 }
544
545 native_buffer_type* buffers()
546 {
547 return &buffer_;
548 }
549
550 std::size_t count() const
551 {
552 return 1;
553 }
554
555 std::size_t total_size() const
556 {
557 return total_buffer_size_;
558 }
559
560 registered_buffer_id registered_id() const
561 {
562 return registered_id_;
563 }
564
565 bool all_empty() const
566 {
567 return total_buffer_size_ == 0;
568 }
569
570 static bool all_empty(
571 const boost::asio::mutable_registered_buffer& buffer_sequence)
572 {
573 return buffer_sequence.size() == 0;
574 }
575
576 static void validate(
577 const boost::asio::mutable_registered_buffer& buffer_sequence)
578 {
579 buffer_sequence.data();
580 }
581
582 static Buffer first(
583 const boost::asio::mutable_registered_buffer& buffer_sequence)
584 {
585 return Buffer(buffer_sequence.buffer());
586 }
587
588 enum { linearisation_storage_size = 1 };
589
590 static Buffer linearise(
591 const boost::asio::mutable_registered_buffer& buffer_sequence,
592 const Buffer&)
593 {
594 return Buffer(buffer_sequence.buffer());
595 }
596
597private:
598 native_buffer_type buffer_;
599 std::size_t total_buffer_size_;
600 registered_buffer_id registered_id_;
601};
602
603template <typename Buffer>
604class buffer_sequence_adapter<Buffer, boost::asio::const_registered_buffer>
605 : buffer_sequence_adapter_base
606{
607public:
608 enum { is_single_buffer = true };
609 enum { is_registered_buffer = true };
610
611 explicit buffer_sequence_adapter(
612 const boost::asio::const_registered_buffer& buffer_sequence)
613 {
614 init_native_buffer(iov&: buffer_, buffer: buffer_sequence.buffer());
615 total_buffer_size_ = buffer_sequence.size();
616 registered_id_ = buffer_sequence.id();
617 }
618
619 native_buffer_type* buffers()
620 {
621 return &buffer_;
622 }
623
624 std::size_t count() const
625 {
626 return 1;
627 }
628
629 std::size_t total_size() const
630 {
631 return total_buffer_size_;
632 }
633
634 registered_buffer_id registered_id() const
635 {
636 return registered_id_;
637 }
638
639 bool all_empty() const
640 {
641 return total_buffer_size_ == 0;
642 }
643
644 static bool all_empty(
645 const boost::asio::const_registered_buffer& buffer_sequence)
646 {
647 return buffer_sequence.size() == 0;
648 }
649
650 static void validate(
651 const boost::asio::const_registered_buffer& buffer_sequence)
652 {
653 buffer_sequence.data();
654 }
655
656 static Buffer first(
657 const boost::asio::const_registered_buffer& buffer_sequence)
658 {
659 return Buffer(buffer_sequence.buffer());
660 }
661
662 enum { linearisation_storage_size = 1 };
663
664 static Buffer linearise(
665 const boost::asio::const_registered_buffer& buffer_sequence,
666 const Buffer&)
667 {
668 return Buffer(buffer_sequence.buffer());
669 }
670
671private:
672 native_buffer_type buffer_;
673 std::size_t total_buffer_size_;
674 registered_buffer_id registered_id_;
675};
676
677template <typename Buffer, typename Elem>
678class buffer_sequence_adapter<Buffer, boost::array<Elem, 2>>
679 : buffer_sequence_adapter_base
680{
681public:
682 enum { is_single_buffer = false };
683 enum { is_registered_buffer = false };
684
685 explicit buffer_sequence_adapter(
686 const boost::array<Elem, 2>& buffer_sequence)
687 {
688 init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
689 init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
690 total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
691 }
692
693 native_buffer_type* buffers()
694 {
695 return buffers_;
696 }
697
698 std::size_t count() const
699 {
700 return 2;
701 }
702
703 std::size_t total_size() const
704 {
705 return total_buffer_size_;
706 }
707
708 registered_buffer_id registered_id() const
709 {
710 return registered_buffer_id();
711 }
712
713 bool all_empty() const
714 {
715 return total_buffer_size_ == 0;
716 }
717
718 static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)
719 {
720 return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
721 }
722
723 static void validate(const boost::array<Elem, 2>& buffer_sequence)
724 {
725 buffer_sequence[0].data();
726 buffer_sequence[1].data();
727 }
728
729 static Buffer first(const boost::array<Elem, 2>& buffer_sequence)
730 {
731 return Buffer(buffer_sequence[0].size() != 0
732 ? buffer_sequence[0] : buffer_sequence[1]);
733 }
734
735 enum { linearisation_storage_size = 8192 };
736
737 static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence,
738 const boost::asio::mutable_buffer& storage)
739 {
740 if (buffer_sequence[0].size() == 0)
741 return Buffer(buffer_sequence[1]);
742 if (buffer_sequence[1].size() == 0)
743 return Buffer(buffer_sequence[0]);
744 return Buffer(storage.data(),
745 boost::asio::buffer_copy(storage, buffer_sequence));
746 }
747
748private:
749 native_buffer_type buffers_[2];
750 std::size_t total_buffer_size_;
751};
752
753template <typename Buffer, typename Elem>
754class buffer_sequence_adapter<Buffer, std::array<Elem, 2>>
755 : buffer_sequence_adapter_base
756{
757public:
758 enum { is_single_buffer = false };
759 enum { is_registered_buffer = false };
760
761 explicit buffer_sequence_adapter(
762 const std::array<Elem, 2>& buffer_sequence)
763 {
764 init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
765 init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
766 total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
767 }
768
769 native_buffer_type* buffers()
770 {
771 return buffers_;
772 }
773
774 std::size_t count() const
775 {
776 return 2;
777 }
778
779 std::size_t total_size() const
780 {
781 return total_buffer_size_;
782 }
783
784 registered_buffer_id registered_id() const
785 {
786 return registered_buffer_id();
787 }
788
789 bool all_empty() const
790 {
791 return total_buffer_size_ == 0;
792 }
793
794 static bool all_empty(const std::array<Elem, 2>& buffer_sequence)
795 {
796 return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
797 }
798
799 static void validate(const std::array<Elem, 2>& buffer_sequence)
800 {
801 buffer_sequence[0].data();
802 buffer_sequence[1].data();
803 }
804
805 static Buffer first(const std::array<Elem, 2>& buffer_sequence)
806 {
807 return Buffer(buffer_sequence[0].size() != 0
808 ? buffer_sequence[0] : buffer_sequence[1]);
809 }
810
811 enum { linearisation_storage_size = 8192 };
812
813 static Buffer linearise(const std::array<Elem, 2>& buffer_sequence,
814 const boost::asio::mutable_buffer& storage)
815 {
816 if (buffer_sequence[0].size() == 0)
817 return Buffer(buffer_sequence[1]);
818 if (buffer_sequence[1].size() == 0)
819 return Buffer(buffer_sequence[0]);
820 return Buffer(storage.data(),
821 boost::asio::buffer_copy(storage, buffer_sequence));
822 }
823
824private:
825 native_buffer_type buffers_[2];
826 std::size_t total_buffer_size_;
827};
828
829} // namespace detail
830} // namespace asio
831} // namespace boost
832
833#include <boost/asio/detail/pop_options.hpp>
834
835#if defined(BOOST_ASIO_HEADER_ONLY)
836# include <boost/asio/detail/impl/buffer_sequence_adapter.ipp>
837#endif // defined(BOOST_ASIO_HEADER_ONLY)
838
839#endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
840

source code of boost/libs/asio/include/boost/asio/detail/buffer_sequence_adapter.hpp