]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // impl/read.hpp | |
3 | // ~~~~~~~~~~~~~ | |
4 | // | |
11fdf7f2 | 5 | // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
b32b8144 FG |
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/associated_allocator.hpp> | |
20 | #include <boost/asio/associated_executor.hpp> | |
21 | #include <boost/asio/buffer.hpp> | |
22 | #include <boost/asio/completion_condition.hpp> | |
23 | #include <boost/asio/detail/array_fwd.hpp> | |
24 | #include <boost/asio/detail/base_from_completion_cond.hpp> | |
25 | #include <boost/asio/detail/bind_handler.hpp> | |
26 | #include <boost/asio/detail/consuming_buffers.hpp> | |
27 | #include <boost/asio/detail/dependent_type.hpp> | |
28 | #include <boost/asio/detail/handler_alloc_helpers.hpp> | |
29 | #include <boost/asio/detail/handler_cont_helpers.hpp> | |
30 | #include <boost/asio/detail/handler_invoke_helpers.hpp> | |
31 | #include <boost/asio/detail/handler_type_requirements.hpp> | |
32 | #include <boost/asio/detail/throw_error.hpp> | |
33 | #include <boost/asio/error.hpp> | |
34 | ||
35 | #include <boost/asio/detail/push_options.hpp> | |
36 | ||
37 | namespace boost { | |
38 | namespace asio { | |
39 | ||
40 | namespace detail | |
41 | { | |
42 | template <typename SyncReadStream, typename MutableBufferSequence, | |
43 | typename MutableBufferIterator, typename CompletionCondition> | |
44 | std::size_t read_buffer_sequence(SyncReadStream& s, | |
45 | const MutableBufferSequence& buffers, const MutableBufferIterator&, | |
46 | CompletionCondition completion_condition, boost::system::error_code& ec) | |
47 | { | |
48 | ec = boost::system::error_code(); | |
49 | boost::asio::detail::consuming_buffers<mutable_buffer, | |
50 | MutableBufferSequence, MutableBufferIterator> tmp(buffers); | |
51 | while (!tmp.empty()) | |
52 | { | |
53 | if (std::size_t max_size = detail::adapt_completion_condition_result( | |
54 | completion_condition(ec, tmp.total_consumed()))) | |
55 | tmp.consume(s.read_some(tmp.prepare(max_size), ec)); | |
56 | else | |
57 | break; | |
58 | } | |
59 | return tmp.total_consumed();; | |
60 | } | |
61 | } // namespace detail | |
62 | ||
63 | template <typename SyncReadStream, typename MutableBufferSequence, | |
64 | typename CompletionCondition> | |
65 | std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, | |
66 | CompletionCondition completion_condition, boost::system::error_code& ec, | |
67 | typename enable_if< | |
68 | is_mutable_buffer_sequence<MutableBufferSequence>::value | |
69 | >::type*) | |
70 | { | |
71 | return detail::read_buffer_sequence(s, buffers, | |
72 | boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); | |
73 | } | |
74 | ||
75 | template <typename SyncReadStream, typename MutableBufferSequence> | |
76 | inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, | |
77 | typename enable_if< | |
78 | is_mutable_buffer_sequence<MutableBufferSequence>::value | |
79 | >::type*) | |
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(ec, "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 | typename enable_if< | |
91 | is_mutable_buffer_sequence<MutableBufferSequence>::value | |
92 | >::type*) | |
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 | typename enable_if< | |
102 | is_mutable_buffer_sequence<MutableBufferSequence>::value | |
103 | >::type*) | |
104 | { | |
105 | boost::system::error_code ec; | |
106 | std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); | |
107 | boost::asio::detail::throw_error(ec, "read"); | |
108 | return bytes_transferred; | |
109 | } | |
110 | ||
111 | template <typename SyncReadStream, typename DynamicBuffer, | |
112 | typename CompletionCondition> | |
113 | std::size_t read(SyncReadStream& s, | |
114 | BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, | |
115 | CompletionCondition completion_condition, boost::system::error_code& ec, | |
116 | typename enable_if< | |
11fdf7f2 | 117 | is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value |
b32b8144 FG |
118 | >::type*) |
119 | { | |
120 | typename decay<DynamicBuffer>::type b( | |
121 | BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); | |
122 | ||
123 | ec = boost::system::error_code(); | |
124 | std::size_t total_transferred = 0; | |
125 | std::size_t max_size = detail::adapt_completion_condition_result( | |
126 | completion_condition(ec, total_transferred)); | |
127 | std::size_t bytes_available = std::min<std::size_t>( | |
128 | std::max<std::size_t>(512, b.capacity() - b.size()), | |
129 | std::min<std::size_t>(max_size, b.max_size() - b.size())); | |
130 | while (bytes_available > 0) | |
131 | { | |
132 | std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); | |
133 | b.commit(bytes_transferred); | |
134 | total_transferred += bytes_transferred; | |
135 | max_size = detail::adapt_completion_condition_result( | |
136 | completion_condition(ec, total_transferred)); | |
137 | bytes_available = std::min<std::size_t>( | |
138 | std::max<std::size_t>(512, b.capacity() - b.size()), | |
139 | std::min<std::size_t>(max_size, b.max_size() - b.size())); | |
140 | } | |
141 | return total_transferred; | |
142 | } | |
143 | ||
144 | template <typename SyncReadStream, typename DynamicBuffer> | |
145 | inline std::size_t read(SyncReadStream& s, | |
146 | BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, | |
147 | typename enable_if< | |
11fdf7f2 | 148 | is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value |
b32b8144 FG |
149 | >::type*) |
150 | { | |
151 | boost::system::error_code ec; | |
152 | std::size_t bytes_transferred = read(s, | |
153 | BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), transfer_all(), ec); | |
154 | boost::asio::detail::throw_error(ec, "read"); | |
155 | return bytes_transferred; | |
156 | } | |
157 | ||
158 | template <typename SyncReadStream, typename DynamicBuffer> | |
159 | inline std::size_t read(SyncReadStream& s, | |
160 | BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, | |
161 | boost::system::error_code& ec, | |
162 | typename enable_if< | |
11fdf7f2 | 163 | is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value |
b32b8144 FG |
164 | >::type*) |
165 | { | |
166 | return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), | |
167 | transfer_all(), ec); | |
168 | } | |
169 | ||
170 | template <typename SyncReadStream, typename DynamicBuffer, | |
171 | typename CompletionCondition> | |
172 | inline std::size_t read(SyncReadStream& s, | |
173 | BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, | |
174 | CompletionCondition completion_condition, | |
175 | typename enable_if< | |
11fdf7f2 | 176 | is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value |
b32b8144 FG |
177 | >::type*) |
178 | { | |
179 | boost::system::error_code ec; | |
180 | std::size_t bytes_transferred = read(s, | |
181 | BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), | |
182 | completion_condition, ec); | |
183 | boost::asio::detail::throw_error(ec, "read"); | |
184 | return bytes_transferred; | |
185 | } | |
186 | ||
187 | #if !defined(BOOST_ASIO_NO_EXTENSIONS) | |
188 | #if !defined(BOOST_ASIO_NO_IOSTREAM) | |
189 | ||
190 | template <typename SyncReadStream, typename Allocator, | |
191 | typename CompletionCondition> | |
192 | inline std::size_t read(SyncReadStream& s, | |
193 | boost::asio::basic_streambuf<Allocator>& b, | |
194 | CompletionCondition completion_condition, boost::system::error_code& ec) | |
195 | { | |
196 | return read(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); | |
197 | } | |
198 | ||
199 | template <typename SyncReadStream, typename Allocator> | |
200 | inline std::size_t read(SyncReadStream& s, | |
201 | boost::asio::basic_streambuf<Allocator>& b) | |
202 | { | |
203 | return read(s, basic_streambuf_ref<Allocator>(b)); | |
204 | } | |
205 | ||
206 | template <typename SyncReadStream, typename Allocator> | |
207 | inline std::size_t read(SyncReadStream& s, | |
208 | boost::asio::basic_streambuf<Allocator>& b, | |
209 | boost::system::error_code& ec) | |
210 | { | |
211 | return read(s, basic_streambuf_ref<Allocator>(b), ec); | |
212 | } | |
213 | ||
214 | template <typename SyncReadStream, typename Allocator, | |
215 | typename CompletionCondition> | |
216 | inline std::size_t read(SyncReadStream& s, | |
217 | boost::asio::basic_streambuf<Allocator>& b, | |
218 | CompletionCondition completion_condition) | |
219 | { | |
220 | return read(s, basic_streambuf_ref<Allocator>(b), completion_condition); | |
221 | } | |
222 | ||
223 | #endif // !defined(BOOST_ASIO_NO_IOSTREAM) | |
224 | #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) | |
225 | ||
226 | namespace detail | |
227 | { | |
228 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
229 | typename MutableBufferIterator, typename CompletionCondition, | |
230 | typename ReadHandler> | |
231 | class read_op | |
232 | : detail::base_from_completion_cond<CompletionCondition> | |
233 | { | |
234 | public: | |
235 | read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, | |
236 | CompletionCondition completion_condition, ReadHandler& handler) | |
237 | : detail::base_from_completion_cond< | |
238 | CompletionCondition>(completion_condition), | |
239 | stream_(stream), | |
240 | buffers_(buffers), | |
241 | start_(0), | |
242 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) | |
243 | { | |
244 | } | |
245 | ||
246 | #if defined(BOOST_ASIO_HAS_MOVE) | |
247 | read_op(const read_op& other) | |
248 | : detail::base_from_completion_cond<CompletionCondition>(other), | |
249 | stream_(other.stream_), | |
250 | buffers_(other.buffers_), | |
251 | start_(other.start_), | |
252 | handler_(other.handler_) | |
253 | { | |
254 | } | |
255 | ||
256 | read_op(read_op&& other) | |
257 | : detail::base_from_completion_cond<CompletionCondition>(other), | |
258 | stream_(other.stream_), | |
259 | buffers_(other.buffers_), | |
260 | start_(other.start_), | |
261 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) | |
262 | { | |
263 | } | |
264 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
265 | ||
266 | void operator()(const boost::system::error_code& ec, | |
267 | std::size_t bytes_transferred, int start = 0) | |
268 | { | |
269 | std::size_t max_size; | |
270 | switch (start_ = start) | |
271 | { | |
272 | case 1: | |
273 | max_size = this->check_for_completion(ec, buffers_.total_consumed()); | |
274 | do | |
275 | { | |
276 | stream_.async_read_some(buffers_.prepare(max_size), | |
277 | BOOST_ASIO_MOVE_CAST(read_op)(*this)); | |
278 | return; default: | |
279 | buffers_.consume(bytes_transferred); | |
280 | if ((!ec && bytes_transferred == 0) || buffers_.empty()) | |
281 | break; | |
282 | max_size = this->check_for_completion(ec, buffers_.total_consumed()); | |
283 | } while (max_size > 0); | |
284 | ||
285 | handler_(ec, buffers_.total_consumed()); | |
286 | } | |
287 | } | |
288 | ||
289 | //private: | |
290 | AsyncReadStream& stream_; | |
291 | boost::asio::detail::consuming_buffers<mutable_buffer, | |
292 | MutableBufferSequence, MutableBufferIterator> buffers_; | |
293 | int start_; | |
294 | ReadHandler handler_; | |
295 | }; | |
296 | ||
297 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
298 | typename MutableBufferIterator, typename CompletionCondition, | |
299 | typename ReadHandler> | |
300 | inline void* asio_handler_allocate(std::size_t size, | |
301 | read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, | |
302 | CompletionCondition, ReadHandler>* this_handler) | |
303 | { | |
304 | return boost_asio_handler_alloc_helpers::allocate( | |
305 | size, this_handler->handler_); | |
306 | } | |
307 | ||
308 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
309 | typename MutableBufferIterator, typename CompletionCondition, | |
310 | typename ReadHandler> | |
311 | inline void asio_handler_deallocate(void* pointer, std::size_t size, | |
312 | read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, | |
313 | CompletionCondition, ReadHandler>* this_handler) | |
314 | { | |
315 | boost_asio_handler_alloc_helpers::deallocate( | |
316 | pointer, size, this_handler->handler_); | |
317 | } | |
318 | ||
319 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
320 | typename MutableBufferIterator, typename CompletionCondition, | |
321 | typename ReadHandler> | |
322 | inline bool asio_handler_is_continuation( | |
323 | read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, | |
324 | CompletionCondition, ReadHandler>* this_handler) | |
325 | { | |
326 | return this_handler->start_ == 0 ? true | |
327 | : boost_asio_handler_cont_helpers::is_continuation( | |
328 | this_handler->handler_); | |
329 | } | |
330 | ||
331 | template <typename Function, typename AsyncReadStream, | |
332 | typename MutableBufferSequence, typename MutableBufferIterator, | |
333 | typename CompletionCondition, typename ReadHandler> | |
334 | inline void asio_handler_invoke(Function& function, | |
335 | read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, | |
336 | CompletionCondition, ReadHandler>* this_handler) | |
337 | { | |
338 | boost_asio_handler_invoke_helpers::invoke( | |
339 | function, this_handler->handler_); | |
340 | } | |
341 | ||
342 | template <typename Function, typename AsyncReadStream, | |
343 | typename MutableBufferSequence, typename MutableBufferIterator, | |
344 | typename CompletionCondition, typename ReadHandler> | |
345 | inline void asio_handler_invoke(const Function& function, | |
346 | read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, | |
347 | CompletionCondition, ReadHandler>* this_handler) | |
348 | { | |
349 | boost_asio_handler_invoke_helpers::invoke( | |
350 | function, this_handler->handler_); | |
351 | } | |
352 | ||
353 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
354 | typename MutableBufferIterator, typename CompletionCondition, | |
355 | typename ReadHandler> | |
356 | inline void start_read_buffer_sequence_op(AsyncReadStream& stream, | |
357 | const MutableBufferSequence& buffers, const MutableBufferIterator&, | |
358 | CompletionCondition completion_condition, ReadHandler& handler) | |
359 | { | |
360 | detail::read_op<AsyncReadStream, MutableBufferSequence, | |
361 | MutableBufferIterator, CompletionCondition, ReadHandler>( | |
362 | stream, buffers, completion_condition, handler)( | |
363 | boost::system::error_code(), 0, 1); | |
364 | } | |
365 | } // namespace detail | |
366 | ||
367 | #if !defined(GENERATING_DOCUMENTATION) | |
368 | ||
369 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
370 | typename MutableBufferIterator, typename CompletionCondition, | |
371 | typename ReadHandler, typename Allocator> | |
372 | struct associated_allocator< | |
373 | detail::read_op<AsyncReadStream, MutableBufferSequence, | |
374 | MutableBufferIterator, CompletionCondition, ReadHandler>, | |
375 | Allocator> | |
376 | { | |
377 | typedef typename associated_allocator<ReadHandler, Allocator>::type type; | |
378 | ||
379 | static type get( | |
380 | const detail::read_op<AsyncReadStream, MutableBufferSequence, | |
381 | MutableBufferIterator, CompletionCondition, ReadHandler>& h, | |
382 | const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT | |
383 | { | |
384 | return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); | |
385 | } | |
386 | }; | |
387 | ||
388 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
389 | typename MutableBufferIterator, typename CompletionCondition, | |
390 | typename ReadHandler, typename Executor> | |
391 | struct associated_executor< | |
392 | detail::read_op<AsyncReadStream, MutableBufferSequence, | |
393 | MutableBufferIterator, CompletionCondition, ReadHandler>, | |
394 | Executor> | |
395 | { | |
396 | typedef typename associated_executor<ReadHandler, Executor>::type type; | |
397 | ||
398 | static type get( | |
399 | const detail::read_op<AsyncReadStream, MutableBufferSequence, | |
400 | MutableBufferIterator, CompletionCondition, ReadHandler>& h, | |
401 | const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT | |
402 | { | |
403 | return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); | |
404 | } | |
405 | }; | |
406 | ||
407 | #endif // !defined(GENERATING_DOCUMENTATION) | |
408 | ||
409 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
410 | typename CompletionCondition, typename ReadHandler> | |
411 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, | |
412 | void (boost::system::error_code, std::size_t)) | |
413 | async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, | |
414 | CompletionCondition completion_condition, | |
415 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler, | |
416 | typename enable_if< | |
417 | is_mutable_buffer_sequence<MutableBufferSequence>::value | |
418 | >::type*) | |
419 | { | |
420 | // If you get an error on the following line it means that your handler does | |
421 | // not meet the documented type requirements for a ReadHandler. | |
422 | BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; | |
423 | ||
424 | async_completion<ReadHandler, | |
425 | void (boost::system::error_code, std::size_t)> init(handler); | |
426 | ||
427 | detail::start_read_buffer_sequence_op(s, buffers, | |
428 | boost::asio::buffer_sequence_begin(buffers), completion_condition, | |
429 | init.completion_handler); | |
430 | ||
431 | return init.result.get(); | |
432 | } | |
433 | ||
434 | template <typename AsyncReadStream, typename MutableBufferSequence, | |
435 | typename ReadHandler> | |
436 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, | |
437 | void (boost::system::error_code, std::size_t)) | |
438 | async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, | |
439 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler, | |
440 | typename enable_if< | |
441 | is_mutable_buffer_sequence<MutableBufferSequence>::value | |
442 | >::type*) | |
443 | { | |
444 | // If you get an error on the following line it means that your handler does | |
445 | // not meet the documented type requirements for a ReadHandler. | |
446 | BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; | |
447 | ||
448 | async_completion<ReadHandler, | |
449 | void (boost::system::error_code, std::size_t)> init(handler); | |
450 | ||
451 | detail::start_read_buffer_sequence_op(s, buffers, | |
452 | boost::asio::buffer_sequence_begin(buffers), transfer_all(), | |
453 | init.completion_handler); | |
454 | ||
455 | return init.result.get(); | |
456 | } | |
457 | ||
458 | namespace detail | |
459 | { | |
460 | template <typename AsyncReadStream, typename DynamicBuffer, | |
461 | typename CompletionCondition, typename ReadHandler> | |
462 | class read_dynbuf_op | |
463 | : detail::base_from_completion_cond<CompletionCondition> | |
464 | { | |
465 | public: | |
466 | template <typename BufferSequence> | |
467 | read_dynbuf_op(AsyncReadStream& stream, | |
468 | BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, | |
469 | CompletionCondition completion_condition, ReadHandler& handler) | |
470 | : detail::base_from_completion_cond< | |
471 | CompletionCondition>(completion_condition), | |
472 | stream_(stream), | |
473 | buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), | |
474 | start_(0), | |
475 | total_transferred_(0), | |
476 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) | |
477 | { | |
478 | } | |
479 | ||
480 | #if defined(BOOST_ASIO_HAS_MOVE) | |
481 | read_dynbuf_op(const read_dynbuf_op& other) | |
482 | : detail::base_from_completion_cond<CompletionCondition>(other), | |
483 | stream_(other.stream_), | |
484 | buffers_(other.buffers_), | |
485 | start_(other.start_), | |
486 | total_transferred_(other.total_transferred_), | |
487 | handler_(other.handler_) | |
488 | { | |
489 | } | |
490 | ||
491 | read_dynbuf_op(read_dynbuf_op&& other) | |
492 | : detail::base_from_completion_cond<CompletionCondition>(other), | |
493 | stream_(other.stream_), | |
494 | buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), | |
495 | start_(other.start_), | |
496 | total_transferred_(other.total_transferred_), | |
497 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) | |
498 | { | |
499 | } | |
500 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
501 | ||
502 | void operator()(const boost::system::error_code& ec, | |
503 | std::size_t bytes_transferred, int start = 0) | |
504 | { | |
505 | std::size_t max_size, bytes_available; | |
506 | switch (start_ = start) | |
507 | { | |
508 | case 1: | |
509 | max_size = this->check_for_completion(ec, total_transferred_); | |
510 | bytes_available = std::min<std::size_t>( | |
511 | std::max<std::size_t>(512, | |
512 | buffers_.capacity() - buffers_.size()), | |
513 | std::min<std::size_t>(max_size, | |
514 | buffers_.max_size() - buffers_.size())); | |
515 | for (;;) | |
516 | { | |
517 | stream_.async_read_some(buffers_.prepare(bytes_available), | |
518 | BOOST_ASIO_MOVE_CAST(read_dynbuf_op)(*this)); | |
519 | return; default: | |
520 | total_transferred_ += bytes_transferred; | |
521 | buffers_.commit(bytes_transferred); | |
522 | max_size = this->check_for_completion(ec, total_transferred_); | |
523 | bytes_available = std::min<std::size_t>( | |
524 | std::max<std::size_t>(512, | |
525 | buffers_.capacity() - buffers_.size()), | |
526 | std::min<std::size_t>(max_size, | |
527 | buffers_.max_size() - buffers_.size())); | |
528 | if ((!ec && bytes_transferred == 0) || bytes_available == 0) | |
529 | break; | |
530 | } | |
531 | ||
532 | handler_(ec, static_cast<const std::size_t&>(total_transferred_)); | |
533 | } | |
534 | } | |
535 | ||
536 | //private: | |
537 | AsyncReadStream& stream_; | |
538 | DynamicBuffer buffers_; | |
539 | int start_; | |
540 | std::size_t total_transferred_; | |
541 | ReadHandler handler_; | |
542 | }; | |
543 | ||
544 | template <typename AsyncReadStream, typename DynamicBuffer, | |
545 | typename CompletionCondition, typename ReadHandler> | |
546 | inline void* asio_handler_allocate(std::size_t size, | |
547 | read_dynbuf_op<AsyncReadStream, DynamicBuffer, | |
548 | CompletionCondition, ReadHandler>* this_handler) | |
549 | { | |
550 | return boost_asio_handler_alloc_helpers::allocate( | |
551 | size, this_handler->handler_); | |
552 | } | |
553 | ||
554 | template <typename AsyncReadStream, typename DynamicBuffer, | |
555 | typename CompletionCondition, typename ReadHandler> | |
556 | inline void asio_handler_deallocate(void* pointer, std::size_t size, | |
557 | read_dynbuf_op<AsyncReadStream, DynamicBuffer, | |
558 | CompletionCondition, ReadHandler>* this_handler) | |
559 | { | |
560 | boost_asio_handler_alloc_helpers::deallocate( | |
561 | pointer, size, this_handler->handler_); | |
562 | } | |
563 | ||
564 | template <typename AsyncReadStream, typename DynamicBuffer, | |
565 | typename CompletionCondition, typename ReadHandler> | |
566 | inline bool asio_handler_is_continuation( | |
567 | read_dynbuf_op<AsyncReadStream, DynamicBuffer, | |
568 | CompletionCondition, ReadHandler>* this_handler) | |
569 | { | |
570 | return this_handler->start_ == 0 ? true | |
571 | : boost_asio_handler_cont_helpers::is_continuation( | |
572 | this_handler->handler_); | |
573 | } | |
574 | ||
575 | template <typename Function, typename AsyncReadStream, | |
576 | typename DynamicBuffer, typename CompletionCondition, | |
577 | typename ReadHandler> | |
578 | inline void asio_handler_invoke(Function& function, | |
579 | read_dynbuf_op<AsyncReadStream, DynamicBuffer, | |
580 | CompletionCondition, ReadHandler>* this_handler) | |
581 | { | |
582 | boost_asio_handler_invoke_helpers::invoke( | |
583 | function, this_handler->handler_); | |
584 | } | |
585 | ||
586 | template <typename Function, typename AsyncReadStream, | |
587 | typename DynamicBuffer, typename CompletionCondition, | |
588 | typename ReadHandler> | |
589 | inline void asio_handler_invoke(const Function& function, | |
590 | read_dynbuf_op<AsyncReadStream, DynamicBuffer, | |
591 | CompletionCondition, ReadHandler>* this_handler) | |
592 | { | |
593 | boost_asio_handler_invoke_helpers::invoke( | |
594 | function, this_handler->handler_); | |
595 | } | |
596 | } // namespace detail | |
597 | ||
598 | #if !defined(GENERATING_DOCUMENTATION) | |
599 | ||
600 | template <typename AsyncReadStream, typename DynamicBuffer, | |
601 | typename CompletionCondition, typename ReadHandler, typename Allocator> | |
602 | struct associated_allocator< | |
603 | detail::read_dynbuf_op<AsyncReadStream, | |
604 | DynamicBuffer, CompletionCondition, ReadHandler>, | |
605 | Allocator> | |
606 | { | |
607 | typedef typename associated_allocator<ReadHandler, Allocator>::type type; | |
608 | ||
609 | static type get( | |
610 | const detail::read_dynbuf_op<AsyncReadStream, | |
611 | DynamicBuffer, CompletionCondition, ReadHandler>& h, | |
612 | const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT | |
613 | { | |
614 | return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); | |
615 | } | |
616 | }; | |
617 | ||
618 | template <typename AsyncReadStream, typename DynamicBuffer, | |
619 | typename CompletionCondition, typename ReadHandler, typename Executor> | |
620 | struct associated_executor< | |
621 | detail::read_dynbuf_op<AsyncReadStream, | |
622 | DynamicBuffer, CompletionCondition, ReadHandler>, | |
623 | Executor> | |
624 | { | |
625 | typedef typename associated_executor<ReadHandler, Executor>::type type; | |
626 | ||
627 | static type get( | |
628 | const detail::read_dynbuf_op<AsyncReadStream, | |
629 | DynamicBuffer, CompletionCondition, ReadHandler>& h, | |
630 | const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT | |
631 | { | |
632 | return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); | |
633 | } | |
634 | }; | |
635 | ||
636 | #endif // !defined(GENERATING_DOCUMENTATION) | |
637 | ||
638 | template <typename AsyncReadStream, | |
639 | typename DynamicBuffer, typename ReadHandler> | |
640 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, | |
641 | void (boost::system::error_code, std::size_t)) | |
642 | async_read(AsyncReadStream& s, | |
643 | BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, | |
644 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler, | |
645 | typename enable_if< | |
11fdf7f2 | 646 | is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value |
b32b8144 FG |
647 | >::type*) |
648 | { | |
649 | return async_read(s, | |
650 | BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), | |
651 | transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); | |
652 | } | |
653 | ||
654 | template <typename AsyncReadStream, typename DynamicBuffer, | |
655 | typename CompletionCondition, typename ReadHandler> | |
656 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, | |
657 | void (boost::system::error_code, std::size_t)) | |
658 | async_read(AsyncReadStream& s, | |
659 | BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, | |
660 | CompletionCondition completion_condition, | |
661 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler, | |
662 | typename enable_if< | |
11fdf7f2 | 663 | is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value |
b32b8144 FG |
664 | >::type*) |
665 | { | |
666 | // If you get an error on the following line it means that your handler does | |
667 | // not meet the documented type requirements for a ReadHandler. | |
668 | BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; | |
669 | ||
670 | async_completion<ReadHandler, | |
671 | void (boost::system::error_code, std::size_t)> init(handler); | |
672 | ||
673 | detail::read_dynbuf_op<AsyncReadStream, | |
674 | typename decay<DynamicBuffer>::type, | |
675 | CompletionCondition, BOOST_ASIO_HANDLER_TYPE( | |
676 | ReadHandler, void (boost::system::error_code, std::size_t))>( | |
677 | s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), | |
678 | completion_condition, init.completion_handler)( | |
679 | boost::system::error_code(), 0, 1); | |
680 | ||
681 | return init.result.get(); | |
682 | } | |
683 | ||
684 | #if !defined(BOOST_ASIO_NO_EXTENSIONS) | |
685 | #if !defined(BOOST_ASIO_NO_IOSTREAM) | |
686 | ||
687 | template <typename AsyncReadStream, typename Allocator, typename ReadHandler> | |
688 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, | |
689 | void (boost::system::error_code, std::size_t)) | |
690 | async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, | |
691 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler) | |
692 | { | |
693 | return async_read(s, basic_streambuf_ref<Allocator>(b), | |
694 | BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); | |
695 | } | |
696 | ||
697 | template <typename AsyncReadStream, typename Allocator, | |
698 | typename CompletionCondition, typename ReadHandler> | |
699 | inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, | |
700 | void (boost::system::error_code, std::size_t)) | |
701 | async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, | |
702 | CompletionCondition completion_condition, | |
703 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler) | |
704 | { | |
705 | return async_read(s, basic_streambuf_ref<Allocator>(b), | |
706 | completion_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); | |
707 | } | |
708 | ||
709 | #endif // !defined(BOOST_ASIO_NO_IOSTREAM) | |
710 | #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) | |
711 | ||
712 | } // namespace asio | |
713 | } // namespace boost | |
714 | ||
715 | #include <boost/asio/detail/pop_options.hpp> | |
716 | ||
717 | #endif // BOOST_ASIO_IMPL_READ_HPP |