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