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 | |
36 | namespace boost { |
37 | namespace asio { |
38 | |
39 | namespace 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 | |
62 | template <typename SyncReadStream, typename MutableBufferSequence, |
63 | typename CompletionCondition> |
64 | std::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 | |
75 | template <typename SyncReadStream, typename MutableBufferSequence> |
76 | inline 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 | |
87 | template <typename SyncReadStream, typename MutableBufferSequence> |
88 | inline 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 | |
97 | template <typename SyncReadStream, typename MutableBufferSequence, |
98 | typename CompletionCondition> |
99 | inline 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 | |
114 | template <typename SyncReadStream, typename DynamicBuffer_v1, |
115 | typename CompletionCondition> |
116 | std::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 | |
150 | template <typename SyncReadStream, typename DynamicBuffer_v1> |
151 | inline 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 | |
167 | template <typename SyncReadStream, typename DynamicBuffer_v1> |
168 | inline 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 | |
182 | template <typename SyncReadStream, typename DynamicBuffer_v1, |
183 | typename CompletionCondition> |
184 | inline 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 | |
205 | template <typename SyncReadStream, typename Allocator, |
206 | typename CompletionCondition> |
207 | inline 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 | |
215 | template <typename SyncReadStream, typename Allocator> |
216 | inline 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 | |
222 | template <typename SyncReadStream, typename Allocator> |
223 | inline 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 | |
230 | template <typename SyncReadStream, typename Allocator, |
231 | typename CompletionCondition> |
232 | inline 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 | |
244 | template <typename SyncReadStream, typename DynamicBuffer_v2, |
245 | typename CompletionCondition> |
246 | std::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 | |
278 | template <typename SyncReadStream, typename DynamicBuffer_v2> |
279 | inline 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 | |
291 | template <typename SyncReadStream, typename DynamicBuffer_v2> |
292 | inline 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 | |
302 | template <typename SyncReadStream, typename DynamicBuffer_v2, |
303 | typename CompletionCondition> |
304 | inline 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 | |
318 | namespace 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 | |
472 | template <template <typename, typename> class Associator, |
473 | typename AsyncReadStream, typename MutableBufferSequence, |
474 | typename MutableBufferIterator, typename CompletionCondition, |
475 | typename ReadHandler, typename DefaultCandidate> |
476 | struct 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 | |
501 | template <typename AsyncReadStream, |
502 | typename MutableBufferSequence, typename CompletionCondition, |
503 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
504 | std::size_t)) ReadToken> |
505 | inline 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 | |
522 | template <typename AsyncReadStream, typename MutableBufferSequence, |
523 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
524 | std::size_t)) ReadToken> |
525 | inline 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 | |
544 | namespace 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 | |
697 | template <template <typename, typename> class Associator, |
698 | typename AsyncReadStream, typename DynamicBuffer_v1, |
699 | typename CompletionCondition, typename ReadHandler, |
700 | typename DefaultCandidate> |
701 | struct 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 | |
726 | template <typename AsyncReadStream, typename DynamicBuffer_v1, |
727 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
728 | std::size_t)) ReadToken> |
729 | inline 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 | |
749 | template <typename AsyncReadStream, |
750 | typename DynamicBuffer_v1, typename CompletionCondition, |
751 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
752 | std::size_t)) ReadToken> |
753 | inline 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 | |
778 | template <typename AsyncReadStream, typename Allocator, |
779 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
780 | std::size_t)) ReadToken> |
781 | inline 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 | |
795 | template <typename AsyncReadStream, |
796 | typename Allocator, typename CompletionCondition, |
797 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
798 | std::size_t)) ReadToken> |
799 | inline 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 | |
819 | namespace 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 | |
978 | template <template <typename, typename> class Associator, |
979 | typename AsyncReadStream, typename DynamicBuffer_v2, |
980 | typename CompletionCondition, typename ReadHandler, |
981 | typename DefaultCandidate> |
982 | struct 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 | |
1007 | template <typename AsyncReadStream, typename DynamicBuffer_v2, |
1008 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
1009 | std::size_t)) ReadToken> |
1010 | inline 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 | |
1027 | template <typename AsyncReadStream, |
1028 | typename DynamicBuffer_v2, typename CompletionCondition, |
1029 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
1030 | std::size_t)) ReadToken> |
1031 | inline 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 | |