1 //
2 // detail/buffer_sequence_adapter.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 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 protected:
32 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
33   // The maximum number of buffers to support in a single operation.
34   enum { max_buffers = 1 };
35 
36   typedef Windows::Storage::Streams::IBuffer^ native_buffer_type;
37 
38   BOOST_ASIO_DECL static void init_native_buffer(
39       native_buffer_type& buf,
40       const boost::asio::mutable_buffer& buffer);
41 
42   BOOST_ASIO_DECL static void init_native_buffer(
43       native_buffer_type& buf,
44       const boost::asio::const_buffer& buffer);
45 #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
46   // The maximum number of buffers to support in a single operation.
47   enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
48 
49   typedef WSABUF native_buffer_type;
50 
51   static void init_native_buffer(WSABUF& buf,
52       const boost::asio::mutable_buffer& buffer)
53   {
54     buf.buf = boost::asio::buffer_cast<char*>(buffer);
55     buf.len = static_cast<ULONG>(boost::asio::buffer_size(buffer));
56   }
57 
58   static void init_native_buffer(WSABUF& buf,
59       const boost::asio::const_buffer& buffer)
60   {
61     buf.buf = const_cast<char*>(boost::asio::buffer_cast<const char*>(buffer));
62     buf.len = static_cast<ULONG>(boost::asio::buffer_size(buffer));
63   }
64 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
65   // The maximum number of buffers to support in a single operation.
66   enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
67 
68   typedef iovec native_buffer_type;
69 
70   static void init_iov_base(void*& base, void* addr)
71   {
72     base = addr;
73   }
74 
75   template <typename T>
76   static void init_iov_base(T& base, void* addr)
77   {
78     base = static_cast<T>(addr);
79   }
80 
81   static void init_native_buffer(iovec& iov,
82       const boost::asio::mutable_buffer& buffer)
83   {
84     init_iov_base(iov.iov_base, boost::asio::buffer_cast<void*>(buffer));
85     iov.iov_len = boost::asio::buffer_size(buffer);
86   }
87 
88   static void init_native_buffer(iovec& iov,
89       const boost::asio::const_buffer& buffer)
90   {
91     init_iov_base(iov.iov_base, const_cast<void*>(
92           boost::asio::buffer_cast<const void*>(buffer)));
93     iov.iov_len = boost::asio::buffer_size(buffer);
94   }
95 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
96 };
97 
98 // Helper class to translate buffers into the native buffer representation.
99 template <typename Buffer, typename Buffers>
100 class buffer_sequence_adapter
101   : buffer_sequence_adapter_base
102 {
103 public:
buffer_sequence_adapter(const Buffers & buffer_sequence)104   explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
105     : count_(0), total_buffer_size_(0)
106   {
107     typename Buffers::const_iterator iter = buffer_sequence.begin();
108     typename Buffers::const_iterator end = buffer_sequence.end();
109     for (; iter != end && count_ < max_buffers; ++iter, ++count_)
110     {
111       Buffer buffer(*iter);
112       init_native_buffer(buffers_[count_], buffer);
113       total_buffer_size_ += boost::asio::buffer_size(buffer);
114     }
115   }
116 
buffers()117   native_buffer_type* buffers()
118   {
119     return buffers_;
120   }
121 
count() const122   std::size_t count() const
123   {
124     return count_;
125   }
126 
all_empty() const127   bool all_empty() const
128   {
129     return total_buffer_size_ == 0;
130   }
131 
all_empty(const Buffers & buffer_sequence)132   static bool all_empty(const Buffers& buffer_sequence)
133   {
134     typename Buffers::const_iterator iter = buffer_sequence.begin();
135     typename Buffers::const_iterator end = buffer_sequence.end();
136     std::size_t i = 0;
137     for (; iter != end && i < max_buffers; ++iter, ++i)
138       if (boost::asio::buffer_size(Buffer(*iter)) > 0)
139         return false;
140     return true;
141   }
142 
validate(const Buffers & buffer_sequence)143   static void validate(const Buffers& buffer_sequence)
144   {
145     typename Buffers::const_iterator iter = buffer_sequence.begin();
146     typename Buffers::const_iterator end = buffer_sequence.end();
147     for (; iter != end; ++iter)
148     {
149       Buffer buffer(*iter);
150       boost::asio::buffer_cast<const void*>(buffer);
151     }
152   }
153 
first(const Buffers & buffer_sequence)154   static Buffer first(const Buffers& buffer_sequence)
155   {
156     typename Buffers::const_iterator iter = buffer_sequence.begin();
157     typename Buffers::const_iterator end = buffer_sequence.end();
158     for (; iter != end; ++iter)
159     {
160       Buffer buffer(*iter);
161       if (boost::asio::buffer_size(buffer) != 0)
162         return buffer;
163     }
164     return Buffer();
165   }
166 
167 private:
168   native_buffer_type buffers_[max_buffers];
169   std::size_t count_;
170   std::size_t total_buffer_size_;
171 };
172 
173 template <typename Buffer>
174 class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1>
175   : buffer_sequence_adapter_base
176 {
177 public:
buffer_sequence_adapter(const boost::asio::mutable_buffers_1 & buffer_sequence)178   explicit buffer_sequence_adapter(
179       const boost::asio::mutable_buffers_1& buffer_sequence)
180   {
181     init_native_buffer(buffer_, Buffer(buffer_sequence));
182     total_buffer_size_ = boost::asio::buffer_size(buffer_sequence);
183   }
184 
buffers()185   native_buffer_type* buffers()
186   {
187     return &buffer_;
188   }
189 
count() const190   std::size_t count() const
191   {
192     return 1;
193   }
194 
all_empty() const195   bool all_empty() const
196   {
197     return total_buffer_size_ == 0;
198   }
199 
all_empty(const boost::asio::mutable_buffers_1 & buffer_sequence)200   static bool all_empty(const boost::asio::mutable_buffers_1& buffer_sequence)
201   {
202     return boost::asio::buffer_size(buffer_sequence) == 0;
203   }
204 
validate(const boost::asio::mutable_buffers_1 & buffer_sequence)205   static void validate(const boost::asio::mutable_buffers_1& buffer_sequence)
206   {
207     boost::asio::buffer_cast<const void*>(buffer_sequence);
208   }
209 
first(const boost::asio::mutable_buffers_1 & buffer_sequence)210   static Buffer first(const boost::asio::mutable_buffers_1& buffer_sequence)
211   {
212     return Buffer(buffer_sequence);
213   }
214 
215 private:
216   native_buffer_type buffer_;
217   std::size_t total_buffer_size_;
218 };
219 
220 template <typename Buffer>
221 class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1>
222   : buffer_sequence_adapter_base
223 {
224 public:
buffer_sequence_adapter(const boost::asio::const_buffers_1 & buffer_sequence)225   explicit buffer_sequence_adapter(
226       const boost::asio::const_buffers_1& buffer_sequence)
227   {
228     init_native_buffer(buffer_, Buffer(buffer_sequence));
229     total_buffer_size_ = boost::asio::buffer_size(buffer_sequence);
230   }
231 
buffers()232   native_buffer_type* buffers()
233   {
234     return &buffer_;
235   }
236 
count() const237   std::size_t count() const
238   {
239     return 1;
240   }
241 
all_empty() const242   bool all_empty() const
243   {
244     return total_buffer_size_ == 0;
245   }
246 
all_empty(const boost::asio::const_buffers_1 & buffer_sequence)247   static bool all_empty(const boost::asio::const_buffers_1& buffer_sequence)
248   {
249     return boost::asio::buffer_size(buffer_sequence) == 0;
250   }
251 
validate(const boost::asio::const_buffers_1 & buffer_sequence)252   static void validate(const boost::asio::const_buffers_1& buffer_sequence)
253   {
254     boost::asio::buffer_cast<const void*>(buffer_sequence);
255   }
256 
first(const boost::asio::const_buffers_1 & buffer_sequence)257   static Buffer first(const boost::asio::const_buffers_1& buffer_sequence)
258   {
259     return Buffer(buffer_sequence);
260   }
261 
262 private:
263   native_buffer_type buffer_;
264   std::size_t total_buffer_size_;
265 };
266 
267 template <typename Buffer, typename Elem>
268 class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
269   : buffer_sequence_adapter_base
270 {
271 public:
buffer_sequence_adapter(const boost::array<Elem,2> & buffer_sequence)272   explicit buffer_sequence_adapter(
273       const boost::array<Elem, 2>& buffer_sequence)
274   {
275     init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
276     init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
277     total_buffer_size_ = boost::asio::buffer_size(buffer_sequence[0])
278       + boost::asio::buffer_size(buffer_sequence[1]);
279   }
280 
buffers()281   native_buffer_type* buffers()
282   {
283     return buffers_;
284   }
285 
count() const286   std::size_t count() const
287   {
288     return 2;
289   }
290 
all_empty() const291   bool all_empty() const
292   {
293     return total_buffer_size_ == 0;
294   }
295 
all_empty(const boost::array<Elem,2> & buffer_sequence)296   static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)
297   {
298     return boost::asio::buffer_size(buffer_sequence[0]) == 0
299       && boost::asio::buffer_size(buffer_sequence[1]) == 0;
300   }
301 
validate(const boost::array<Elem,2> & buffer_sequence)302   static void validate(const boost::array<Elem, 2>& buffer_sequence)
303   {
304     boost::asio::buffer_cast<const void*>(buffer_sequence[0]);
305     boost::asio::buffer_cast<const void*>(buffer_sequence[1]);
306   }
307 
first(const boost::array<Elem,2> & buffer_sequence)308   static Buffer first(const boost::array<Elem, 2>& buffer_sequence)
309   {
310     return Buffer(boost::asio::buffer_size(buffer_sequence[0]) != 0
311         ? buffer_sequence[0] : buffer_sequence[1]);
312   }
313 
314 private:
315   native_buffer_type buffers_[2];
316   std::size_t total_buffer_size_;
317 };
318 
319 #if defined(BOOST_ASIO_HAS_STD_ARRAY)
320 
321 template <typename Buffer, typename Elem>
322 class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
323   : buffer_sequence_adapter_base
324 {
325 public:
buffer_sequence_adapter(const std::array<Elem,2> & buffer_sequence)326   explicit buffer_sequence_adapter(
327       const std::array<Elem, 2>& buffer_sequence)
328   {
329     init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
330     init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
331     total_buffer_size_ = boost::asio::buffer_size(buffer_sequence[0])
332       + boost::asio::buffer_size(buffer_sequence[1]);
333   }
334 
buffers()335   native_buffer_type* buffers()
336   {
337     return buffers_;
338   }
339 
count() const340   std::size_t count() const
341   {
342     return 2;
343   }
344 
all_empty() const345   bool all_empty() const
346   {
347     return total_buffer_size_ == 0;
348   }
349 
all_empty(const std::array<Elem,2> & buffer_sequence)350   static bool all_empty(const std::array<Elem, 2>& buffer_sequence)
351   {
352     return boost::asio::buffer_size(buffer_sequence[0]) == 0
353       && boost::asio::buffer_size(buffer_sequence[1]) == 0;
354   }
355 
validate(const std::array<Elem,2> & buffer_sequence)356   static void validate(const std::array<Elem, 2>& buffer_sequence)
357   {
358     boost::asio::buffer_cast<const void*>(buffer_sequence[0]);
359     boost::asio::buffer_cast<const void*>(buffer_sequence[1]);
360   }
361 
first(const std::array<Elem,2> & buffer_sequence)362   static Buffer first(const std::array<Elem, 2>& buffer_sequence)
363   {
364     return Buffer(boost::asio::buffer_size(buffer_sequence[0]) != 0
365         ? buffer_sequence[0] : buffer_sequence[1]);
366   }
367 
368 private:
369   native_buffer_type buffers_[2];
370   std::size_t total_buffer_size_;
371 };
372 
373 #endif // defined(BOOST_ASIO_HAS_STD_ARRAY)
374 
375 } // namespace detail
376 } // namespace asio
377 } // namespace boost
378 
379 #include <boost/asio/detail/pop_options.hpp>
380 
381 #if defined(BOOST_ASIO_HEADER_ONLY)
382 # include <boost/asio/detail/impl/buffer_sequence_adapter.ipp>
383 #endif // defined(BOOST_ASIO_HEADER_ONLY)
384 
385 #endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
386