1 //
2 // detail/consuming_buffers.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_CONSUMING_BUFFERS_HPP
12 #define ASIO_DETAIL_CONSUMING_BUFFERS_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 <cstddef>
20 #include "asio/buffer.hpp"
21 #include "asio/detail/buffer_sequence_adapter.hpp"
22 #include "asio/detail/limits.hpp"
23 
24 #include "asio/detail/push_options.hpp"
25 
26 namespace asio {
27 namespace detail {
28 
29 
30 // A buffer sequence used to represent a subsequence of the buffers.
31 template <typename Buffer>
32 struct prepared_buffers
33 {
34   typedef Buffer value_type;
35   typedef const Buffer* const_iterator;
36 
37   enum
38   {
39     max_buffers = buffer_sequence_adapter_base::max_buffers < 8
40       ? buffer_sequence_adapter_base::max_buffers : 8
41   };
42 
prepared_buffersasio::detail::prepared_buffers43   prepared_buffers() : count(0) {}
beginasio::detail::prepared_buffers44   const_iterator begin() const { return elems; }
endasio::detail::prepared_buffers45   const_iterator end() const { return elems + count; }
46 
47   Buffer elems[max_buffers];
48   std::size_t count;
49 };
50 
51 // A proxy for a sub-range in a list of buffers.
52 template <typename Buffer, typename Buffers, typename Buffer_Iterator>
53 class consuming_buffers
54 {
55 public:
56   // Construct to represent the entire list of buffers.
consuming_buffers(const Buffers & buffers)57   explicit consuming_buffers(const Buffers& buffers)
58     : buffers_(buffers),
59       total_size_(asio::buffer_size(buffers)),
60       total_consumed_(0),
61       next_elem_(0),
62       next_elem_offset_(0)
63   {
64   }
65 
66   // Determine if we are at the end of the buffers.
empty() const67   bool empty() const
68   {
69     return total_consumed_ >= total_size_;
70   }
71 
72   // Get the buffer for a single transfer, with a size.
prepare(std::size_t max_size)73   prepared_buffers<Buffer> prepare(std::size_t max_size)
74   {
75     prepared_buffers<Buffer> result;
76 
77     Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);
78     Buffer_Iterator end = asio::buffer_sequence_end(buffers_);
79 
80     std::advance(next, next_elem_);
81     std::size_t elem_offset = next_elem_offset_;
82     while (next != end && max_size > 0 && result.count < result.max_buffers)
83     {
84       Buffer next_buf = Buffer(*next) + elem_offset;
85       result.elems[result.count] = asio::buffer(next_buf, max_size);
86       max_size -= result.elems[result.count].size();
87       elem_offset = 0;
88       if (result.elems[result.count].size() > 0)
89         ++result.count;
90       ++next;
91     }
92 
93     return result;
94   }
95 
96   // Consume the specified number of bytes from the buffers.
consume(std::size_t size)97   void consume(std::size_t size)
98   {
99     total_consumed_ += size;
100 
101     Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);
102     Buffer_Iterator end = asio::buffer_sequence_end(buffers_);
103 
104     std::advance(next, next_elem_);
105     while (next != end && size > 0)
106     {
107       Buffer next_buf = Buffer(*next) + next_elem_offset_;
108       if (size < next_buf.size())
109       {
110         next_elem_offset_ += size;
111         size = 0;
112       }
113       else
114       {
115         size -= next_buf.size();
116         next_elem_offset_ = 0;
117         ++next_elem_;
118         ++next;
119       }
120     }
121   }
122 
123   // Get the total number of bytes consumed from the buffers.
total_consumed() const124   std::size_t total_consumed() const
125   {
126     return total_consumed_;
127   }
128 
129 private:
130   Buffers buffers_;
131   std::size_t total_size_;
132   std::size_t total_consumed_;
133   std::size_t next_elem_;
134   std::size_t next_elem_offset_;
135 };
136 
137 // Base class of all consuming_buffers specialisations for single buffers.
138 template <typename Buffer>
139 class consuming_single_buffer
140 {
141 public:
142   // Construct to represent the entire list of buffers.
143   template <typename Buffer1>
consuming_single_buffer(const Buffer1 & buffer)144   explicit consuming_single_buffer(const Buffer1& buffer)
145     : buffer_(buffer),
146       total_consumed_(0)
147   {
148   }
149 
150   // Determine if we are at the end of the buffers.
empty() const151   bool empty() const
152   {
153     return total_consumed_ >= buffer_.size();
154   }
155 
156   // Get the buffer for a single transfer, with a size.
prepare(std::size_t max_size)157   Buffer prepare(std::size_t max_size)
158   {
159     return asio::buffer(buffer_ + total_consumed_, max_size);
160   }
161 
162   // Consume the specified number of bytes from the buffers.
consume(std::size_t size)163   void consume(std::size_t size)
164   {
165     total_consumed_ += size;
166   }
167 
168   // Get the total number of bytes consumed from the buffers.
total_consumed() const169   std::size_t total_consumed() const
170   {
171     return total_consumed_;
172   }
173 
174 private:
175   Buffer buffer_;
176   std::size_t total_consumed_;
177 };
178 
179 template <>
180 class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*>
181   : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>
182 {
183 public:
consuming_buffers(const mutable_buffer & buffer)184   explicit consuming_buffers(const mutable_buffer& buffer)
185     : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)
186   {
187   }
188 };
189 
190 template <>
191 class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*>
192   : public consuming_single_buffer<ASIO_CONST_BUFFER>
193 {
194 public:
consuming_buffers(const mutable_buffer & buffer)195   explicit consuming_buffers(const mutable_buffer& buffer)
196     : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
197   {
198   }
199 };
200 
201 template <>
202 class consuming_buffers<const_buffer, const_buffer, const const_buffer*>
203   : public consuming_single_buffer<ASIO_CONST_BUFFER>
204 {
205 public:
consuming_buffers(const const_buffer & buffer)206   explicit consuming_buffers(const const_buffer& buffer)
207     : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
208   {
209   }
210 };
211 
212 #if !defined(ASIO_NO_DEPRECATED)
213 
214 template <>
215 class consuming_buffers<mutable_buffer,
216     mutable_buffers_1, const mutable_buffer*>
217   : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>
218 {
219 public:
consuming_buffers(const mutable_buffers_1 & buffer)220   explicit consuming_buffers(const mutable_buffers_1& buffer)
221     : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)
222   {
223   }
224 };
225 
226 template <>
227 class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*>
228   : public consuming_single_buffer<ASIO_CONST_BUFFER>
229 {
230 public:
consuming_buffers(const mutable_buffers_1 & buffer)231   explicit consuming_buffers(const mutable_buffers_1& buffer)
232     : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
233   {
234   }
235 };
236 
237 template <>
238 class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*>
239   : public consuming_single_buffer<ASIO_CONST_BUFFER>
240 {
241 public:
consuming_buffers(const const_buffers_1 & buffer)242   explicit consuming_buffers(const const_buffers_1& buffer)
243     : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
244   {
245   }
246 };
247 
248 #endif // !defined(ASIO_NO_DEPRECATED)
249 
250 template <typename Buffer, typename Elem>
251 class consuming_buffers<Buffer, boost::array<Elem, 2>,
252     typename boost::array<Elem, 2>::const_iterator>
253 {
254 public:
255   // Construct to represent the entire list of buffers.
consuming_buffers(const boost::array<Elem,2> & buffers)256   explicit consuming_buffers(const boost::array<Elem, 2>& buffers)
257     : buffers_(buffers),
258       total_consumed_(0)
259   {
260   }
261 
262   // Determine if we are at the end of the buffers.
empty() const263   bool empty() const
264   {
265     return total_consumed_ >=
266       Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
267   }
268 
269   // Get the buffer for a single transfer, with a size.
prepare(std::size_t max_size)270   boost::array<Buffer, 2> prepare(std::size_t max_size)
271   {
272     boost::array<Buffer, 2> result = {{
273       Buffer(buffers_[0]), Buffer(buffers_[1]) }};
274     std::size_t buffer0_size = result[0].size();
275     result[0] = asio::buffer(result[0] + total_consumed_, max_size);
276     result[1] = asio::buffer(
277         result[1] + (total_consumed_ < buffer0_size
278           ? 0 : total_consumed_ - buffer0_size),
279         max_size - result[0].size());
280     return result;
281   }
282 
283   // Consume the specified number of bytes from the buffers.
consume(std::size_t size)284   void consume(std::size_t size)
285   {
286     total_consumed_ += size;
287   }
288 
289   // Get the total number of bytes consumed from the buffers.
total_consumed() const290   std::size_t total_consumed() const
291   {
292     return total_consumed_;
293   }
294 
295 private:
296   boost::array<Elem, 2> buffers_;
297   std::size_t total_consumed_;
298 };
299 
300 #if defined(ASIO_HAS_STD_ARRAY)
301 
302 template <typename Buffer, typename Elem>
303 class consuming_buffers<Buffer, std::array<Elem, 2>,
304     typename std::array<Elem, 2>::const_iterator>
305 {
306 public:
307   // Construct to represent the entire list of buffers.
consuming_buffers(const std::array<Elem,2> & buffers)308   explicit consuming_buffers(const std::array<Elem, 2>& buffers)
309     : buffers_(buffers),
310       total_consumed_(0)
311   {
312   }
313 
314   // Determine if we are at the end of the buffers.
empty() const315   bool empty() const
316   {
317     return total_consumed_ >=
318       Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
319   }
320 
321   // Get the buffer for a single transfer, with a size.
prepare(std::size_t max_size)322   std::array<Buffer, 2> prepare(std::size_t max_size)
323   {
324     std::array<Buffer, 2> result = {{
325       Buffer(buffers_[0]), Buffer(buffers_[1]) }};
326     std::size_t buffer0_size = result[0].size();
327     result[0] = asio::buffer(result[0] + total_consumed_, max_size);
328     result[1] = asio::buffer(
329         result[1] + (total_consumed_ < buffer0_size
330           ? 0 : total_consumed_ - buffer0_size),
331         max_size - result[0].size());
332     return result;
333   }
334 
335   // Consume the specified number of bytes from the buffers.
consume(std::size_t size)336   void consume(std::size_t size)
337   {
338     total_consumed_ += size;
339   }
340 
341   // Get the total number of bytes consumed from the buffers.
total_consumed() const342   std::size_t total_consumed() const
343   {
344     return total_consumed_;
345   }
346 
347 private:
348   std::array<Elem, 2> buffers_;
349   std::size_t total_consumed_;
350 };
351 
352 #endif // defined(ASIO_HAS_STD_ARRAY)
353 
354 // Specialisation for null_buffers to ensure that the null_buffers type is
355 // always passed through to the underlying read or write operation.
356 template <typename Buffer>
357 class consuming_buffers<Buffer, null_buffers, const mutable_buffer*>
358   : public asio::null_buffers
359 {
360 public:
consuming_buffers(const null_buffers &)361   consuming_buffers(const null_buffers&)
362   {
363     // No-op.
364   }
365 
empty()366   bool empty()
367   {
368     return false;
369   }
370 
prepare(std::size_t)371   null_buffers prepare(std::size_t)
372   {
373     return null_buffers();
374   }
375 
consume(std::size_t)376   void consume(std::size_t)
377   {
378     // No-op.
379   }
380 
total_consume() const381   std::size_t total_consume() const
382   {
383     return 0;
384   }
385 };
386 
387 } // namespace detail
388 } // namespace asio
389 
390 #include "asio/detail/pop_options.hpp"
391 
392 #endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP
393