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 ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
12 #define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
13 
14 
15 #include "asio/detail/config.hpp"
16 #include "asio/buffer.hpp"
17 #include "asio/detail/array_fwd.hpp"
18 #include "asio/detail/socket_types.hpp"
19 
20 #include "asio/detail/push_options.hpp"
21 
22 namespace asio {
23 namespace detail {
24 
25 class buffer_sequence_adapter_base
26 {
27 protected:
28   // The maximum number of buffers to support in a single operation.
29   enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
30 
31   typedef iovec native_buffer_type;
32 
init_iov_base(void * & base,void * addr)33   static void init_iov_base(void*& base, void* addr)
34   {
35     base = addr;
36   }
37 
38   template <typename T>
init_iov_base(T & base,void * addr)39   static void init_iov_base(T& base, void* addr)
40   {
41     base = static_cast<T>(addr);
42   }
43 
init_native_buffer(iovec & iov,const asio::mutable_buffer & buffer)44   static void init_native_buffer(iovec& iov,
45       const asio::mutable_buffer& buffer)
46   {
47     init_iov_base(iov.iov_base, asio::buffer_cast<void*>(buffer));
48     iov.iov_len = asio::buffer_size(buffer);
49   }
50 
init_native_buffer(iovec & iov,const asio::const_buffer & buffer)51   static void init_native_buffer(iovec& iov,
52       const asio::const_buffer& buffer)
53   {
54     init_iov_base(iov.iov_base, const_cast<void*>(
55           asio::buffer_cast<const void*>(buffer)));
56     iov.iov_len = asio::buffer_size(buffer);
57   }
58 };
59 
60 // Helper class to translate buffers into the native buffer representation.
61 template <typename Buffer, typename Buffers>
62 class buffer_sequence_adapter
63   : buffer_sequence_adapter_base
64 {
65 public:
buffer_sequence_adapter(const Buffers & buffer_sequence)66   explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
67     : count_(0), total_buffer_size_(0)
68   {
69     typename Buffers::const_iterator iter = buffer_sequence.begin();
70     typename Buffers::const_iterator end = buffer_sequence.end();
71     for (; iter != end && count_ < max_buffers; ++iter, ++count_)
72     {
73       Buffer buffer(*iter);
74       init_native_buffer(buffers_[count_], buffer);
75       total_buffer_size_ += asio::buffer_size(buffer);
76     }
77   }
78 
buffers()79   native_buffer_type* buffers()
80   {
81     return buffers_;
82   }
83 
count() const84   std::size_t count() const
85   {
86     return count_;
87   }
88 
all_empty() const89   bool all_empty() const
90   {
91     return total_buffer_size_ == 0;
92   }
93 
all_empty(const Buffers & buffer_sequence)94   static bool all_empty(const Buffers& buffer_sequence)
95   {
96     typename Buffers::const_iterator iter = buffer_sequence.begin();
97     typename Buffers::const_iterator end = buffer_sequence.end();
98     std::size_t i = 0;
99     for (; iter != end && i < max_buffers; ++iter, ++i)
100       if (asio::buffer_size(Buffer(*iter)) > 0)
101         return false;
102     return true;
103   }
104 
validate(const Buffers & buffer_sequence)105   static void validate(const Buffers& buffer_sequence)
106   {
107     typename Buffers::const_iterator iter = buffer_sequence.begin();
108     typename Buffers::const_iterator end = buffer_sequence.end();
109     for (; iter != end; ++iter)
110     {
111       Buffer buffer(*iter);
112       asio::buffer_cast<const void*>(buffer);
113     }
114   }
115 
first(const Buffers & buffer_sequence)116   static Buffer first(const Buffers& buffer_sequence)
117   {
118     typename Buffers::const_iterator iter = buffer_sequence.begin();
119     typename Buffers::const_iterator end = buffer_sequence.end();
120     for (; iter != end; ++iter)
121     {
122       Buffer buffer(*iter);
123       if (asio::buffer_size(buffer) != 0)
124         return buffer;
125     }
126     return Buffer();
127   }
128 
129 private:
130   native_buffer_type buffers_[max_buffers];
131   std::size_t count_;
132   std::size_t total_buffer_size_;
133 };
134 
135 template <typename Buffer>
136 class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1>
137   : buffer_sequence_adapter_base
138 {
139 public:
buffer_sequence_adapter(const asio::mutable_buffers_1 & buffer_sequence)140   explicit buffer_sequence_adapter(
141       const asio::mutable_buffers_1& buffer_sequence)
142   {
143     init_native_buffer(buffer_, Buffer(buffer_sequence));
144     total_buffer_size_ = asio::buffer_size(buffer_sequence);
145   }
146 
buffers()147   native_buffer_type* buffers()
148   {
149     return &buffer_;
150   }
151 
count() const152   std::size_t count() const
153   {
154     return 1;
155   }
156 
all_empty() const157   bool all_empty() const
158   {
159     return total_buffer_size_ == 0;
160   }
161 
all_empty(const asio::mutable_buffers_1 & buffer_sequence)162   static bool all_empty(const asio::mutable_buffers_1& buffer_sequence)
163   {
164     return asio::buffer_size(buffer_sequence) == 0;
165   }
166 
validate(const asio::mutable_buffers_1 & buffer_sequence)167   static void validate(const asio::mutable_buffers_1& buffer_sequence)
168   {
169     asio::buffer_cast<const void*>(buffer_sequence);
170   }
171 
first(const asio::mutable_buffers_1 & buffer_sequence)172   static Buffer first(const asio::mutable_buffers_1& buffer_sequence)
173   {
174     return Buffer(buffer_sequence);
175   }
176 
177 private:
178   native_buffer_type buffer_;
179   std::size_t total_buffer_size_;
180 };
181 
182 template <typename Buffer>
183 class buffer_sequence_adapter<Buffer, asio::const_buffers_1>
184   : buffer_sequence_adapter_base
185 {
186 public:
buffer_sequence_adapter(const asio::const_buffers_1 & buffer_sequence)187   explicit buffer_sequence_adapter(
188       const asio::const_buffers_1& buffer_sequence)
189   {
190     init_native_buffer(buffer_, Buffer(buffer_sequence));
191     total_buffer_size_ = asio::buffer_size(buffer_sequence);
192   }
193 
buffers()194   native_buffer_type* buffers()
195   {
196     return &buffer_;
197   }
198 
count() const199   std::size_t count() const
200   {
201     return 1;
202   }
203 
all_empty() const204   bool all_empty() const
205   {
206     return total_buffer_size_ == 0;
207   }
208 
all_empty(const asio::const_buffers_1 & buffer_sequence)209   static bool all_empty(const asio::const_buffers_1& buffer_sequence)
210   {
211     return asio::buffer_size(buffer_sequence) == 0;
212   }
213 
validate(const asio::const_buffers_1 & buffer_sequence)214   static void validate(const asio::const_buffers_1& buffer_sequence)
215   {
216     asio::buffer_cast<const void*>(buffer_sequence);
217   }
218 
first(const asio::const_buffers_1 & buffer_sequence)219   static Buffer first(const asio::const_buffers_1& buffer_sequence)
220   {
221     return Buffer(buffer_sequence);
222   }
223 
224 private:
225   native_buffer_type buffer_;
226   std::size_t total_buffer_size_;
227 };
228 
229 template <typename Buffer, typename Elem>
230 class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
231   : buffer_sequence_adapter_base
232 {
233 public:
buffer_sequence_adapter(const boost::array<Elem,2> & buffer_sequence)234   explicit buffer_sequence_adapter(
235       const boost::array<Elem, 2>& buffer_sequence)
236   {
237     init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
238     init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
239     total_buffer_size_ = asio::buffer_size(buffer_sequence[0])
240       + asio::buffer_size(buffer_sequence[1]);
241   }
242 
buffers()243   native_buffer_type* buffers()
244   {
245     return buffers_;
246   }
247 
count() const248   std::size_t count() const
249   {
250     return 2;
251   }
252 
all_empty() const253   bool all_empty() const
254   {
255     return total_buffer_size_ == 0;
256   }
257 
all_empty(const boost::array<Elem,2> & buffer_sequence)258   static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)
259   {
260     return asio::buffer_size(buffer_sequence[0]) == 0
261       && asio::buffer_size(buffer_sequence[1]) == 0;
262   }
263 
validate(const boost::array<Elem,2> & buffer_sequence)264   static void validate(const boost::array<Elem, 2>& buffer_sequence)
265   {
266     asio::buffer_cast<const void*>(buffer_sequence[0]);
267     asio::buffer_cast<const void*>(buffer_sequence[1]);
268   }
269 
first(const boost::array<Elem,2> & buffer_sequence)270   static Buffer first(const boost::array<Elem, 2>& buffer_sequence)
271   {
272     return Buffer(asio::buffer_size(buffer_sequence[0]) != 0
273         ? buffer_sequence[0] : buffer_sequence[1]);
274   }
275 
276 private:
277   native_buffer_type buffers_[2];
278   std::size_t total_buffer_size_;
279 };
280 
281 
282 template <typename Buffer, typename Elem>
283 class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
284   : buffer_sequence_adapter_base
285 {
286 public:
buffer_sequence_adapter(const std::array<Elem,2> & buffer_sequence)287   explicit buffer_sequence_adapter(
288       const std::array<Elem, 2>& buffer_sequence)
289   {
290     init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
291     init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
292     total_buffer_size_ = asio::buffer_size(buffer_sequence[0])
293       + asio::buffer_size(buffer_sequence[1]);
294   }
295 
buffers()296   native_buffer_type* buffers()
297   {
298     return buffers_;
299   }
300 
count() const301   std::size_t count() const
302   {
303     return 2;
304   }
305 
all_empty() const306   bool all_empty() const
307   {
308     return total_buffer_size_ == 0;
309   }
310 
all_empty(const std::array<Elem,2> & buffer_sequence)311   static bool all_empty(const std::array<Elem, 2>& buffer_sequence)
312   {
313     return asio::buffer_size(buffer_sequence[0]) == 0
314       && asio::buffer_size(buffer_sequence[1]) == 0;
315   }
316 
validate(const std::array<Elem,2> & buffer_sequence)317   static void validate(const std::array<Elem, 2>& buffer_sequence)
318   {
319     asio::buffer_cast<const void*>(buffer_sequence[0]);
320     asio::buffer_cast<const void*>(buffer_sequence[1]);
321   }
322 
first(const std::array<Elem,2> & buffer_sequence)323   static Buffer first(const std::array<Elem, 2>& buffer_sequence)
324   {
325     return Buffer(asio::buffer_size(buffer_sequence[0]) != 0
326         ? buffer_sequence[0] : buffer_sequence[1]);
327   }
328 
329 private:
330   native_buffer_type buffers_[2];
331   std::size_t total_buffer_size_;
332 };
333 
334 
335 } // namespace detail
336 } // namespace asio
337 
338 #include "asio/detail/pop_options.hpp"
339 
340 # include "asio/detail/impl/buffer_sequence_adapter.ipp"
341 
342 #endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
343