]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // impl/buffered_read_stream.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
f67539c2 | 5 | // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae 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_BUFFERED_READ_STREAM_HPP | |
12 | #define BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP | |
13 | ||
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) | |
15 | # pragma once | |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) | |
17 | ||
b32b8144 FG |
18 | #include <boost/asio/associated_allocator.hpp> |
19 | #include <boost/asio/associated_executor.hpp> | |
7c673cae FG |
20 | #include <boost/asio/detail/handler_alloc_helpers.hpp> |
21 | #include <boost/asio/detail/handler_cont_helpers.hpp> | |
22 | #include <boost/asio/detail/handler_invoke_helpers.hpp> | |
23 | #include <boost/asio/detail/handler_type_requirements.hpp> | |
92f5a8d4 TL |
24 | #include <boost/asio/detail/non_const_lvalue.hpp> |
25 | #include <boost/asio/detail/type_traits.hpp> | |
7c673cae FG |
26 | |
27 | #include <boost/asio/detail/push_options.hpp> | |
28 | ||
29 | namespace boost { | |
30 | namespace asio { | |
31 | ||
32 | template <typename Stream> | |
33 | std::size_t buffered_read_stream<Stream>::fill() | |
34 | { | |
35 | detail::buffer_resize_guard<detail::buffered_stream_storage> | |
36 | resize_guard(storage_); | |
37 | std::size_t previous_size = storage_.size(); | |
38 | storage_.resize(storage_.capacity()); | |
39 | storage_.resize(previous_size + next_layer_.read_some(buffer( | |
40 | storage_.data() + previous_size, | |
41 | storage_.size() - previous_size))); | |
42 | resize_guard.commit(); | |
43 | return storage_.size() - previous_size; | |
44 | } | |
45 | ||
46 | template <typename Stream> | |
47 | std::size_t buffered_read_stream<Stream>::fill(boost::system::error_code& ec) | |
48 | { | |
49 | detail::buffer_resize_guard<detail::buffered_stream_storage> | |
50 | resize_guard(storage_); | |
51 | std::size_t previous_size = storage_.size(); | |
52 | storage_.resize(storage_.capacity()); | |
53 | storage_.resize(previous_size + next_layer_.read_some(buffer( | |
54 | storage_.data() + previous_size, | |
55 | storage_.size() - previous_size), | |
56 | ec)); | |
57 | resize_guard.commit(); | |
58 | return storage_.size() - previous_size; | |
59 | } | |
60 | ||
61 | namespace detail | |
62 | { | |
63 | template <typename ReadHandler> | |
64 | class buffered_fill_handler | |
65 | { | |
66 | public: | |
67 | buffered_fill_handler(detail::buffered_stream_storage& storage, | |
68 | std::size_t previous_size, ReadHandler& handler) | |
69 | : storage_(storage), | |
70 | previous_size_(previous_size), | |
71 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) | |
72 | { | |
73 | } | |
74 | ||
75 | #if defined(BOOST_ASIO_HAS_MOVE) | |
76 | buffered_fill_handler(const buffered_fill_handler& other) | |
77 | : storage_(other.storage_), | |
78 | previous_size_(other.previous_size_), | |
79 | handler_(other.handler_) | |
80 | { | |
81 | } | |
82 | ||
83 | buffered_fill_handler(buffered_fill_handler&& other) | |
84 | : storage_(other.storage_), | |
85 | previous_size_(other.previous_size_), | |
86 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) | |
87 | { | |
88 | } | |
89 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
90 | ||
91 | void operator()(const boost::system::error_code& ec, | |
92 | const std::size_t bytes_transferred) | |
93 | { | |
94 | storage_.resize(previous_size_ + bytes_transferred); | |
95 | handler_(ec, bytes_transferred); | |
96 | } | |
97 | ||
98 | //private: | |
99 | detail::buffered_stream_storage& storage_; | |
100 | std::size_t previous_size_; | |
101 | ReadHandler handler_; | |
102 | }; | |
103 | ||
104 | template <typename ReadHandler> | |
105 | inline void* asio_handler_allocate(std::size_t size, | |
106 | buffered_fill_handler<ReadHandler>* this_handler) | |
107 | { | |
108 | return boost_asio_handler_alloc_helpers::allocate( | |
109 | size, this_handler->handler_); | |
110 | } | |
111 | ||
112 | template <typename ReadHandler> | |
113 | inline void asio_handler_deallocate(void* pointer, std::size_t size, | |
114 | buffered_fill_handler<ReadHandler>* this_handler) | |
115 | { | |
116 | boost_asio_handler_alloc_helpers::deallocate( | |
117 | pointer, size, this_handler->handler_); | |
118 | } | |
119 | ||
120 | template <typename ReadHandler> | |
121 | inline bool asio_handler_is_continuation( | |
122 | buffered_fill_handler<ReadHandler>* this_handler) | |
123 | { | |
124 | return boost_asio_handler_cont_helpers::is_continuation( | |
125 | this_handler->handler_); | |
126 | } | |
127 | ||
128 | template <typename Function, typename ReadHandler> | |
129 | inline void asio_handler_invoke(Function& function, | |
130 | buffered_fill_handler<ReadHandler>* this_handler) | |
131 | { | |
132 | boost_asio_handler_invoke_helpers::invoke( | |
133 | function, this_handler->handler_); | |
134 | } | |
135 | ||
136 | template <typename Function, typename ReadHandler> | |
137 | inline void asio_handler_invoke(const Function& function, | |
138 | buffered_fill_handler<ReadHandler>* this_handler) | |
139 | { | |
140 | boost_asio_handler_invoke_helpers::invoke( | |
141 | function, this_handler->handler_); | |
142 | } | |
92f5a8d4 TL |
143 | |
144 | template <typename Stream> | |
145 | class initiate_async_buffered_fill | |
146 | { | |
147 | public: | |
148 | typedef typename remove_reference< | |
149 | Stream>::type::lowest_layer_type::executor_type executor_type; | |
150 | ||
f67539c2 TL |
151 | explicit initiate_async_buffered_fill( |
152 | typename remove_reference<Stream>::type& next_layer) | |
92f5a8d4 TL |
153 | : next_layer_(next_layer) |
154 | { | |
155 | } | |
156 | ||
157 | executor_type get_executor() const BOOST_ASIO_NOEXCEPT | |
158 | { | |
159 | return next_layer_.lowest_layer().get_executor(); | |
160 | } | |
161 | ||
162 | template <typename ReadHandler> | |
163 | void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, | |
164 | buffered_stream_storage* storage) const | |
165 | { | |
166 | // If you get an error on the following line it means that your handler | |
167 | // does not meet the documented type requirements for a ReadHandler. | |
168 | BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; | |
169 | ||
170 | non_const_lvalue<ReadHandler> handler2(handler); | |
171 | std::size_t previous_size = storage->size(); | |
172 | storage->resize(storage->capacity()); | |
173 | next_layer_.async_read_some( | |
174 | buffer( | |
175 | storage->data() + previous_size, | |
176 | storage->size() - previous_size), | |
177 | buffered_fill_handler<typename decay<ReadHandler>::type>( | |
178 | *storage, previous_size, handler2.value)); | |
179 | } | |
180 | ||
181 | private: | |
f67539c2 | 182 | typename remove_reference<Stream>::type& next_layer_; |
92f5a8d4 | 183 | }; |
7c673cae FG |
184 | } // namespace detail |
185 | ||
b32b8144 FG |
186 | #if !defined(GENERATING_DOCUMENTATION) |
187 | ||
188 | template <typename ReadHandler, typename Allocator> | |
189 | struct associated_allocator< | |
190 | detail::buffered_fill_handler<ReadHandler>, Allocator> | |
191 | { | |
192 | typedef typename associated_allocator<ReadHandler, Allocator>::type type; | |
193 | ||
194 | static type get(const detail::buffered_fill_handler<ReadHandler>& h, | |
195 | const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT | |
196 | { | |
197 | return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); | |
198 | } | |
199 | }; | |
200 | ||
201 | template <typename ReadHandler, typename Executor> | |
202 | struct associated_executor< | |
203 | detail::buffered_fill_handler<ReadHandler>, Executor> | |
204 | { | |
205 | typedef typename associated_executor<ReadHandler, Executor>::type type; | |
206 | ||
207 | static type get(const detail::buffered_fill_handler<ReadHandler>& h, | |
208 | const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT | |
209 | { | |
210 | return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); | |
211 | } | |
212 | }; | |
213 | ||
214 | #endif // !defined(GENERATING_DOCUMENTATION) | |
215 | ||
7c673cae | 216 | template <typename Stream> |
92f5a8d4 TL |
217 | template < |
218 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, | |
219 | std::size_t)) ReadHandler> | |
220 | BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, | |
7c673cae FG |
221 | void (boost::system::error_code, std::size_t)) |
222 | buffered_read_stream<Stream>::async_fill( | |
223 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler) | |
224 | { | |
92f5a8d4 TL |
225 | return async_initiate<ReadHandler, |
226 | void (boost::system::error_code, std::size_t)>( | |
227 | detail::initiate_async_buffered_fill<Stream>(next_layer_), | |
228 | handler, &storage_); | |
7c673cae FG |
229 | } |
230 | ||
231 | template <typename Stream> | |
232 | template <typename MutableBufferSequence> | |
233 | std::size_t buffered_read_stream<Stream>::read_some( | |
234 | const MutableBufferSequence& buffers) | |
235 | { | |
b32b8144 FG |
236 | using boost::asio::buffer_size; |
237 | if (buffer_size(buffers) == 0) | |
7c673cae FG |
238 | return 0; |
239 | ||
240 | if (storage_.empty()) | |
241 | this->fill(); | |
242 | ||
243 | return this->copy(buffers); | |
244 | } | |
245 | ||
246 | template <typename Stream> | |
247 | template <typename MutableBufferSequence> | |
248 | std::size_t buffered_read_stream<Stream>::read_some( | |
249 | const MutableBufferSequence& buffers, boost::system::error_code& ec) | |
250 | { | |
251 | ec = boost::system::error_code(); | |
252 | ||
b32b8144 FG |
253 | using boost::asio::buffer_size; |
254 | if (buffer_size(buffers) == 0) | |
7c673cae FG |
255 | return 0; |
256 | ||
257 | if (storage_.empty() && !this->fill(ec)) | |
258 | return 0; | |
259 | ||
260 | return this->copy(buffers); | |
261 | } | |
262 | ||
263 | namespace detail | |
264 | { | |
265 | template <typename MutableBufferSequence, typename ReadHandler> | |
266 | class buffered_read_some_handler | |
267 | { | |
268 | public: | |
269 | buffered_read_some_handler(detail::buffered_stream_storage& storage, | |
270 | const MutableBufferSequence& buffers, ReadHandler& handler) | |
271 | : storage_(storage), | |
272 | buffers_(buffers), | |
b32b8144 | 273 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) |
7c673cae FG |
274 | { |
275 | } | |
276 | ||
277 | #if defined(BOOST_ASIO_HAS_MOVE) | |
278 | buffered_read_some_handler(const buffered_read_some_handler& other) | |
279 | : storage_(other.storage_), | |
280 | buffers_(other.buffers_), | |
281 | handler_(other.handler_) | |
282 | { | |
283 | } | |
284 | ||
285 | buffered_read_some_handler(buffered_read_some_handler&& other) | |
286 | : storage_(other.storage_), | |
287 | buffers_(other.buffers_), | |
288 | handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) | |
289 | { | |
290 | } | |
291 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
292 | ||
293 | void operator()(const boost::system::error_code& ec, std::size_t) | |
294 | { | |
295 | if (ec || storage_.empty()) | |
296 | { | |
297 | const std::size_t length = 0; | |
298 | handler_(ec, length); | |
299 | } | |
300 | else | |
301 | { | |
302 | const std::size_t bytes_copied = boost::asio::buffer_copy( | |
303 | buffers_, storage_.data(), storage_.size()); | |
304 | storage_.consume(bytes_copied); | |
305 | handler_(ec, bytes_copied); | |
306 | } | |
307 | } | |
308 | ||
309 | //private: | |
310 | detail::buffered_stream_storage& storage_; | |
311 | MutableBufferSequence buffers_; | |
312 | ReadHandler handler_; | |
313 | }; | |
314 | ||
315 | template <typename MutableBufferSequence, typename ReadHandler> | |
316 | inline void* asio_handler_allocate(std::size_t size, | |
317 | buffered_read_some_handler< | |
318 | MutableBufferSequence, ReadHandler>* this_handler) | |
319 | { | |
320 | return boost_asio_handler_alloc_helpers::allocate( | |
321 | size, this_handler->handler_); | |
322 | } | |
323 | ||
324 | template <typename MutableBufferSequence, typename ReadHandler> | |
325 | inline void asio_handler_deallocate(void* pointer, std::size_t size, | |
326 | buffered_read_some_handler< | |
327 | MutableBufferSequence, ReadHandler>* this_handler) | |
328 | { | |
329 | boost_asio_handler_alloc_helpers::deallocate( | |
330 | pointer, size, this_handler->handler_); | |
331 | } | |
332 | ||
333 | template <typename MutableBufferSequence, typename ReadHandler> | |
334 | inline bool asio_handler_is_continuation( | |
335 | buffered_read_some_handler< | |
336 | MutableBufferSequence, ReadHandler>* this_handler) | |
337 | { | |
338 | return boost_asio_handler_cont_helpers::is_continuation( | |
339 | this_handler->handler_); | |
340 | } | |
341 | ||
342 | template <typename Function, typename MutableBufferSequence, | |
343 | typename ReadHandler> | |
344 | inline void asio_handler_invoke(Function& function, | |
345 | buffered_read_some_handler< | |
346 | MutableBufferSequence, ReadHandler>* this_handler) | |
347 | { | |
348 | boost_asio_handler_invoke_helpers::invoke( | |
349 | function, this_handler->handler_); | |
350 | } | |
351 | ||
352 | template <typename Function, typename MutableBufferSequence, | |
353 | typename ReadHandler> | |
354 | inline void asio_handler_invoke(const Function& function, | |
355 | buffered_read_some_handler< | |
356 | MutableBufferSequence, ReadHandler>* this_handler) | |
357 | { | |
358 | boost_asio_handler_invoke_helpers::invoke( | |
359 | function, this_handler->handler_); | |
360 | } | |
92f5a8d4 TL |
361 | |
362 | template <typename Stream> | |
363 | class initiate_async_buffered_read_some | |
364 | { | |
365 | public: | |
366 | typedef typename remove_reference< | |
367 | Stream>::type::lowest_layer_type::executor_type executor_type; | |
368 | ||
f67539c2 TL |
369 | explicit initiate_async_buffered_read_some( |
370 | typename remove_reference<Stream>::type& next_layer) | |
92f5a8d4 TL |
371 | : next_layer_(next_layer) |
372 | { | |
373 | } | |
374 | ||
375 | executor_type get_executor() const BOOST_ASIO_NOEXCEPT | |
376 | { | |
377 | return next_layer_.lowest_layer().get_executor(); | |
378 | } | |
379 | ||
380 | template <typename ReadHandler, typename MutableBufferSequence> | |
381 | void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, | |
382 | buffered_stream_storage* storage, | |
383 | const MutableBufferSequence& buffers) const | |
384 | { | |
385 | // If you get an error on the following line it means that your handler | |
386 | // does not meet the documented type requirements for a ReadHandler. | |
387 | BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; | |
388 | ||
389 | using boost::asio::buffer_size; | |
390 | non_const_lvalue<ReadHandler> handler2(handler); | |
391 | if (buffer_size(buffers) == 0 || !storage->empty()) | |
392 | { | |
393 | next_layer_.async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), | |
394 | buffered_read_some_handler<MutableBufferSequence, | |
395 | typename decay<ReadHandler>::type>( | |
396 | *storage, buffers, handler2.value)); | |
397 | } | |
398 | else | |
399 | { | |
400 | initiate_async_buffered_fill<Stream>(this->next_layer_)( | |
401 | buffered_read_some_handler<MutableBufferSequence, | |
402 | typename decay<ReadHandler>::type>( | |
403 | *storage, buffers, handler2.value), | |
404 | storage); | |
405 | } | |
406 | } | |
407 | ||
408 | private: | |
f67539c2 | 409 | typename remove_reference<Stream>::type& next_layer_; |
92f5a8d4 | 410 | }; |
7c673cae FG |
411 | } // namespace detail |
412 | ||
b32b8144 FG |
413 | #if !defined(GENERATING_DOCUMENTATION) |
414 | ||
415 | template <typename MutableBufferSequence, | |
416 | typename ReadHandler, typename Allocator> | |
417 | struct associated_allocator< | |
418 | detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, | |
419 | Allocator> | |
420 | { | |
421 | typedef typename associated_allocator<ReadHandler, Allocator>::type type; | |
422 | ||
423 | static type get( | |
424 | const detail::buffered_read_some_handler< | |
425 | MutableBufferSequence, ReadHandler>& h, | |
426 | const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT | |
427 | { | |
428 | return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); | |
429 | } | |
430 | }; | |
431 | ||
432 | template <typename MutableBufferSequence, | |
433 | typename ReadHandler, typename Executor> | |
434 | struct associated_executor< | |
435 | detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, | |
436 | Executor> | |
437 | { | |
438 | typedef typename associated_executor<ReadHandler, Executor>::type type; | |
439 | ||
440 | static type get( | |
441 | const detail::buffered_read_some_handler< | |
442 | MutableBufferSequence, ReadHandler>& h, | |
443 | const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT | |
444 | { | |
445 | return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); | |
446 | } | |
447 | }; | |
448 | ||
449 | #endif // !defined(GENERATING_DOCUMENTATION) | |
450 | ||
7c673cae | 451 | template <typename Stream> |
92f5a8d4 TL |
452 | template <typename MutableBufferSequence, |
453 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, | |
454 | std::size_t)) ReadHandler> | |
455 | BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, | |
7c673cae FG |
456 | void (boost::system::error_code, std::size_t)) |
457 | buffered_read_stream<Stream>::async_read_some( | |
458 | const MutableBufferSequence& buffers, | |
459 | BOOST_ASIO_MOVE_ARG(ReadHandler) handler) | |
460 | { | |
92f5a8d4 TL |
461 | return async_initiate<ReadHandler, |
462 | void (boost::system::error_code, std::size_t)>( | |
463 | detail::initiate_async_buffered_read_some<Stream>(next_layer_), | |
464 | handler, &storage_, buffers); | |
7c673cae FG |
465 | } |
466 | ||
467 | template <typename Stream> | |
468 | template <typename MutableBufferSequence> | |
469 | std::size_t buffered_read_stream<Stream>::peek( | |
470 | const MutableBufferSequence& buffers) | |
471 | { | |
472 | if (storage_.empty()) | |
473 | this->fill(); | |
474 | return this->peek_copy(buffers); | |
475 | } | |
476 | ||
477 | template <typename Stream> | |
478 | template <typename MutableBufferSequence> | |
479 | std::size_t buffered_read_stream<Stream>::peek( | |
480 | const MutableBufferSequence& buffers, boost::system::error_code& ec) | |
481 | { | |
482 | ec = boost::system::error_code(); | |
483 | if (storage_.empty() && !this->fill(ec)) | |
484 | return 0; | |
485 | return this->peek_copy(buffers); | |
486 | } | |
487 | ||
488 | } // namespace asio | |
489 | } // namespace boost | |
490 | ||
491 | #include <boost/asio/detail/pop_options.hpp> | |
492 | ||
493 | #endif // BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP |