1 //
2 // detail/buffer_sequence_adapter.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_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 
23 #include <boost/asio/detail/push_options.hpp>
24 
25 namespace boost {
26 namespace asio {
27 namespace detail {
28 
29 class buffer_sequence_adapter_base
30 {
31 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
32 public:
33   // The maximum number of buffers to support in a single operation.
34   enum { max_buffers = 1 };
35 
36 protected:
37   typedef Windows::Storage::Streams::IBuffer^ native_buffer_type;
38 
39   BOOST_ASIO_DECL static void init_native_buffer(
40       native_buffer_type& buf,
41       const boost::asio::mutable_buffer& buffer);
42 
43   BOOST_ASIO_DECL static void init_native_buffer(
44       native_buffer_type& buf,
45       const boost::asio::const_buffer& buffer);
46 #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
47 public:
48   // The maximum number of buffers to support in a single operation.
49   enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
50 
51 protected:
52   typedef WSABUF native_buffer_type;
53 
54   static void init_native_buffer(WSABUF& buf,
55       const boost::asio::mutable_buffer& buffer)
56   {
57     buf.buf = static_cast<char*>(buffer.data());
58     buf.len = static_cast<ULONG>(buffer.size());
59   }
60 
61   static void init_native_buffer(WSABUF& buf,
62       const boost::asio::const_buffer& buffer)
63   {
64     buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data()));
65     buf.len = static_cast<ULONG>(buffer.size());
66   }
67 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
68 public:
69   // The maximum number of buffers to support in a single operation.
70   enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
71 
72 protected:
73   typedef iovec native_buffer_type;
74 
75   static void init_iov_base(void*& base, void* addr)
76   {
77     base = addr;
78   }
79 
80   template <typename T>
81   static void init_iov_base(T& base, void* addr)
82   {
83     base = static_cast<T>(addr);
84   }
85 
86   static void init_native_buffer(iovec& iov,
87       const boost::asio::mutable_buffer& buffer)
88   {
89     init_iov_base(iov.iov_base, buffer.data());
90     iov.iov_len = buffer.size();
91   }
92 
93   static void init_native_buffer(iovec& iov,
94       const boost::asio::const_buffer& buffer)
95   {
96     init_iov_base(iov.iov_base, const_cast<void*>(buffer.data()));
97     iov.iov_len = buffer.size();
98   }
99 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
100 };
101 
102 // Helper class to translate buffers into the native buffer representation.
103 template <typename Buffer, typename Buffers>
104 class buffer_sequence_adapter
105   : buffer_sequence_adapter_base
106 {
107 public:
108   enum { is_single_buffer = false };
109 
buffer_sequence_adapter(const Buffers & buffer_sequence)110   explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
111     : count_(0), total_buffer_size_(0)
112   {
113     buffer_sequence_adapter::init(
114         boost::asio::buffer_sequence_begin(buffer_sequence),
115         boost::asio::buffer_sequence_end(buffer_sequence));
116   }
117 
buffers()118   native_buffer_type* buffers()
119   {
120     return buffers_;
121   }
122 
count() const123   std::size_t count() const
124   {
125     return count_;
126   }
127 
total_size() const128   std::size_t total_size() const
129   {
130     return total_buffer_size_;
131   }
132 
all_empty() const133   bool all_empty() const
134   {
135     return total_buffer_size_ == 0;
136   }
137 
all_empty(const Buffers & buffer_sequence)138   static bool all_empty(const Buffers& buffer_sequence)
139   {
140     return buffer_sequence_adapter::all_empty(
141         boost::asio::buffer_sequence_begin(buffer_sequence),
142         boost::asio::buffer_sequence_end(buffer_sequence));
143   }
144 
validate(const Buffers & buffer_sequence)145   static void validate(const Buffers& buffer_sequence)
146   {
147     buffer_sequence_adapter::validate(
148         boost::asio::buffer_sequence_begin(buffer_sequence),
149         boost::asio::buffer_sequence_end(buffer_sequence));
150   }
151 
first(const Buffers & buffer_sequence)152   static Buffer first(const Buffers& buffer_sequence)
153   {
154     return buffer_sequence_adapter::first(
155         boost::asio::buffer_sequence_begin(buffer_sequence),
156         boost::asio::buffer_sequence_end(buffer_sequence));
157   }
158 
159   enum { linearisation_storage_size = 8192 };
160 
linearise(const Buffers & buffer_sequence,const boost::asio::mutable_buffer & storage)161   static Buffer linearise(const Buffers& buffer_sequence,
162       const boost::asio::mutable_buffer& storage)
163   {
164     return buffer_sequence_adapter::linearise(
165         boost::asio::buffer_sequence_begin(buffer_sequence),
166         boost::asio::buffer_sequence_end(buffer_sequence), storage);
167   }
168 
169 private:
170   template <typename Iterator>
init(Iterator begin,Iterator end)171   void init(Iterator begin, Iterator end)
172   {
173     Iterator iter = begin;
174     for (; iter != end && count_ < max_buffers; ++iter, ++count_)
175     {
176       Buffer buffer(*iter);
177       init_native_buffer(buffers_[count_], buffer);
178       total_buffer_size_ += buffer.size();
179     }
180   }
181 
182   template <typename Iterator>
all_empty(Iterator begin,Iterator end)183   static bool all_empty(Iterator begin, Iterator end)
184   {
185     Iterator iter = begin;
186     std::size_t i = 0;
187     for (; iter != end && i < max_buffers; ++iter, ++i)
188       if (Buffer(*iter).size() > 0)
189         return false;
190     return true;
191   }
192 
193   template <typename Iterator>
validate(Iterator begin,Iterator end)194   static void validate(Iterator begin, Iterator end)
195   {
196     Iterator iter = begin;
197     for (; iter != end; ++iter)
198     {
199       Buffer buffer(*iter);
200       buffer.data();
201     }
202   }
203 
204   template <typename Iterator>
first(Iterator begin,Iterator end)205   static Buffer first(Iterator begin, Iterator end)
206   {
207     Iterator iter = begin;
208     for (; iter != end; ++iter)
209     {
210       Buffer buffer(*iter);
211       if (buffer.size() != 0)
212         return buffer;
213     }
214     return Buffer();
215   }
216 
217   template <typename Iterator>
linearise(Iterator begin,Iterator end,const boost::asio::mutable_buffer & storage)218   static Buffer linearise(Iterator begin, Iterator end,
219       const boost::asio::mutable_buffer& storage)
220   {
221     boost::asio::mutable_buffer unused_storage = storage;
222     Iterator iter = begin;
223     while (iter != end && unused_storage.size() != 0)
224     {
225       Buffer buffer(*iter);
226       ++iter;
227       if (buffer.size() == 0)
228         continue;
229       if (unused_storage.size() == storage.size())
230       {
231         if (iter == end)
232           return buffer;
233         if (buffer.size() >= unused_storage.size())
234           return buffer;
235       }
236       unused_storage += boost::asio::buffer_copy(unused_storage, buffer);
237     }
238     return Buffer(storage.data(), storage.size() - unused_storage.size());
239   }
240 
241   native_buffer_type buffers_[max_buffers];
242   std::size_t count_;
243   std::size_t total_buffer_size_;
244 };
245 
246 template <typename Buffer>
247 class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer>
248   : buffer_sequence_adapter_base
249 {
250 public:
251   enum { is_single_buffer = true };
252 
buffer_sequence_adapter(const boost::asio::mutable_buffer & buffer_sequence)253   explicit buffer_sequence_adapter(
254       const boost::asio::mutable_buffer& buffer_sequence)
255   {
256     init_native_buffer(buffer_, Buffer(buffer_sequence));
257     total_buffer_size_ = buffer_sequence.size();
258   }
259 
buffers()260   native_buffer_type* buffers()
261   {
262     return &buffer_;
263   }
264 
count() const265   std::size_t count() const
266   {
267     return 1;
268   }
269 
total_size() const270   std::size_t total_size() const
271   {
272     return total_buffer_size_;
273   }
274 
all_empty() const275   bool all_empty() const
276   {
277     return total_buffer_size_ == 0;
278   }
279 
all_empty(const boost::asio::mutable_buffer & buffer_sequence)280   static bool all_empty(const boost::asio::mutable_buffer& buffer_sequence)
281   {
282     return buffer_sequence.size() == 0;
283   }
284 
validate(const boost::asio::mutable_buffer & buffer_sequence)285   static void validate(const boost::asio::mutable_buffer& buffer_sequence)
286   {
287     buffer_sequence.data();
288   }
289 
first(const boost::asio::mutable_buffer & buffer_sequence)290   static Buffer first(const boost::asio::mutable_buffer& buffer_sequence)
291   {
292     return Buffer(buffer_sequence);
293   }
294 
295   enum { linearisation_storage_size = 1 };
296 
linearise(const boost::asio::mutable_buffer & buffer_sequence,const Buffer &)297   static Buffer linearise(const boost::asio::mutable_buffer& buffer_sequence,
298       const Buffer&)
299   {
300     return Buffer(buffer_sequence);
301   }
302 
303 private:
304   native_buffer_type buffer_;
305   std::size_t total_buffer_size_;
306 };
307 
308 template <typename Buffer>
309 class buffer_sequence_adapter<Buffer, boost::asio::const_buffer>
310   : buffer_sequence_adapter_base
311 {
312 public:
313   enum { is_single_buffer = true };
314 
buffer_sequence_adapter(const boost::asio::const_buffer & buffer_sequence)315   explicit buffer_sequence_adapter(
316       const boost::asio::const_buffer& buffer_sequence)
317   {
318     init_native_buffer(buffer_, Buffer(buffer_sequence));
319     total_buffer_size_ = buffer_sequence.size();
320   }
321 
buffers()322   native_buffer_type* buffers()
323   {
324     return &buffer_;
325   }
326 
count() const327   std::size_t count() const
328   {
329     return 1;
330   }
331 
total_size() const332   std::size_t total_size() const
333   {
334     return total_buffer_size_;
335   }
336 
all_empty() const337   bool all_empty() const
338   {
339     return total_buffer_size_ == 0;
340   }
341 
all_empty(const boost::asio::const_buffer & buffer_sequence)342   static bool all_empty(const boost::asio::const_buffer& buffer_sequence)
343   {
344     return buffer_sequence.size() == 0;
345   }
346 
validate(const boost::asio::const_buffer & buffer_sequence)347   static void validate(const boost::asio::const_buffer& buffer_sequence)
348   {
349     buffer_sequence.data();
350   }
351 
first(const boost::asio::const_buffer & buffer_sequence)352   static Buffer first(const boost::asio::const_buffer& buffer_sequence)
353   {
354     return Buffer(buffer_sequence);
355   }
356 
357   enum { linearisation_storage_size = 1 };
358 
linearise(const boost::asio::const_buffer & buffer_sequence,const Buffer &)359   static Buffer linearise(const boost::asio::const_buffer& buffer_sequence,
360       const Buffer&)
361   {
362     return Buffer(buffer_sequence);
363   }
364 
365 private:
366   native_buffer_type buffer_;
367   std::size_t total_buffer_size_;
368 };
369 
370 #if !defined(BOOST_ASIO_NO_DEPRECATED)
371 
372 template <typename Buffer>
373 class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1>
374   : buffer_sequence_adapter_base
375 {
376 public:
377   enum { is_single_buffer = true };
378 
buffer_sequence_adapter(const boost::asio::mutable_buffers_1 & buffer_sequence)379   explicit buffer_sequence_adapter(
380       const boost::asio::mutable_buffers_1& buffer_sequence)
381   {
382     init_native_buffer(buffer_, Buffer(buffer_sequence));
383     total_buffer_size_ = buffer_sequence.size();
384   }
385 
buffers()386   native_buffer_type* buffers()
387   {
388     return &buffer_;
389   }
390 
count() const391   std::size_t count() const
392   {
393     return 1;
394   }
395 
total_size() const396   std::size_t total_size() const
397   {
398     return total_buffer_size_;
399   }
400 
all_empty() const401   bool all_empty() const
402   {
403     return total_buffer_size_ == 0;
404   }
405 
all_empty(const boost::asio::mutable_buffers_1 & buffer_sequence)406   static bool all_empty(const boost::asio::mutable_buffers_1& buffer_sequence)
407   {
408     return buffer_sequence.size() == 0;
409   }
410 
validate(const boost::asio::mutable_buffers_1 & buffer_sequence)411   static void validate(const boost::asio::mutable_buffers_1& buffer_sequence)
412   {
413     buffer_sequence.data();
414   }
415 
first(const boost::asio::mutable_buffers_1 & buffer_sequence)416   static Buffer first(const boost::asio::mutable_buffers_1& buffer_sequence)
417   {
418     return Buffer(buffer_sequence);
419   }
420 
421   enum { linearisation_storage_size = 1 };
422 
linearise(const boost::asio::mutable_buffers_1 & buffer_sequence,const Buffer &)423   static Buffer linearise(const boost::asio::mutable_buffers_1& buffer_sequence,
424       const Buffer&)
425   {
426     return Buffer(buffer_sequence);
427   }
428 
429 private:
430   native_buffer_type buffer_;
431   std::size_t total_buffer_size_;
432 };
433 
434 template <typename Buffer>
435 class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1>
436   : buffer_sequence_adapter_base
437 {
438 public:
439   enum { is_single_buffer = true };
440 
buffer_sequence_adapter(const boost::asio::const_buffers_1 & buffer_sequence)441   explicit buffer_sequence_adapter(
442       const boost::asio::const_buffers_1& buffer_sequence)
443   {
444     init_native_buffer(buffer_, Buffer(buffer_sequence));
445     total_buffer_size_ = buffer_sequence.size();
446   }
447 
buffers()448   native_buffer_type* buffers()
449   {
450     return &buffer_;
451   }
452 
count() const453   std::size_t count() const
454   {
455     return 1;
456   }
457 
total_size() const458   std::size_t total_size() const
459   {
460     return total_buffer_size_;
461   }
462 
all_empty() const463   bool all_empty() const
464   {
465     return total_buffer_size_ == 0;
466   }
467 
all_empty(const boost::asio::const_buffers_1 & buffer_sequence)468   static bool all_empty(const boost::asio::const_buffers_1& buffer_sequence)
469   {
470     return buffer_sequence.size() == 0;
471   }
472 
validate(const boost::asio::const_buffers_1 & buffer_sequence)473   static void validate(const boost::asio::const_buffers_1& buffer_sequence)
474   {
475     buffer_sequence.data();
476   }
477 
first(const boost::asio::const_buffers_1 & buffer_sequence)478   static Buffer first(const boost::asio::const_buffers_1& buffer_sequence)
479   {
480     return Buffer(buffer_sequence);
481   }
482 
483   enum { linearisation_storage_size = 1 };
484 
linearise(const boost::asio::const_buffers_1 & buffer_sequence,const Buffer &)485   static Buffer linearise(const boost::asio::const_buffers_1& buffer_sequence,
486       const Buffer&)
487   {
488     return Buffer(buffer_sequence);
489   }
490 
491 private:
492   native_buffer_type buffer_;
493   std::size_t total_buffer_size_;
494 };
495 
496 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
497 
498 template <typename Buffer, typename Elem>
499 class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
500   : buffer_sequence_adapter_base
501 {
502 public:
503   enum { is_single_buffer = false };
504 
buffer_sequence_adapter(const boost::array<Elem,2> & buffer_sequence)505   explicit buffer_sequence_adapter(
506       const boost::array<Elem, 2>& buffer_sequence)
507   {
508     init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
509     init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
510     total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
511   }
512 
buffers()513   native_buffer_type* buffers()
514   {
515     return buffers_;
516   }
517 
count() const518   std::size_t count() const
519   {
520     return 2;
521   }
522 
total_size() const523   std::size_t total_size() const
524   {
525     return total_buffer_size_;
526   }
527 
all_empty() const528   bool all_empty() const
529   {
530     return total_buffer_size_ == 0;
531   }
532 
all_empty(const boost::array<Elem,2> & buffer_sequence)533   static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)
534   {
535     return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
536   }
537 
validate(const boost::array<Elem,2> & buffer_sequence)538   static void validate(const boost::array<Elem, 2>& buffer_sequence)
539   {
540     buffer_sequence[0].data();
541     buffer_sequence[1].data();
542   }
543 
first(const boost::array<Elem,2> & buffer_sequence)544   static Buffer first(const boost::array<Elem, 2>& buffer_sequence)
545   {
546     return Buffer(buffer_sequence[0].size() != 0
547         ? buffer_sequence[0] : buffer_sequence[1]);
548   }
549 
550   enum { linearisation_storage_size = 8192 };
551 
linearise(const boost::array<Elem,2> & buffer_sequence,const boost::asio::mutable_buffer & storage)552   static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence,
553       const boost::asio::mutable_buffer& storage)
554   {
555     if (buffer_sequence[0].size() == 0)
556       return Buffer(buffer_sequence[1]);
557     if (buffer_sequence[1].size() == 0)
558       return Buffer(buffer_sequence[0]);
559     return Buffer(storage.data(),
560         boost::asio::buffer_copy(storage, buffer_sequence));
561   }
562 
563 private:
564   native_buffer_type buffers_[2];
565   std::size_t total_buffer_size_;
566 };
567 
568 #if defined(BOOST_ASIO_HAS_STD_ARRAY)
569 
570 template <typename Buffer, typename Elem>
571 class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
572   : buffer_sequence_adapter_base
573 {
574 public:
575   enum { is_single_buffer = false };
576 
buffer_sequence_adapter(const std::array<Elem,2> & buffer_sequence)577   explicit buffer_sequence_adapter(
578       const std::array<Elem, 2>& buffer_sequence)
579   {
580     init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
581     init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
582     total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
583   }
584 
buffers()585   native_buffer_type* buffers()
586   {
587     return buffers_;
588   }
589 
count() const590   std::size_t count() const
591   {
592     return 2;
593   }
594 
total_size() const595   std::size_t total_size() const
596   {
597     return total_buffer_size_;
598   }
599 
all_empty() const600   bool all_empty() const
601   {
602     return total_buffer_size_ == 0;
603   }
604 
all_empty(const std::array<Elem,2> & buffer_sequence)605   static bool all_empty(const std::array<Elem, 2>& buffer_sequence)
606   {
607     return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
608   }
609 
validate(const std::array<Elem,2> & buffer_sequence)610   static void validate(const std::array<Elem, 2>& buffer_sequence)
611   {
612     buffer_sequence[0].data();
613     buffer_sequence[1].data();
614   }
615 
first(const std::array<Elem,2> & buffer_sequence)616   static Buffer first(const std::array<Elem, 2>& buffer_sequence)
617   {
618     return Buffer(buffer_sequence[0].size() != 0
619         ? buffer_sequence[0] : buffer_sequence[1]);
620   }
621 
622   enum { linearisation_storage_size = 8192 };
623 
linearise(const std::array<Elem,2> & buffer_sequence,const boost::asio::mutable_buffer & storage)624   static Buffer linearise(const std::array<Elem, 2>& buffer_sequence,
625       const boost::asio::mutable_buffer& storage)
626   {
627     if (buffer_sequence[0].size() == 0)
628       return Buffer(buffer_sequence[1]);
629     if (buffer_sequence[1].size() == 0)
630       return Buffer(buffer_sequence[0]);
631     return Buffer(storage.data(),
632         boost::asio::buffer_copy(storage, buffer_sequence));
633   }
634 
635 private:
636   native_buffer_type buffers_[2];
637   std::size_t total_buffer_size_;
638 };
639 
640 #endif // defined(BOOST_ASIO_HAS_STD_ARRAY)
641 
642 } // namespace detail
643 } // namespace asio
644 } // namespace boost
645 
646 #include <boost/asio/detail/pop_options.hpp>
647 
648 #if defined(BOOST_ASIO_HEADER_ONLY)
649 # include <boost/asio/detail/impl/buffer_sequence_adapter.ipp>
650 #endif // defined(BOOST_ASIO_HEADER_ONLY)
651 
652 #endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
653