2 // impl/buffered_read_stream.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP
12 #define BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/associated_allocator.hpp>
19 #include <boost/asio/associated_executor.hpp>
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>
24 #include <boost/asio/detail/non_const_lvalue.hpp>
25 #include <boost/asio/detail/type_traits.hpp>
27 #include <boost/asio/detail/push_options.hpp>
32 template <typename Stream>
33 std::size_t buffered_read_stream<Stream>::fill()
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;
46 template <typename Stream>
47 std::size_t buffered_read_stream<Stream>::fill(boost::system::error_code& ec)
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),
57 resize_guard.commit();
58 return storage_.size() - previous_size;
63 template <typename ReadHandler>
64 class buffered_fill_handler
67 buffered_fill_handler(detail::buffered_stream_storage& storage,
68 std::size_t previous_size, ReadHandler& handler)
70 previous_size_(previous_size),
71 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
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_)
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_))
89 #endif // defined(BOOST_ASIO_HAS_MOVE)
91 void operator()(const boost::system::error_code& ec,
92 const std::size_t bytes_transferred)
94 storage_.resize(previous_size_ + bytes_transferred);
95 handler_(ec, bytes_transferred);
99 detail::buffered_stream_storage& storage_;
100 std::size_t previous_size_;
101 ReadHandler handler_;
104 template <typename ReadHandler>
105 inline void* asio_handler_allocate(std::size_t size,
106 buffered_fill_handler<ReadHandler>* this_handler)
108 return boost_asio_handler_alloc_helpers::allocate(
109 size, this_handler->handler_);
112 template <typename ReadHandler>
113 inline void asio_handler_deallocate(void* pointer, std::size_t size,
114 buffered_fill_handler<ReadHandler>* this_handler)
116 boost_asio_handler_alloc_helpers::deallocate(
117 pointer, size, this_handler->handler_);
120 template <typename ReadHandler>
121 inline bool asio_handler_is_continuation(
122 buffered_fill_handler<ReadHandler>* this_handler)
124 return boost_asio_handler_cont_helpers::is_continuation(
125 this_handler->handler_);
128 template <typename Function, typename ReadHandler>
129 inline void asio_handler_invoke(Function& function,
130 buffered_fill_handler<ReadHandler>* this_handler)
132 boost_asio_handler_invoke_helpers::invoke(
133 function, this_handler->handler_);
136 template <typename Function, typename ReadHandler>
137 inline void asio_handler_invoke(const Function& function,
138 buffered_fill_handler<ReadHandler>* this_handler)
140 boost_asio_handler_invoke_helpers::invoke(
141 function, this_handler->handler_);
144 template <typename Stream>
145 class initiate_async_buffered_fill
148 typedef typename remove_reference<
149 Stream>::type::lowest_layer_type::executor_type executor_type;
151 explicit initiate_async_buffered_fill(Stream& next_layer)
152 : next_layer_(next_layer)
156 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
158 return next_layer_.lowest_layer().get_executor();
161 template <typename ReadHandler>
162 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
163 buffered_stream_storage* storage) const
165 // If you get an error on the following line it means that your handler
166 // does not meet the documented type requirements for a ReadHandler.
167 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
169 non_const_lvalue<ReadHandler> handler2(handler);
170 std::size_t previous_size = storage->size();
171 storage->resize(storage->capacity());
172 next_layer_.async_read_some(
174 storage->data() + previous_size,
175 storage->size() - previous_size),
176 buffered_fill_handler<typename decay<ReadHandler>::type>(
177 *storage, previous_size, handler2.value));
183 } // namespace detail
185 #if !defined(GENERATING_DOCUMENTATION)
187 template <typename ReadHandler, typename Allocator>
188 struct associated_allocator<
189 detail::buffered_fill_handler<ReadHandler>, Allocator>
191 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
193 static type get(const detail::buffered_fill_handler<ReadHandler>& h,
194 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
196 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
200 template <typename ReadHandler, typename Executor>
201 struct associated_executor<
202 detail::buffered_fill_handler<ReadHandler>, Executor>
204 typedef typename associated_executor<ReadHandler, Executor>::type type;
206 static type get(const detail::buffered_fill_handler<ReadHandler>& h,
207 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
209 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
213 #endif // !defined(GENERATING_DOCUMENTATION)
215 template <typename Stream>
217 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
218 std::size_t)) ReadHandler>
219 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
220 void (boost::system::error_code, std::size_t))
221 buffered_read_stream<Stream>::async_fill(
222 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
224 return async_initiate<ReadHandler,
225 void (boost::system::error_code, std::size_t)>(
226 detail::initiate_async_buffered_fill<Stream>(next_layer_),
230 template <typename Stream>
231 template <typename MutableBufferSequence>
232 std::size_t buffered_read_stream<Stream>::read_some(
233 const MutableBufferSequence& buffers)
235 using boost::asio::buffer_size;
236 if (buffer_size(buffers) == 0)
239 if (storage_.empty())
242 return this->copy(buffers);
245 template <typename Stream>
246 template <typename MutableBufferSequence>
247 std::size_t buffered_read_stream<Stream>::read_some(
248 const MutableBufferSequence& buffers, boost::system::error_code& ec)
250 ec = boost::system::error_code();
252 using boost::asio::buffer_size;
253 if (buffer_size(buffers) == 0)
256 if (storage_.empty() && !this->fill(ec))
259 return this->copy(buffers);
264 template <typename MutableBufferSequence, typename ReadHandler>
265 class buffered_read_some_handler
268 buffered_read_some_handler(detail::buffered_stream_storage& storage,
269 const MutableBufferSequence& buffers, ReadHandler& handler)
272 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
276 #if defined(BOOST_ASIO_HAS_MOVE)
277 buffered_read_some_handler(const buffered_read_some_handler& other)
278 : storage_(other.storage_),
279 buffers_(other.buffers_),
280 handler_(other.handler_)
284 buffered_read_some_handler(buffered_read_some_handler&& other)
285 : storage_(other.storage_),
286 buffers_(other.buffers_),
287 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
290 #endif // defined(BOOST_ASIO_HAS_MOVE)
292 void operator()(const boost::system::error_code& ec, std::size_t)
294 if (ec || storage_.empty())
296 const std::size_t length = 0;
297 handler_(ec, length);
301 const std::size_t bytes_copied = boost::asio::buffer_copy(
302 buffers_, storage_.data(), storage_.size());
303 storage_.consume(bytes_copied);
304 handler_(ec, bytes_copied);
309 detail::buffered_stream_storage& storage_;
310 MutableBufferSequence buffers_;
311 ReadHandler handler_;
314 template <typename MutableBufferSequence, typename ReadHandler>
315 inline void* asio_handler_allocate(std::size_t size,
316 buffered_read_some_handler<
317 MutableBufferSequence, ReadHandler>* this_handler)
319 return boost_asio_handler_alloc_helpers::allocate(
320 size, this_handler->handler_);
323 template <typename MutableBufferSequence, typename ReadHandler>
324 inline void asio_handler_deallocate(void* pointer, std::size_t size,
325 buffered_read_some_handler<
326 MutableBufferSequence, ReadHandler>* this_handler)
328 boost_asio_handler_alloc_helpers::deallocate(
329 pointer, size, this_handler->handler_);
332 template <typename MutableBufferSequence, typename ReadHandler>
333 inline bool asio_handler_is_continuation(
334 buffered_read_some_handler<
335 MutableBufferSequence, ReadHandler>* this_handler)
337 return boost_asio_handler_cont_helpers::is_continuation(
338 this_handler->handler_);
341 template <typename Function, typename MutableBufferSequence,
342 typename ReadHandler>
343 inline void asio_handler_invoke(Function& function,
344 buffered_read_some_handler<
345 MutableBufferSequence, ReadHandler>* this_handler)
347 boost_asio_handler_invoke_helpers::invoke(
348 function, this_handler->handler_);
351 template <typename Function, typename MutableBufferSequence,
352 typename ReadHandler>
353 inline void asio_handler_invoke(const Function& function,
354 buffered_read_some_handler<
355 MutableBufferSequence, ReadHandler>* this_handler)
357 boost_asio_handler_invoke_helpers::invoke(
358 function, this_handler->handler_);
361 template <typename Stream>
362 class initiate_async_buffered_read_some
365 typedef typename remove_reference<
366 Stream>::type::lowest_layer_type::executor_type executor_type;
368 explicit initiate_async_buffered_read_some(Stream& next_layer)
369 : next_layer_(next_layer)
373 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
375 return next_layer_.lowest_layer().get_executor();
378 template <typename ReadHandler, typename MutableBufferSequence>
379 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
380 buffered_stream_storage* storage,
381 const MutableBufferSequence& buffers) const
383 // If you get an error on the following line it means that your handler
384 // does not meet the documented type requirements for a ReadHandler.
385 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
387 using boost::asio::buffer_size;
388 non_const_lvalue<ReadHandler> handler2(handler);
389 if (buffer_size(buffers) == 0 || !storage->empty())
391 next_layer_.async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0),
392 buffered_read_some_handler<MutableBufferSequence,
393 typename decay<ReadHandler>::type>(
394 *storage, buffers, handler2.value));
398 initiate_async_buffered_fill<Stream>(this->next_layer_)(
399 buffered_read_some_handler<MutableBufferSequence,
400 typename decay<ReadHandler>::type>(
401 *storage, buffers, handler2.value),
409 } // namespace detail
411 #if !defined(GENERATING_DOCUMENTATION)
413 template <typename MutableBufferSequence,
414 typename ReadHandler, typename Allocator>
415 struct associated_allocator<
416 detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,
419 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
422 const detail::buffered_read_some_handler<
423 MutableBufferSequence, ReadHandler>& h,
424 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
426 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
430 template <typename MutableBufferSequence,
431 typename ReadHandler, typename Executor>
432 struct associated_executor<
433 detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,
436 typedef typename associated_executor<ReadHandler, Executor>::type type;
439 const detail::buffered_read_some_handler<
440 MutableBufferSequence, ReadHandler>& h,
441 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
443 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
447 #endif // !defined(GENERATING_DOCUMENTATION)
449 template <typename Stream>
450 template <typename MutableBufferSequence,
451 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
452 std::size_t)) ReadHandler>
453 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
454 void (boost::system::error_code, std::size_t))
455 buffered_read_stream<Stream>::async_read_some(
456 const MutableBufferSequence& buffers,
457 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
459 return async_initiate<ReadHandler,
460 void (boost::system::error_code, std::size_t)>(
461 detail::initiate_async_buffered_read_some<Stream>(next_layer_),
462 handler, &storage_, buffers);
465 template <typename Stream>
466 template <typename MutableBufferSequence>
467 std::size_t buffered_read_stream<Stream>::peek(
468 const MutableBufferSequence& buffers)
470 if (storage_.empty())
472 return this->peek_copy(buffers);
475 template <typename Stream>
476 template <typename MutableBufferSequence>
477 std::size_t buffered_read_stream<Stream>::peek(
478 const MutableBufferSequence& buffers, boost::system::error_code& ec)
480 ec = boost::system::error_code();
481 if (storage_.empty() && !this->fill(ec))
483 return this->peek_copy(buffers);
489 #include <boost/asio/detail/pop_options.hpp>
491 #endif // BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP