1//
2// impl/read.hpp
3// ~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 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 BOOST_ASIO_IMPL_READ_HPP
12#define BOOST_ASIO_IMPL_READ_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <algorithm>
19#include <boost/asio/associator.hpp>
20#include <boost/asio/buffer.hpp>
21#include <boost/asio/detail/array_fwd.hpp>
22#include <boost/asio/detail/base_from_cancellation_state.hpp>
23#include <boost/asio/detail/base_from_completion_cond.hpp>
24#include <boost/asio/detail/bind_handler.hpp>
25#include <boost/asio/detail/consuming_buffers.hpp>
26#include <boost/asio/detail/dependent_type.hpp>
27#include <boost/asio/detail/handler_cont_helpers.hpp>
28#include <boost/asio/detail/handler_tracking.hpp>
29#include <boost/asio/detail/handler_type_requirements.hpp>
30#include <boost/asio/detail/non_const_lvalue.hpp>
31#include <boost/asio/detail/throw_error.hpp>
32#include <boost/asio/error.hpp>
33
34#include <boost/asio/detail/push_options.hpp>
35
36namespace boost {
37namespace asio {
38
39namespace detail
40{
41 template <typename SyncReadStream, typename MutableBufferSequence,
42 typename MutableBufferIterator, typename CompletionCondition>
43 std::size_t read_buffer_seq(SyncReadStream& s,
44 const MutableBufferSequence& buffers, const MutableBufferIterator&,
45 CompletionCondition completion_condition, boost::system::error_code& ec)
46 {
47 ec = boost::system::error_code();
48 boost::asio::detail::consuming_buffers<mutable_buffer,
49 MutableBufferSequence, MutableBufferIterator> tmp(buffers);
50 while (!tmp.empty())
51 {
52 if (std::size_t max_size = detail::adapt_completion_condition_result(
53 completion_condition(ec, tmp.total_consumed())))
54 tmp.consume(s.read_some(tmp.prepare(max_size), ec));
55 else
56 break;
57 }
58 return tmp.total_consumed();
59 }
60} // namespace detail
61
62template <typename SyncReadStream, typename MutableBufferSequence,
63 typename CompletionCondition>
64std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
65 CompletionCondition completion_condition, boost::system::error_code& ec,
66 constraint_t<
67 is_mutable_buffer_sequence<MutableBufferSequence>::value
68 >)
69{
70 return detail::read_buffer_seq(s, buffers,
71 boost::asio::buffer_sequence_begin(buffers),
72 static_cast<CompletionCondition&&>(completion_condition), ec);
73}
74
75template <typename SyncReadStream, typename MutableBufferSequence>
76inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
77 constraint_t<
78 is_mutable_buffer_sequence<MutableBufferSequence>::value
79 >)
80{
81 boost::system::error_code ec;
82 std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
83 boost::asio::detail::throw_error(err: ec, location: "read");
84 return bytes_transferred;
85}
86
87template <typename SyncReadStream, typename MutableBufferSequence>
88inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
89 boost::system::error_code& ec,
90 constraint_t<
91 is_mutable_buffer_sequence<MutableBufferSequence>::value
92 >)
93{
94 return read(s, buffers, transfer_all(), ec);
95}
96
97template <typename SyncReadStream, typename MutableBufferSequence,
98 typename CompletionCondition>
99inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
100 CompletionCondition completion_condition,
101 constraint_t<
102 is_mutable_buffer_sequence<MutableBufferSequence>::value
103 >)
104{
105 boost::system::error_code ec;
106 std::size_t bytes_transferred = read(s, buffers,
107 static_cast<CompletionCondition&&>(completion_condition), ec);
108 boost::asio::detail::throw_error(err: ec, location: "read");
109 return bytes_transferred;
110}
111
112#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
113
114template <typename SyncReadStream, typename DynamicBuffer_v1,
115 typename CompletionCondition>
116std::size_t read(SyncReadStream& s,
117 DynamicBuffer_v1&& buffers,
118 CompletionCondition completion_condition, boost::system::error_code& ec,
119 constraint_t<
120 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
121 >,
122 constraint_t<
123 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
124 >)
125{
126 decay_t<DynamicBuffer_v1> b(
127 static_cast<DynamicBuffer_v1&&>(buffers));
128
129 ec = boost::system::error_code();
130 std::size_t total_transferred = 0;
131 std::size_t max_size = detail::adapt_completion_condition_result(
132 completion_condition(ec, total_transferred));
133 std::size_t bytes_available = std::min<std::size_t>(
134 std::max<std::size_t>(512, b.capacity() - b.size()),
135 std::min<std::size_t>(max_size, b.max_size() - b.size()));
136 while (bytes_available > 0)
137 {
138 std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec);
139 b.commit(bytes_transferred);
140 total_transferred += bytes_transferred;
141 max_size = detail::adapt_completion_condition_result(
142 completion_condition(ec, total_transferred));
143 bytes_available = std::min<std::size_t>(
144 std::max<std::size_t>(512, b.capacity() - b.size()),
145 std::min<std::size_t>(max_size, b.max_size() - b.size()));
146 }
147 return total_transferred;
148}
149
150template <typename SyncReadStream, typename DynamicBuffer_v1>
151inline std::size_t read(SyncReadStream& s,
152 DynamicBuffer_v1&& buffers,
153 constraint_t<
154 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
155 >,
156 constraint_t<
157 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
158 >)
159{
160 boost::system::error_code ec;
161 std::size_t bytes_transferred = read(s,
162 static_cast<DynamicBuffer_v1&&>(buffers), transfer_all(), ec);
163 boost::asio::detail::throw_error(err: ec, location: "read");
164 return bytes_transferred;
165}
166
167template <typename SyncReadStream, typename DynamicBuffer_v1>
168inline std::size_t read(SyncReadStream& s,
169 DynamicBuffer_v1&& buffers,
170 boost::system::error_code& ec,
171 constraint_t<
172 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
173 >,
174 constraint_t<
175 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
176 >)
177{
178 return read(s, static_cast<DynamicBuffer_v1&&>(buffers),
179 transfer_all(), ec);
180}
181
182template <typename SyncReadStream, typename DynamicBuffer_v1,
183 typename CompletionCondition>
184inline std::size_t read(SyncReadStream& s,
185 DynamicBuffer_v1&& buffers,
186 CompletionCondition completion_condition,
187 constraint_t<
188 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
189 >,
190 constraint_t<
191 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
192 >)
193{
194 boost::system::error_code ec;
195 std::size_t bytes_transferred = read(s,
196 static_cast<DynamicBuffer_v1&&>(buffers),
197 static_cast<CompletionCondition&&>(completion_condition), ec);
198 boost::asio::detail::throw_error(err: ec, location: "read");
199 return bytes_transferred;
200}
201
202#if !defined(BOOST_ASIO_NO_EXTENSIONS)
203#if !defined(BOOST_ASIO_NO_IOSTREAM)
204
205template <typename SyncReadStream, typename Allocator,
206 typename CompletionCondition>
207inline std::size_t read(SyncReadStream& s,
208 boost::asio::basic_streambuf<Allocator>& b,
209 CompletionCondition completion_condition, boost::system::error_code& ec)
210{
211 return read(s, basic_streambuf_ref<Allocator>(b),
212 static_cast<CompletionCondition&&>(completion_condition), ec);
213}
214
215template <typename SyncReadStream, typename Allocator>
216inline std::size_t read(SyncReadStream& s,
217 boost::asio::basic_streambuf<Allocator>& b)
218{
219 return read(s, basic_streambuf_ref<Allocator>(b));
220}
221
222template <typename SyncReadStream, typename Allocator>
223inline std::size_t read(SyncReadStream& s,
224 boost::asio::basic_streambuf<Allocator>& b,
225 boost::system::error_code& ec)
226{
227 return read(s, basic_streambuf_ref<Allocator>(b), ec);
228}
229
230template <typename SyncReadStream, typename Allocator,
231 typename CompletionCondition>
232inline std::size_t read(SyncReadStream& s,
233 boost::asio::basic_streambuf<Allocator>& b,
234 CompletionCondition completion_condition)
235{
236 return read(s, basic_streambuf_ref<Allocator>(b),
237 static_cast<CompletionCondition&&>(completion_condition));
238}
239
240#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
241#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
242#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
243
244template <typename SyncReadStream, typename DynamicBuffer_v2,
245 typename CompletionCondition>
246std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
247 CompletionCondition completion_condition, boost::system::error_code& ec,
248 constraint_t<
249 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
250 >)
251{
252 DynamicBuffer_v2& b = buffers;
253
254 ec = boost::system::error_code();
255 std::size_t total_transferred = 0;
256 std::size_t max_size = detail::adapt_completion_condition_result(
257 completion_condition(ec, total_transferred));
258 std::size_t bytes_available = std::min<std::size_t>(
259 std::max<std::size_t>(512, b.capacity() - b.size()),
260 std::min<std::size_t>(max_size, b.max_size() - b.size()));
261 while (bytes_available > 0)
262 {
263 std::size_t pos = b.size();
264 b.grow(bytes_available);
265 std::size_t bytes_transferred = s.read_some(
266 b.data(pos, bytes_available), ec);
267 b.shrink(bytes_available - bytes_transferred);
268 total_transferred += bytes_transferred;
269 max_size = detail::adapt_completion_condition_result(
270 completion_condition(ec, total_transferred));
271 bytes_available = std::min<std::size_t>(
272 std::max<std::size_t>(512, b.capacity() - b.size()),
273 std::min<std::size_t>(max_size, b.max_size() - b.size()));
274 }
275 return total_transferred;
276}
277
278template <typename SyncReadStream, typename DynamicBuffer_v2>
279inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
280 constraint_t<
281 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
282 >)
283{
284 boost::system::error_code ec;
285 std::size_t bytes_transferred = read(s,
286 static_cast<DynamicBuffer_v2&&>(buffers), transfer_all(), ec);
287 boost::asio::detail::throw_error(err: ec, location: "read");
288 return bytes_transferred;
289}
290
291template <typename SyncReadStream, typename DynamicBuffer_v2>
292inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
293 boost::system::error_code& ec,
294 constraint_t<
295 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
296 >)
297{
298 return read(s, static_cast<DynamicBuffer_v2&&>(buffers),
299 transfer_all(), ec);
300}
301
302template <typename SyncReadStream, typename DynamicBuffer_v2,
303 typename CompletionCondition>
304inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,
305 CompletionCondition completion_condition,
306 constraint_t<
307 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
308 >)
309{
310 boost::system::error_code ec;
311 std::size_t bytes_transferred = read(s,
312 static_cast<DynamicBuffer_v2&&>(buffers),
313 static_cast<CompletionCondition&&>(completion_condition), ec);
314 boost::asio::detail::throw_error(err: ec, location: "read");
315 return bytes_transferred;
316}
317
318namespace detail
319{
320 template <typename AsyncReadStream, typename MutableBufferSequence,
321 typename MutableBufferIterator, typename CompletionCondition,
322 typename ReadHandler>
323 class read_op
324 : public base_from_cancellation_state<ReadHandler>,
325 base_from_completion_cond<CompletionCondition>
326 {
327 public:
328 read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers,
329 CompletionCondition& completion_condition, ReadHandler& handler)
330 : base_from_cancellation_state<ReadHandler>(
331 handler, enable_partial_cancellation()),
332 base_from_completion_cond<CompletionCondition>(completion_condition),
333 stream_(stream),
334 buffers_(buffers),
335 start_(0),
336 handler_(static_cast<ReadHandler&&>(handler))
337 {
338 }
339
340 read_op(const read_op& other)
341 : base_from_cancellation_state<ReadHandler>(other),
342 base_from_completion_cond<CompletionCondition>(other),
343 stream_(other.stream_),
344 buffers_(other.buffers_),
345 start_(other.start_),
346 handler_(other.handler_)
347 {
348 }
349
350 read_op(read_op&& other)
351 : base_from_cancellation_state<ReadHandler>(
352 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
353 base_from_completion_cond<CompletionCondition>(
354 static_cast<base_from_completion_cond<CompletionCondition>&&>(other)),
355 stream_(other.stream_),
356 buffers_(static_cast<buffers_type&&>(other.buffers_)),
357 start_(other.start_),
358 handler_(static_cast<ReadHandler&&>(other.handler_))
359 {
360 }
361
362 void operator()(boost::system::error_code ec,
363 std::size_t bytes_transferred, int start = 0)
364 {
365 std::size_t max_size;
366 switch (start_ = start)
367 {
368 case 1:
369 max_size = this->check_for_completion(ec, buffers_.total_consumed());
370 for (;;)
371 {
372 {
373 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));
374 stream_.async_read_some(buffers_.prepare(max_size),
375 static_cast<read_op&&>(*this));
376 }
377 return; default:
378 buffers_.consume(bytes_transferred);
379 if ((!ec && bytes_transferred == 0) || buffers_.empty())
380 break;
381 max_size = this->check_for_completion(ec, buffers_.total_consumed());
382 if (max_size == 0)
383 break;
384 if (this->cancelled() != cancellation_type::none)
385 {
386 ec = error::operation_aborted;
387 break;
388 }
389 }
390
391 static_cast<ReadHandler&&>(handler_)(
392 static_cast<const boost::system::error_code&>(ec),
393 static_cast<const std::size_t&>(buffers_.total_consumed()));
394 }
395 }
396
397 //private:
398 typedef boost::asio::detail::consuming_buffers<mutable_buffer,
399 MutableBufferSequence, MutableBufferIterator> buffers_type;
400
401 AsyncReadStream& stream_;
402 buffers_type buffers_;
403 int start_;
404 ReadHandler handler_;
405 };
406
407 template <typename AsyncReadStream, typename MutableBufferSequence,
408 typename MutableBufferIterator, typename CompletionCondition,
409 typename ReadHandler>
410 inline bool asio_handler_is_continuation(
411 read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,
412 CompletionCondition, ReadHandler>* this_handler)
413 {
414 return this_handler->start_ == 0 ? true
415 : boost_asio_handler_cont_helpers::is_continuation(
416 this_handler->handler_);
417 }
418
419 template <typename AsyncReadStream, typename MutableBufferSequence,
420 typename MutableBufferIterator, typename CompletionCondition,
421 typename ReadHandler>
422 inline void start_read_op(AsyncReadStream& stream,
423 const MutableBufferSequence& buffers, const MutableBufferIterator&,
424 CompletionCondition& completion_condition, ReadHandler& handler)
425 {
426 read_op<AsyncReadStream, MutableBufferSequence,
427 MutableBufferIterator, CompletionCondition, ReadHandler>(
428 stream, buffers, completion_condition, handler)(
429 boost::system::error_code(), 0, 1);
430 }
431
432 template <typename AsyncReadStream>
433 class initiate_async_read
434 {
435 public:
436 typedef typename AsyncReadStream::executor_type executor_type;
437
438 explicit initiate_async_read(AsyncReadStream& stream)
439 : stream_(stream)
440 {
441 }
442
443 executor_type get_executor() const noexcept
444 {
445 return stream_.get_executor();
446 }
447
448 template <typename ReadHandler, typename MutableBufferSequence,
449 typename CompletionCondition>
450 void operator()(ReadHandler&& handler,
451 const MutableBufferSequence& buffers,
452 CompletionCondition&& completion_cond) const
453 {
454 // If you get an error on the following line it means that your handler
455 // does not meet the documented type requirements for a ReadHandler.
456 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
457
458 non_const_lvalue<ReadHandler> handler2(handler);
459 non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
460 start_read_op(stream_, buffers,
461 boost::asio::buffer_sequence_begin(buffers),
462 completion_cond2.value, handler2.value);
463 }
464
465 private:
466 AsyncReadStream& stream_;
467 };
468} // namespace detail
469
470#if !defined(GENERATING_DOCUMENTATION)
471
472template <template <typename, typename> class Associator,
473 typename AsyncReadStream, typename MutableBufferSequence,
474 typename MutableBufferIterator, typename CompletionCondition,
475 typename ReadHandler, typename DefaultCandidate>
476struct associator<Associator,
477 detail::read_op<AsyncReadStream, MutableBufferSequence,
478 MutableBufferIterator, CompletionCondition, ReadHandler>,
479 DefaultCandidate>
480 : Associator<ReadHandler, DefaultCandidate>
481{
482 static typename Associator<ReadHandler, DefaultCandidate>::type get(
483 const detail::read_op<AsyncReadStream, MutableBufferSequence,
484 MutableBufferIterator, CompletionCondition, ReadHandler>& h) noexcept
485 {
486 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
487 }
488
489 static auto get(
490 const detail::read_op<AsyncReadStream, MutableBufferSequence,
491 MutableBufferIterator, CompletionCondition, ReadHandler>& h,
492 const DefaultCandidate& c) noexcept
493 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
494 {
495 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
496 }
497};
498
499#endif // !defined(GENERATING_DOCUMENTATION)
500
501template <typename AsyncReadStream,
502 typename MutableBufferSequence, typename CompletionCondition,
503 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
504 std::size_t)) ReadToken>
505inline auto async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
506 CompletionCondition completion_condition, ReadToken&& token,
507 constraint_t<
508 is_mutable_buffer_sequence<MutableBufferSequence>::value
509 >)
510 -> decltype(
511 async_initiate<ReadToken,
512 void (boost::system::error_code, std::size_t)>(
513 declval<detail::initiate_async_read<AsyncReadStream>>(), token, buffers,
514 static_cast<CompletionCondition&&>(completion_condition)))
515{
516 return async_initiate<ReadToken,
517 void (boost::system::error_code, std::size_t)>(
518 detail::initiate_async_read<AsyncReadStream>(s), token, buffers,
519 static_cast<CompletionCondition&&>(completion_condition));
520}
521
522template <typename AsyncReadStream, typename MutableBufferSequence,
523 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
524 std::size_t)) ReadToken>
525inline auto async_read(AsyncReadStream& s,
526 const MutableBufferSequence& buffers, ReadToken&& token,
527 constraint_t<
528 is_mutable_buffer_sequence<MutableBufferSequence>::value
529 >)
530 -> decltype(
531 async_initiate<ReadToken,
532 void (boost::system::error_code, std::size_t)>(
533 declval<detail::initiate_async_read<AsyncReadStream>>(),
534 token, buffers, transfer_all()))
535{
536 return async_initiate<ReadToken,
537 void (boost::system::error_code, std::size_t)>(
538 detail::initiate_async_read<AsyncReadStream>(s),
539 token, buffers, transfer_all());
540}
541
542#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
543
544namespace detail
545{
546 template <typename AsyncReadStream, typename DynamicBuffer_v1,
547 typename CompletionCondition, typename ReadHandler>
548 class read_dynbuf_v1_op
549 : public base_from_cancellation_state<ReadHandler>,
550 base_from_completion_cond<CompletionCondition>
551 {
552 public:
553 template <typename BufferSequence>
554 read_dynbuf_v1_op(AsyncReadStream& stream,
555 BufferSequence&& buffers,
556 CompletionCondition& completion_condition, ReadHandler& handler)
557 : base_from_cancellation_state<ReadHandler>(
558 handler, enable_partial_cancellation()),
559 base_from_completion_cond<CompletionCondition>(completion_condition),
560 stream_(stream),
561 buffers_(static_cast<BufferSequence&&>(buffers)),
562 start_(0),
563 total_transferred_(0),
564 handler_(static_cast<ReadHandler&&>(handler))
565 {
566 }
567
568 read_dynbuf_v1_op(const read_dynbuf_v1_op& other)
569 : base_from_cancellation_state<ReadHandler>(other),
570 base_from_completion_cond<CompletionCondition>(other),
571 stream_(other.stream_),
572 buffers_(other.buffers_),
573 start_(other.start_),
574 total_transferred_(other.total_transferred_),
575 handler_(other.handler_)
576 {
577 }
578
579 read_dynbuf_v1_op(read_dynbuf_v1_op&& other)
580 : base_from_cancellation_state<ReadHandler>(
581 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
582 base_from_completion_cond<CompletionCondition>(
583 static_cast<base_from_completion_cond<CompletionCondition>&&>(other)),
584 stream_(other.stream_),
585 buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
586 start_(other.start_),
587 total_transferred_(other.total_transferred_),
588 handler_(static_cast<ReadHandler&&>(other.handler_))
589 {
590 }
591
592 void operator()(boost::system::error_code ec,
593 std::size_t bytes_transferred, int start = 0)
594 {
595 std::size_t max_size, bytes_available;
596 switch (start_ = start)
597 {
598 case 1:
599 max_size = this->check_for_completion(ec, total_transferred_);
600 bytes_available = std::min<std::size_t>(
601 std::max<std::size_t>(512,
602 buffers_.capacity() - buffers_.size()),
603 std::min<std::size_t>(max_size,
604 buffers_.max_size() - buffers_.size()));
605 for (;;)
606 {
607 {
608 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));
609 stream_.async_read_some(buffers_.prepare(bytes_available),
610 static_cast<read_dynbuf_v1_op&&>(*this));
611 }
612 return; default:
613 total_transferred_ += bytes_transferred;
614 buffers_.commit(bytes_transferred);
615 max_size = this->check_for_completion(ec, total_transferred_);
616 bytes_available = std::min<std::size_t>(
617 std::max<std::size_t>(512,
618 buffers_.capacity() - buffers_.size()),
619 std::min<std::size_t>(max_size,
620 buffers_.max_size() - buffers_.size()));
621 if ((!ec && bytes_transferred == 0) || bytes_available == 0)
622 break;
623 if (this->cancelled() != cancellation_type::none)
624 {
625 ec = error::operation_aborted;
626 break;
627 }
628 }
629
630 static_cast<ReadHandler&&>(handler_)(
631 static_cast<const boost::system::error_code&>(ec),
632 static_cast<const std::size_t&>(total_transferred_));
633 }
634 }
635
636 //private:
637 AsyncReadStream& stream_;
638 DynamicBuffer_v1 buffers_;
639 int start_;
640 std::size_t total_transferred_;
641 ReadHandler handler_;
642 };
643
644 template <typename AsyncReadStream, typename DynamicBuffer_v1,
645 typename CompletionCondition, typename ReadHandler>
646 inline bool asio_handler_is_continuation(
647 read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
648 CompletionCondition, ReadHandler>* this_handler)
649 {
650 return this_handler->start_ == 0 ? true
651 : boost_asio_handler_cont_helpers::is_continuation(
652 this_handler->handler_);
653 }
654
655 template <typename AsyncReadStream>
656 class initiate_async_read_dynbuf_v1
657 {
658 public:
659 typedef typename AsyncReadStream::executor_type executor_type;
660
661 explicit initiate_async_read_dynbuf_v1(AsyncReadStream& stream)
662 : stream_(stream)
663 {
664 }
665
666 executor_type get_executor() const noexcept
667 {
668 return stream_.get_executor();
669 }
670
671 template <typename ReadHandler, typename DynamicBuffer_v1,
672 typename CompletionCondition>
673 void operator()(ReadHandler&& handler,
674 DynamicBuffer_v1&& buffers,
675 CompletionCondition&& completion_cond) const
676 {
677 // If you get an error on the following line it means that your handler
678 // does not meet the documented type requirements for a ReadHandler.
679 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
680
681 non_const_lvalue<ReadHandler> handler2(handler);
682 non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
683 read_dynbuf_v1_op<AsyncReadStream, decay_t<DynamicBuffer_v1>,
684 CompletionCondition, decay_t<ReadHandler>>(
685 stream_, static_cast<DynamicBuffer_v1&&>(buffers),
686 completion_cond2.value, handler2.value)(
687 boost::system::error_code(), 0, 1);
688 }
689
690 private:
691 AsyncReadStream& stream_;
692 };
693} // namespace detail
694
695#if !defined(GENERATING_DOCUMENTATION)
696
697template <template <typename, typename> class Associator,
698 typename AsyncReadStream, typename DynamicBuffer_v1,
699 typename CompletionCondition, typename ReadHandler,
700 typename DefaultCandidate>
701struct associator<Associator,
702 detail::read_dynbuf_v1_op<AsyncReadStream,
703 DynamicBuffer_v1, CompletionCondition, ReadHandler>,
704 DefaultCandidate>
705 : Associator<ReadHandler, DefaultCandidate>
706{
707 static typename Associator<ReadHandler, DefaultCandidate>::type get(
708 const detail::read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,
709 CompletionCondition, ReadHandler>& h) noexcept
710 {
711 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
712 }
713
714 static auto get(
715 const detail::read_dynbuf_v1_op<AsyncReadStream,
716 DynamicBuffer_v1, CompletionCondition, ReadHandler>& h,
717 const DefaultCandidate& c) noexcept
718 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
719 {
720 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
721 }
722};
723
724#endif // !defined(GENERATING_DOCUMENTATION)
725
726template <typename AsyncReadStream, typename DynamicBuffer_v1,
727 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
728 std::size_t)) ReadToken>
729inline auto async_read(AsyncReadStream& s,
730 DynamicBuffer_v1&& buffers, ReadToken&& token,
731 constraint_t<
732 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
733 >,
734 constraint_t<
735 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
736 >)
737 -> decltype(
738 async_initiate<ReadToken,
739 void (boost::system::error_code, std::size_t)>(
740 declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(),
741 token, static_cast<DynamicBuffer_v1&&>(buffers), transfer_all()))
742{
743 return async_initiate<ReadToken,
744 void (boost::system::error_code, std::size_t)>(
745 detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s),
746 token, static_cast<DynamicBuffer_v1&&>(buffers), transfer_all());
747}
748
749template <typename AsyncReadStream,
750 typename DynamicBuffer_v1, typename CompletionCondition,
751 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
752 std::size_t)) ReadToken>
753inline auto async_read(AsyncReadStream& s, DynamicBuffer_v1&& buffers,
754 CompletionCondition completion_condition, ReadToken&& token,
755 constraint_t<
756 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
757 >,
758 constraint_t<
759 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
760 >)
761 -> decltype(
762 async_initiate<ReadToken,
763 void (boost::system::error_code, std::size_t)>(
764 declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(),
765 token, static_cast<DynamicBuffer_v1&&>(buffers),
766 static_cast<CompletionCondition&&>(completion_condition)))
767{
768 return async_initiate<ReadToken,
769 void (boost::system::error_code, std::size_t)>(
770 detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s),
771 token, static_cast<DynamicBuffer_v1&&>(buffers),
772 static_cast<CompletionCondition&&>(completion_condition));
773}
774
775#if !defined(BOOST_ASIO_NO_EXTENSIONS)
776#if !defined(BOOST_ASIO_NO_IOSTREAM)
777
778template <typename AsyncReadStream, typename Allocator,
779 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
780 std::size_t)) ReadToken>
781inline auto async_read(AsyncReadStream& s,
782 basic_streambuf<Allocator>& b, ReadToken&& token)
783 -> decltype(
784 async_initiate<ReadToken,
785 void (boost::system::error_code, std::size_t)>(
786 declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(),
787 token, basic_streambuf_ref<Allocator>(b), transfer_all()))
788{
789 return async_initiate<ReadToken,
790 void (boost::system::error_code, std::size_t)>(
791 detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s),
792 token, basic_streambuf_ref<Allocator>(b), transfer_all());
793}
794
795template <typename AsyncReadStream,
796 typename Allocator, typename CompletionCondition,
797 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
798 std::size_t)) ReadToken>
799inline auto async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
800 CompletionCondition completion_condition, ReadToken&& token)
801 -> decltype(
802 async_initiate<ReadToken,
803 void (boost::system::error_code, std::size_t)>(
804 declval<detail::initiate_async_read_dynbuf_v1<AsyncReadStream>>(),
805 token, basic_streambuf_ref<Allocator>(b),
806 static_cast<CompletionCondition&&>(completion_condition)))
807{
808 return async_initiate<ReadToken,
809 void (boost::system::error_code, std::size_t)>(
810 detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s),
811 token, basic_streambuf_ref<Allocator>(b),
812 static_cast<CompletionCondition&&>(completion_condition));
813}
814
815#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
816#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
817#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
818
819namespace detail
820{
821 template <typename AsyncReadStream, typename DynamicBuffer_v2,
822 typename CompletionCondition, typename ReadHandler>
823 class read_dynbuf_v2_op
824 : public base_from_cancellation_state<ReadHandler>,
825 base_from_completion_cond<CompletionCondition>
826 {
827 public:
828 template <typename BufferSequence>
829 read_dynbuf_v2_op(AsyncReadStream& stream,
830 BufferSequence&& buffers,
831 CompletionCondition& completion_condition, ReadHandler& handler)
832 : base_from_cancellation_state<ReadHandler>(
833 handler, enable_partial_cancellation()),
834 base_from_completion_cond<CompletionCondition>(completion_condition),
835 stream_(stream),
836 buffers_(static_cast<BufferSequence&&>(buffers)),
837 start_(0),
838 total_transferred_(0),
839 bytes_available_(0),
840 handler_(static_cast<ReadHandler&&>(handler))
841 {
842 }
843
844 read_dynbuf_v2_op(const read_dynbuf_v2_op& other)
845 : base_from_cancellation_state<ReadHandler>(other),
846 base_from_completion_cond<CompletionCondition>(other),
847 stream_(other.stream_),
848 buffers_(other.buffers_),
849 start_(other.start_),
850 total_transferred_(other.total_transferred_),
851 bytes_available_(other.bytes_available_),
852 handler_(other.handler_)
853 {
854 }
855
856 read_dynbuf_v2_op(read_dynbuf_v2_op&& other)
857 : base_from_cancellation_state<ReadHandler>(
858 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
859 base_from_completion_cond<CompletionCondition>(
860 static_cast<base_from_completion_cond<CompletionCondition>&&>(other)),
861 stream_(other.stream_),
862 buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
863 start_(other.start_),
864 total_transferred_(other.total_transferred_),
865 bytes_available_(other.bytes_available_),
866 handler_(static_cast<ReadHandler&&>(other.handler_))
867 {
868 }
869
870 void operator()(boost::system::error_code ec,
871 std::size_t bytes_transferred, int start = 0)
872 {
873 std::size_t max_size, pos;
874 switch (start_ = start)
875 {
876 case 1:
877 max_size = this->check_for_completion(ec, total_transferred_);
878 bytes_available_ = std::min<std::size_t>(
879 std::max<std::size_t>(512,
880 buffers_.capacity() - buffers_.size()),
881 std::min<std::size_t>(max_size,
882 buffers_.max_size() - buffers_.size()));
883 for (;;)
884 {
885 pos = buffers_.size();
886 buffers_.grow(bytes_available_);
887 {
888 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));
889 stream_.async_read_some(buffers_.data(pos, bytes_available_),
890 static_cast<read_dynbuf_v2_op&&>(*this));
891 }
892 return; default:
893 total_transferred_ += bytes_transferred;
894 buffers_.shrink(bytes_available_ - bytes_transferred);
895 max_size = this->check_for_completion(ec, total_transferred_);
896 bytes_available_ = std::min<std::size_t>(
897 std::max<std::size_t>(512,
898 buffers_.capacity() - buffers_.size()),
899 std::min<std::size_t>(max_size,
900 buffers_.max_size() - buffers_.size()));
901 if ((!ec && bytes_transferred == 0) || bytes_available_ == 0)
902 break;
903 if (this->cancelled() != cancellation_type::none)
904 {
905 ec = error::operation_aborted;
906 break;
907 }
908 }
909
910 static_cast<ReadHandler&&>(handler_)(
911 static_cast<const boost::system::error_code&>(ec),
912 static_cast<const std::size_t&>(total_transferred_));
913 }
914 }
915
916 //private:
917 AsyncReadStream& stream_;
918 DynamicBuffer_v2 buffers_;
919 int start_;
920 std::size_t total_transferred_;
921 std::size_t bytes_available_;
922 ReadHandler handler_;
923 };
924
925 template <typename AsyncReadStream, typename DynamicBuffer_v2,
926 typename CompletionCondition, typename ReadHandler>
927 inline bool asio_handler_is_continuation(
928 read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,
929 CompletionCondition, ReadHandler>* this_handler)
930 {
931 return this_handler->start_ == 0 ? true
932 : boost_asio_handler_cont_helpers::is_continuation(
933 this_handler->handler_);
934 }
935
936 template <typename AsyncReadStream>
937 class initiate_async_read_dynbuf_v2
938 {
939 public:
940 typedef typename AsyncReadStream::executor_type executor_type;
941
942 explicit initiate_async_read_dynbuf_v2(AsyncReadStream& stream)
943 : stream_(stream)
944 {
945 }
946
947 executor_type get_executor() const noexcept
948 {
949 return stream_.get_executor();
950 }
951
952 template <typename ReadHandler, typename DynamicBuffer_v2,
953 typename CompletionCondition>
954 void operator()(ReadHandler&& handler,
955 DynamicBuffer_v2&& buffers,
956 CompletionCondition&& completion_cond) const
957 {
958 // If you get an error on the following line it means that your handler
959 // does not meet the documented type requirements for a ReadHandler.
960 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
961
962 non_const_lvalue<ReadHandler> handler2(handler);
963 non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
964 read_dynbuf_v2_op<AsyncReadStream, decay_t<DynamicBuffer_v2>,
965 CompletionCondition, decay_t<ReadHandler>>(
966 stream_, static_cast<DynamicBuffer_v2&&>(buffers),
967 completion_cond2.value, handler2.value)(
968 boost::system::error_code(), 0, 1);
969 }
970
971 private:
972 AsyncReadStream& stream_;
973 };
974} // namespace detail
975
976#if !defined(GENERATING_DOCUMENTATION)
977
978template <template <typename, typename> class Associator,
979 typename AsyncReadStream, typename DynamicBuffer_v2,
980 typename CompletionCondition, typename ReadHandler,
981 typename DefaultCandidate>
982struct associator<Associator,
983 detail::read_dynbuf_v2_op<AsyncReadStream,
984 DynamicBuffer_v2, CompletionCondition, ReadHandler>,
985 DefaultCandidate>
986 : Associator<ReadHandler, DefaultCandidate>
987{
988 static typename Associator<ReadHandler, DefaultCandidate>::type get(
989 const detail::read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,
990 CompletionCondition, ReadHandler>& h) noexcept
991 {
992 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
993 }
994
995 static auto get(
996 const detail::read_dynbuf_v2_op<AsyncReadStream,
997 DynamicBuffer_v2, CompletionCondition, ReadHandler>& h,
998 const DefaultCandidate& c) noexcept
999 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1000 {
1001 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1002 }
1003};
1004
1005#endif // !defined(GENERATING_DOCUMENTATION)
1006
1007template <typename AsyncReadStream, typename DynamicBuffer_v2,
1008 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1009 std::size_t)) ReadToken>
1010inline auto async_read(AsyncReadStream& s,
1011 DynamicBuffer_v2 buffers, ReadToken&& token,
1012 constraint_t<
1013 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1014 >)
1015 -> decltype(
1016 async_initiate<ReadToken,
1017 void (boost::system::error_code, std::size_t)>(
1018 declval<detail::initiate_async_read_dynbuf_v2<AsyncReadStream>>(),
1019 token, static_cast<DynamicBuffer_v2&&>(buffers), transfer_all()))
1020{
1021 return async_initiate<ReadToken,
1022 void (boost::system::error_code, std::size_t)>(
1023 detail::initiate_async_read_dynbuf_v2<AsyncReadStream>(s),
1024 token, static_cast<DynamicBuffer_v2&&>(buffers), transfer_all());
1025}
1026
1027template <typename AsyncReadStream,
1028 typename DynamicBuffer_v2, typename CompletionCondition,
1029 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1030 std::size_t)) ReadToken>
1031inline auto async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,
1032 CompletionCondition completion_condition, ReadToken&& token,
1033 constraint_t<
1034 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1035 >)
1036 -> decltype(
1037 async_initiate<ReadToken,
1038 void (boost::system::error_code, std::size_t)>(
1039 declval<detail::initiate_async_read_dynbuf_v2<AsyncReadStream>>(),
1040 token, static_cast<DynamicBuffer_v2&&>(buffers),
1041 static_cast<CompletionCondition&&>(completion_condition)))
1042{
1043 return async_initiate<ReadToken,
1044 void (boost::system::error_code, std::size_t)>(
1045 detail::initiate_async_read_dynbuf_v2<AsyncReadStream>(s),
1046 token, static_cast<DynamicBuffer_v2&&>(buffers),
1047 static_cast<CompletionCondition&&>(completion_condition));
1048}
1049
1050} // namespace asio
1051} // namespace boost
1052
1053#include <boost/asio/detail/pop_options.hpp>
1054
1055#endif // BOOST_ASIO_IMPL_READ_HPP
1056

source code of boost/libs/asio/include/boost/asio/impl/read.hpp