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
22namespace asio {
23namespace detail {
24
25class buffer_sequence_adapter_base
26{
27protected:
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
33  static void init_iov_base(void*& base, void* addr)
34  {
35    base = addr;
36  }
37
38  template <typename T>
39  static void init_iov_base(T& base, void* addr)
40  {
41    base = static_cast<T>(addr);
42  }
43
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
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.
61template <typename Buffer, typename Buffers>
62class buffer_sequence_adapter
63  : buffer_sequence_adapter_base
64{
65public:
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
79  native_buffer_type* buffers()
80  {
81    return buffers_;
82  }
83
84  std::size_t count() const
85  {
86    return count_;
87  }
88
89  bool all_empty() const
90  {
91    return total_buffer_size_ == 0;
92  }
93
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
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
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
129private:
130  native_buffer_type buffers_[max_buffers];
131  std::size_t count_;
132  std::size_t total_buffer_size_;
133};
134
135template <typename Buffer>
136class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1>
137  : buffer_sequence_adapter_base
138{
139public:
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
147  native_buffer_type* buffers()
148  {
149    return &buffer_;
150  }
151
152  std::size_t count() const
153  {
154    return 1;
155  }
156
157  bool all_empty() const
158  {
159    return total_buffer_size_ == 0;
160  }
161
162  static bool all_empty(const asio::mutable_buffers_1& buffer_sequence)
163  {
164    return asio::buffer_size(buffer_sequence) == 0;
165  }
166
167  static void validate(const asio::mutable_buffers_1& buffer_sequence)
168  {
169    asio::buffer_cast<const void*>(buffer_sequence);
170  }
171
172  static Buffer first(const asio::mutable_buffers_1& buffer_sequence)
173  {
174    return Buffer(buffer_sequence);
175  }
176
177private:
178  native_buffer_type buffer_;
179  std::size_t total_buffer_size_;
180};
181
182template <typename Buffer>
183class buffer_sequence_adapter<Buffer, asio::const_buffers_1>
184  : buffer_sequence_adapter_base
185{
186public:
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
194  native_buffer_type* buffers()
195  {
196    return &buffer_;
197  }
198
199  std::size_t count() const
200  {
201    return 1;
202  }
203
204  bool all_empty() const
205  {
206    return total_buffer_size_ == 0;
207  }
208
209  static bool all_empty(const asio::const_buffers_1& buffer_sequence)
210  {
211    return asio::buffer_size(buffer_sequence) == 0;
212  }
213
214  static void validate(const asio::const_buffers_1& buffer_sequence)
215  {
216    asio::buffer_cast<const void*>(buffer_sequence);
217  }
218
219  static Buffer first(const asio::const_buffers_1& buffer_sequence)
220  {
221    return Buffer(buffer_sequence);
222  }
223
224private:
225  native_buffer_type buffer_;
226  std::size_t total_buffer_size_;
227};
228
229template <typename Buffer, typename Elem>
230class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
231  : buffer_sequence_adapter_base
232{
233public:
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
243  native_buffer_type* buffers()
244  {
245    return buffers_;
246  }
247
248  std::size_t count() const
249  {
250    return 2;
251  }
252
253  bool all_empty() const
254  {
255    return total_buffer_size_ == 0;
256  }
257
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
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
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
276private:
277  native_buffer_type buffers_[2];
278  std::size_t total_buffer_size_;
279};
280
281
282template <typename Buffer, typename Elem>
283class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
284  : buffer_sequence_adapter_base
285{
286public:
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
296  native_buffer_type* buffers()
297  {
298    return buffers_;
299  }
300
301  std::size_t count() const
302  {
303    return 2;
304  }
305
306  bool all_empty() const
307  {
308    return total_buffer_size_ == 0;
309  }
310
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
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
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
329private:
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