1//
2// impl/read.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_IMPL_READ_HPP
12#define ASIO_IMPL_READ_HPP
13
14
15#include <algorithm>
16#include "asio/buffer.hpp"
17#include "asio/completion_condition.hpp"
18#include "asio/detail/array_fwd.hpp"
19#include "asio/detail/base_from_completion_cond.hpp"
20#include "asio/detail/bind_handler.hpp"
21#include "asio/detail/consuming_buffers.hpp"
22#include "asio/detail/dependent_type.hpp"
23#include "asio/detail/handler_alloc_helpers.hpp"
24#include "asio/detail/handler_cont_helpers.hpp"
25#include "asio/detail/handler_invoke_helpers.hpp"
26#include "asio/detail/handler_type_requirements.hpp"
27#include "asio/detail/throw_error.hpp"
28#include "asio/error.hpp"
29
30#include "asio/detail/push_options.hpp"
31
32namespace asio {
33
34template <typename SyncReadStream, typename MutableBufferSequence,
35    typename CompletionCondition>
36std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
37    CompletionCondition completion_condition, asio::error_code& ec)
38{
39  ec = asio::error_code();
40  asio::detail::consuming_buffers<
41    mutable_buffer, MutableBufferSequence> tmp(buffers);
42  std::size_t total_transferred = 0;
43  tmp.prepare(detail::adapt_completion_condition_result(
44        completion_condition(ec, total_transferred)));
45  while (tmp.begin() != tmp.end())
46  {
47    std::size_t bytes_transferred = s.read_some(tmp, ec);
48    tmp.consume(bytes_transferred);
49    total_transferred += bytes_transferred;
50    tmp.prepare(detail::adapt_completion_condition_result(
51          completion_condition(ec, total_transferred)));
52  }
53  return total_transferred;
54}
55
56template <typename SyncReadStream, typename MutableBufferSequence>
57inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers)
58{
59  asio::error_code ec;
60  std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
61  asio::detail::throw_error(ec, "read");
62  return bytes_transferred;
63}
64
65template <typename SyncReadStream, typename MutableBufferSequence>
66inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
67    asio::error_code& ec)
68{
69  return read(s, buffers, transfer_all(), ec);
70}
71
72template <typename SyncReadStream, typename MutableBufferSequence,
73    typename CompletionCondition>
74inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
75    CompletionCondition completion_condition)
76{
77  asio::error_code ec;
78  std::size_t bytes_transferred = read(s, buffers, completion_condition, ec);
79  asio::detail::throw_error(ec, "read");
80  return bytes_transferred;
81}
82
83
84namespace detail
85{
86  template <typename AsyncReadStream, typename MutableBufferSequence,
87      typename CompletionCondition, typename ReadHandler>
88  class read_op
89    : detail::base_from_completion_cond<CompletionCondition>
90  {
91  public:
92    read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers,
93        CompletionCondition completion_condition, ReadHandler& handler)
94      : detail::base_from_completion_cond<
95          CompletionCondition>(completion_condition),
96        stream_(stream),
97        buffers_(buffers),
98        start_(0),
99        total_transferred_(0),
100        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
101    {
102    }
103
104    read_op(const read_op& other)
105      : detail::base_from_completion_cond<CompletionCondition>(other),
106        stream_(other.stream_),
107        buffers_(other.buffers_),
108        start_(other.start_),
109        total_transferred_(other.total_transferred_),
110        handler_(other.handler_)
111    {
112    }
113
114    read_op(read_op&& other)
115      : detail::base_from_completion_cond<CompletionCondition>(other),
116        stream_(other.stream_),
117        buffers_(other.buffers_),
118        start_(other.start_),
119        total_transferred_(other.total_transferred_),
120        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
121    {
122    }
123
124    void operator()(const asio::error_code& ec,
125        std::size_t bytes_transferred, int start = 0)
126    {
127      switch (start_ = start)
128      {
129        case 1:
130        buffers_.prepare(this->check_for_completion(ec, total_transferred_));
131        for (;;)
132        {
133          stream_.async_read_some(buffers_,
134              ASIO_MOVE_CAST(read_op)(*this));
135          return; default:
136          total_transferred_ += bytes_transferred;
137          buffers_.consume(bytes_transferred);
138          buffers_.prepare(this->check_for_completion(ec, total_transferred_));
139          if ((!ec && bytes_transferred == 0)
140              || buffers_.begin() == buffers_.end())
141            break;
142        }
143
144        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
145      }
146    }
147
148  //private:
149    AsyncReadStream& stream_;
150    asio::detail::consuming_buffers<
151      mutable_buffer, MutableBufferSequence> buffers_;
152    int start_;
153    std::size_t total_transferred_;
154    ReadHandler handler_;
155  };
156
157  template <typename AsyncReadStream,
158      typename CompletionCondition, typename ReadHandler>
159  class read_op<AsyncReadStream, asio::mutable_buffers_1,
160      CompletionCondition, ReadHandler>
161    : detail::base_from_completion_cond<CompletionCondition>
162  {
163  public:
164    read_op(AsyncReadStream& stream,
165        const asio::mutable_buffers_1& buffers,
166        CompletionCondition completion_condition, ReadHandler& handler)
167      : detail::base_from_completion_cond<
168          CompletionCondition>(completion_condition),
169        stream_(stream),
170        buffer_(buffers),
171        start_(0),
172        total_transferred_(0),
173        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
174    {
175    }
176
177    read_op(const read_op& other)
178      : detail::base_from_completion_cond<CompletionCondition>(other),
179        stream_(other.stream_),
180        buffer_(other.buffer_),
181        start_(other.start_),
182        total_transferred_(other.total_transferred_),
183        handler_(other.handler_)
184    {
185    }
186
187    read_op(read_op&& other)
188      : detail::base_from_completion_cond<CompletionCondition>(other),
189        stream_(other.stream_),
190        buffer_(other.buffer_),
191        start_(other.start_),
192        total_transferred_(other.total_transferred_),
193        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
194    {
195    }
196
197    void operator()(const asio::error_code& ec,
198        std::size_t bytes_transferred, int start = 0)
199    {
200      std::size_t n = 0;
201      switch (start_ = start)
202      {
203        case 1:
204        n = this->check_for_completion(ec, total_transferred_);
205        for (;;)
206        {
207          stream_.async_read_some(
208              asio::buffer(buffer_ + total_transferred_, n),
209              ASIO_MOVE_CAST(read_op)(*this));
210          return; default:
211          total_transferred_ += bytes_transferred;
212          if ((!ec && bytes_transferred == 0)
213              || (n = this->check_for_completion(ec, total_transferred_)) == 0
214              || total_transferred_ == asio::buffer_size(buffer_))
215            break;
216        }
217
218        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
219      }
220    }
221
222  //private:
223    AsyncReadStream& stream_;
224    asio::mutable_buffer buffer_;
225    int start_;
226    std::size_t total_transferred_;
227    ReadHandler handler_;
228  };
229
230  template <typename AsyncReadStream, typename Elem,
231      typename CompletionCondition, typename ReadHandler>
232  class read_op<AsyncReadStream, boost::array<Elem, 2>,
233      CompletionCondition, ReadHandler>
234    : detail::base_from_completion_cond<CompletionCondition>
235  {
236  public:
237    read_op(AsyncReadStream& stream, const boost::array<Elem, 2>& buffers,
238        CompletionCondition completion_condition, ReadHandler& handler)
239      : detail::base_from_completion_cond<
240          CompletionCondition>(completion_condition),
241        stream_(stream),
242        buffers_(buffers),
243        start_(0),
244        total_transferred_(0),
245        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
246    {
247    }
248
249    read_op(const read_op& other)
250      : detail::base_from_completion_cond<CompletionCondition>(other),
251        stream_(other.stream_),
252        buffers_(other.buffers_),
253        start_(other.start_),
254        total_transferred_(other.total_transferred_),
255        handler_(other.handler_)
256    {
257    }
258
259    read_op(read_op&& other)
260      : detail::base_from_completion_cond<CompletionCondition>(other),
261        stream_(other.stream_),
262        buffers_(other.buffers_),
263        start_(other.start_),
264        total_transferred_(other.total_transferred_),
265        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
266    {
267    }
268
269    void operator()(const asio::error_code& ec,
270        std::size_t bytes_transferred, int start = 0)
271    {
272      typename asio::detail::dependent_type<Elem,
273          boost::array<asio::mutable_buffer, 2> >::type bufs = {{
274        asio::mutable_buffer(buffers_[0]),
275        asio::mutable_buffer(buffers_[1]) }};
276      std::size_t buffer_size0 = asio::buffer_size(bufs[0]);
277      std::size_t buffer_size1 = asio::buffer_size(bufs[1]);
278      std::size_t n = 0;
279      switch (start_ = start)
280      {
281        case 1:
282        n = this->check_for_completion(ec, total_transferred_);
283        for (;;)
284        {
285          bufs[0] = asio::buffer(bufs[0] + total_transferred_, n);
286          bufs[1] = asio::buffer(
287              bufs[1] + (total_transferred_ < buffer_size0
288                ? 0 : total_transferred_ - buffer_size0),
289              n - asio::buffer_size(bufs[0]));
290          stream_.async_read_some(bufs, ASIO_MOVE_CAST(read_op)(*this));
291          return; default:
292          total_transferred_ += bytes_transferred;
293          if ((!ec && bytes_transferred == 0)
294              || (n = this->check_for_completion(ec, total_transferred_)) == 0
295              || total_transferred_ == buffer_size0 + buffer_size1)
296            break;
297        }
298
299        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
300      }
301    }
302
303  //private:
304    AsyncReadStream& stream_;
305    boost::array<Elem, 2> buffers_;
306    int start_;
307    std::size_t total_transferred_;
308    ReadHandler handler_;
309  };
310
311
312  template <typename AsyncReadStream, typename Elem,
313      typename CompletionCondition, typename ReadHandler>
314  class read_op<AsyncReadStream, std::array<Elem, 2>,
315      CompletionCondition, ReadHandler>
316    : detail::base_from_completion_cond<CompletionCondition>
317  {
318  public:
319    read_op(AsyncReadStream& stream, const std::array<Elem, 2>& buffers,
320        CompletionCondition completion_condition, ReadHandler& handler)
321      : detail::base_from_completion_cond<
322          CompletionCondition>(completion_condition),
323        stream_(stream),
324        buffers_(buffers),
325        start_(0),
326        total_transferred_(0),
327        handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
328    {
329    }
330
331    read_op(const read_op& other)
332      : detail::base_from_completion_cond<CompletionCondition>(other),
333        stream_(other.stream_),
334        buffers_(other.buffers_),
335        start_(other.start_),
336        total_transferred_(other.total_transferred_),
337        handler_(other.handler_)
338    {
339    }
340
341    read_op(read_op&& other)
342      : detail::base_from_completion_cond<CompletionCondition>(other),
343        stream_(other.stream_),
344        buffers_(other.buffers_),
345        start_(other.start_),
346        total_transferred_(other.total_transferred_),
347        handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
348    {
349    }
350
351    void operator()(const asio::error_code& ec,
352        std::size_t bytes_transferred, int start = 0)
353    {
354      typename asio::detail::dependent_type<Elem,
355          std::array<asio::mutable_buffer, 2> >::type bufs = {{
356        asio::mutable_buffer(buffers_[0]),
357        asio::mutable_buffer(buffers_[1]) }};
358      std::size_t buffer_size0 = asio::buffer_size(bufs[0]);
359      std::size_t buffer_size1 = asio::buffer_size(bufs[1]);
360      std::size_t n = 0;
361      switch (start_ = start)
362      {
363        case 1:
364        n = this->check_for_completion(ec, total_transferred_);
365        for (;;)
366        {
367          bufs[0] = asio::buffer(bufs[0] + total_transferred_, n);
368          bufs[1] = asio::buffer(
369              bufs[1] + (total_transferred_ < buffer_size0
370                ? 0 : total_transferred_ - buffer_size0),
371              n - asio::buffer_size(bufs[0]));
372          stream_.async_read_some(bufs, ASIO_MOVE_CAST(read_op)(*this));
373          return; default:
374          total_transferred_ += bytes_transferred;
375          if ((!ec && bytes_transferred == 0)
376              || (n = this->check_for_completion(ec, total_transferred_)) == 0
377              || total_transferred_ == buffer_size0 + buffer_size1)
378            break;
379        }
380
381        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
382      }
383    }
384
385  //private:
386    AsyncReadStream& stream_;
387    std::array<Elem, 2> buffers_;
388    int start_;
389    std::size_t total_transferred_;
390    ReadHandler handler_;
391  };
392
393
394  template <typename AsyncReadStream, typename MutableBufferSequence,
395      typename CompletionCondition, typename ReadHandler>
396  inline void* asio_handler_allocate(std::size_t size,
397      read_op<AsyncReadStream, MutableBufferSequence,
398        CompletionCondition, ReadHandler>* this_handler)
399  {
400    return asio_handler_alloc_helpers::allocate(
401        size, this_handler->handler_);
402  }
403
404  template <typename AsyncReadStream, typename MutableBufferSequence,
405      typename CompletionCondition, typename ReadHandler>
406  inline void asio_handler_deallocate(void* pointer, std::size_t size,
407      read_op<AsyncReadStream, MutableBufferSequence,
408        CompletionCondition, ReadHandler>* this_handler)
409  {
410    asio_handler_alloc_helpers::deallocate(
411        pointer, size, this_handler->handler_);
412  }
413
414  template <typename AsyncReadStream, typename MutableBufferSequence,
415      typename CompletionCondition, typename ReadHandler>
416  inline bool asio_handler_is_continuation(
417      read_op<AsyncReadStream, MutableBufferSequence,
418        CompletionCondition, ReadHandler>* this_handler)
419  {
420    return this_handler->start_ == 0 ? true
421      : asio_handler_cont_helpers::is_continuation(
422          this_handler->handler_);
423  }
424
425  template <typename Function, typename AsyncReadStream,
426      typename MutableBufferSequence, typename CompletionCondition,
427      typename ReadHandler>
428  inline void asio_handler_invoke(Function& function,
429      read_op<AsyncReadStream, MutableBufferSequence,
430        CompletionCondition, ReadHandler>* this_handler)
431  {
432    asio_handler_invoke_helpers::invoke(
433        function, this_handler->handler_);
434  }
435
436  template <typename Function, typename AsyncReadStream,
437      typename MutableBufferSequence, typename CompletionCondition,
438      typename ReadHandler>
439  inline void asio_handler_invoke(const Function& function,
440      read_op<AsyncReadStream, MutableBufferSequence,
441        CompletionCondition, ReadHandler>* this_handler)
442  {
443    asio_handler_invoke_helpers::invoke(
444        function, this_handler->handler_);
445  }
446} // namespace detail
447
448template <typename AsyncReadStream, typename MutableBufferSequence,
449    typename CompletionCondition, typename ReadHandler>
450inline ASIO_INITFN_RESULT_TYPE(ReadHandler,
451    void (asio::error_code, std::size_t))
452async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
453    CompletionCondition completion_condition,
454    ASIO_MOVE_ARG(ReadHandler) handler)
455{
456  // If you get an error on the following line it means that your handler does
457  // not meet the documented type requirements for a ReadHandler.
458  ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
459
460  detail::async_result_init<
461    ReadHandler, void (asio::error_code, std::size_t)> init(
462      ASIO_MOVE_CAST(ReadHandler)(handler));
463
464  detail::read_op<AsyncReadStream, MutableBufferSequence,
465    CompletionCondition, ASIO_HANDLER_TYPE(
466      ReadHandler, void (asio::error_code, std::size_t))>(
467        s, buffers, completion_condition, init.handler)(
468          asio::error_code(), 0, 1);
469
470  return init.result.get();
471}
472
473template <typename AsyncReadStream, typename MutableBufferSequence,
474    typename ReadHandler>
475inline ASIO_INITFN_RESULT_TYPE(ReadHandler,
476    void (asio::error_code, std::size_t))
477async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
478    ASIO_MOVE_ARG(ReadHandler) handler)
479{
480  // If you get an error on the following line it means that your handler does
481  // not meet the documented type requirements for a ReadHandler.
482  ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
483
484  detail::async_result_init<
485    ReadHandler, void (asio::error_code, std::size_t)> init(
486      ASIO_MOVE_CAST(ReadHandler)(handler));
487
488  detail::read_op<AsyncReadStream, MutableBufferSequence,
489    detail::transfer_all_t, ASIO_HANDLER_TYPE(
490      ReadHandler, void (asio::error_code, std::size_t))>(
491        s, buffers, transfer_all(), init.handler)(
492          asio::error_code(), 0, 1);
493
494  return init.result.get();
495}
496
497
498} // namespace asio
499
500#include "asio/detail/pop_options.hpp"
501
502#endif // ASIO_IMPL_READ_HPP
503