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
32 namespace asio {
33
34 template <typename SyncReadStream, typename MutableBufferSequence,
35 typename CompletionCondition>
read(SyncReadStream & s,const MutableBufferSequence & buffers,CompletionCondition completion_condition,asio::error_code & ec)36 std::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
56 template <typename SyncReadStream, typename MutableBufferSequence>
read(SyncReadStream & s,const MutableBufferSequence & buffers)57 inline 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
65 template <typename SyncReadStream, typename MutableBufferSequence>
read(SyncReadStream & s,const MutableBufferSequence & buffers,asio::error_code & ec)66 inline 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
72 template <typename SyncReadStream, typename MutableBufferSequence,
73 typename CompletionCondition>
read(SyncReadStream & s,const MutableBufferSequence & buffers,CompletionCondition completion_condition)74 inline 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
84 namespace 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:
read_op(AsyncReadStream & stream,const MutableBufferSequence & buffers,CompletionCondition completion_condition,ReadHandler & handler)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
read_op(const read_op & other)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
read_op(read_op && other)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
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)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:
read_op(AsyncReadStream & stream,const asio::mutable_buffers_1 & buffers,CompletionCondition completion_condition,ReadHandler & handler)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
read_op(const read_op & other)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
read_op(read_op && other)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
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)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:
read_op(AsyncReadStream & stream,const boost::array<Elem,2> & buffers,CompletionCondition completion_condition,ReadHandler & handler)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
read_op(const read_op & other)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
read_op(read_op && other)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
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)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:
read_op(AsyncReadStream & stream,const std::array<Elem,2> & buffers,CompletionCondition completion_condition,ReadHandler & handler)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
read_op(const read_op & other)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
read_op(read_op && other)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
operator ()(const asio::error_code & ec,std::size_t bytes_transferred,int start=0)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>
asio_handler_allocate(std::size_t size,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)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>
asio_handler_deallocate(void * pointer,std::size_t size,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)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>
asio_handler_is_continuation(read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)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>
asio_handler_invoke(Function & function,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)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>
asio_handler_invoke(const Function & function,read_op<AsyncReadStream,MutableBufferSequence,CompletionCondition,ReadHandler> * this_handler)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
448 template <typename AsyncReadStream, typename MutableBufferSequence,
449 typename CompletionCondition, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,void (asio::error_code,std::size_t))450 inline ASIO_INITFN_RESULT_TYPE(ReadHandler,
451 void (asio::error_code, std::size_t))
452 async_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
473 template <typename AsyncReadStream, typename MutableBufferSequence,
474 typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,void (asio::error_code,std::size_t))475 inline ASIO_INITFN_RESULT_TYPE(ReadHandler,
476 void (asio::error_code, std::size_t))
477 async_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