2 // impl/buffered_read_stream.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2017 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>
25 #include <boost/asio/detail/push_options.hpp>
30 template <typename Stream>
31 std::size_t buffered_read_stream<Stream>::fill()
33 detail::buffer_resize_guard<detail::buffered_stream_storage>
34 resize_guard(storage_);
35 std::size_t previous_size = storage_.size();
36 storage_.resize(storage_.capacity());
37 storage_.resize(previous_size + next_layer_.read_some(buffer(
38 storage_.data() + previous_size,
39 storage_.size() - previous_size)));
40 resize_guard.commit();
41 return storage_.size() - previous_size;
44 template <typename Stream>
45 std::size_t buffered_read_stream<Stream>::fill(boost::system::error_code& ec)
47 detail::buffer_resize_guard<detail::buffered_stream_storage>
48 resize_guard(storage_);
49 std::size_t previous_size = storage_.size();
50 storage_.resize(storage_.capacity());
51 storage_.resize(previous_size + next_layer_.read_some(buffer(
52 storage_.data() + previous_size,
53 storage_.size() - previous_size),
55 resize_guard.commit();
56 return storage_.size() - previous_size;
61 template <typename ReadHandler>
62 class buffered_fill_handler
65 buffered_fill_handler(detail::buffered_stream_storage& storage,
66 std::size_t previous_size, ReadHandler& handler)
68 previous_size_(previous_size),
69 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
73 #if defined(BOOST_ASIO_HAS_MOVE)
74 buffered_fill_handler(const buffered_fill_handler& other)
75 : storage_(other.storage_),
76 previous_size_(other.previous_size_),
77 handler_(other.handler_)
81 buffered_fill_handler(buffered_fill_handler&& other)
82 : storage_(other.storage_),
83 previous_size_(other.previous_size_),
84 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
87 #endif // defined(BOOST_ASIO_HAS_MOVE)
89 void operator()(const boost::system::error_code& ec,
90 const std::size_t bytes_transferred)
92 storage_.resize(previous_size_ + bytes_transferred);
93 handler_(ec, bytes_transferred);
97 detail::buffered_stream_storage& storage_;
98 std::size_t previous_size_;
102 template <typename ReadHandler>
103 inline void* asio_handler_allocate(std::size_t size,
104 buffered_fill_handler<ReadHandler>* this_handler)
106 return boost_asio_handler_alloc_helpers::allocate(
107 size, this_handler->handler_);
110 template <typename ReadHandler>
111 inline void asio_handler_deallocate(void* pointer, std::size_t size,
112 buffered_fill_handler<ReadHandler>* this_handler)
114 boost_asio_handler_alloc_helpers::deallocate(
115 pointer, size, this_handler->handler_);
118 template <typename ReadHandler>
119 inline bool asio_handler_is_continuation(
120 buffered_fill_handler<ReadHandler>* this_handler)
122 return boost_asio_handler_cont_helpers::is_continuation(
123 this_handler->handler_);
126 template <typename Function, typename ReadHandler>
127 inline void asio_handler_invoke(Function& function,
128 buffered_fill_handler<ReadHandler>* this_handler)
130 boost_asio_handler_invoke_helpers::invoke(
131 function, this_handler->handler_);
134 template <typename Function, typename ReadHandler>
135 inline void asio_handler_invoke(const Function& function,
136 buffered_fill_handler<ReadHandler>* this_handler)
138 boost_asio_handler_invoke_helpers::invoke(
139 function, this_handler->handler_);
141 } // namespace detail
143 #if !defined(GENERATING_DOCUMENTATION)
145 template <typename ReadHandler, typename Allocator>
146 struct associated_allocator<
147 detail::buffered_fill_handler<ReadHandler>, Allocator>
149 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
151 static type get(const detail::buffered_fill_handler<ReadHandler>& h,
152 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
154 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
158 template <typename ReadHandler, typename Executor>
159 struct associated_executor<
160 detail::buffered_fill_handler<ReadHandler>, Executor>
162 typedef typename associated_executor<ReadHandler, Executor>::type type;
164 static type get(const detail::buffered_fill_handler<ReadHandler>& h,
165 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
167 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
171 #endif // !defined(GENERATING_DOCUMENTATION)
173 template <typename Stream>
174 template <typename ReadHandler>
175 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
176 void (boost::system::error_code, std::size_t))
177 buffered_read_stream<Stream>::async_fill(
178 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
180 // If you get an error on the following line it means that your handler does
181 // not meet the documented type requirements for a ReadHandler.
182 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
184 async_completion<ReadHandler,
185 void (boost::system::error_code, std::size_t)> init(handler);
187 std::size_t previous_size = storage_.size();
188 storage_.resize(storage_.capacity());
189 next_layer_.async_read_some(
191 storage_.data() + previous_size,
192 storage_.size() - previous_size),
193 detail::buffered_fill_handler<BOOST_ASIO_HANDLER_TYPE(
194 ReadHandler, void (boost::system::error_code, std::size_t))>(
195 storage_, previous_size, init.completion_handler));
197 return init.result.get();
200 template <typename Stream>
201 template <typename MutableBufferSequence>
202 std::size_t buffered_read_stream<Stream>::read_some(
203 const MutableBufferSequence& buffers)
205 using boost::asio::buffer_size;
206 if (buffer_size(buffers) == 0)
209 if (storage_.empty())
212 return this->copy(buffers);
215 template <typename Stream>
216 template <typename MutableBufferSequence>
217 std::size_t buffered_read_stream<Stream>::read_some(
218 const MutableBufferSequence& buffers, boost::system::error_code& ec)
220 ec = boost::system::error_code();
222 using boost::asio::buffer_size;
223 if (buffer_size(buffers) == 0)
226 if (storage_.empty() && !this->fill(ec))
229 return this->copy(buffers);
234 template <typename MutableBufferSequence, typename ReadHandler>
235 class buffered_read_some_handler
238 buffered_read_some_handler(detail::buffered_stream_storage& storage,
239 const MutableBufferSequence& buffers, ReadHandler& handler)
242 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
246 #if defined(BOOST_ASIO_HAS_MOVE)
247 buffered_read_some_handler(const buffered_read_some_handler& other)
248 : storage_(other.storage_),
249 buffers_(other.buffers_),
250 handler_(other.handler_)
254 buffered_read_some_handler(buffered_read_some_handler&& other)
255 : storage_(other.storage_),
256 buffers_(other.buffers_),
257 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
260 #endif // defined(BOOST_ASIO_HAS_MOVE)
262 void operator()(const boost::system::error_code& ec, std::size_t)
264 if (ec || storage_.empty())
266 const std::size_t length = 0;
267 handler_(ec, length);
271 const std::size_t bytes_copied = boost::asio::buffer_copy(
272 buffers_, storage_.data(), storage_.size());
273 storage_.consume(bytes_copied);
274 handler_(ec, bytes_copied);
279 detail::buffered_stream_storage& storage_;
280 MutableBufferSequence buffers_;
281 ReadHandler handler_;
284 template <typename MutableBufferSequence, typename ReadHandler>
285 inline void* asio_handler_allocate(std::size_t size,
286 buffered_read_some_handler<
287 MutableBufferSequence, ReadHandler>* this_handler)
289 return boost_asio_handler_alloc_helpers::allocate(
290 size, this_handler->handler_);
293 template <typename MutableBufferSequence, typename ReadHandler>
294 inline void asio_handler_deallocate(void* pointer, std::size_t size,
295 buffered_read_some_handler<
296 MutableBufferSequence, ReadHandler>* this_handler)
298 boost_asio_handler_alloc_helpers::deallocate(
299 pointer, size, this_handler->handler_);
302 template <typename MutableBufferSequence, typename ReadHandler>
303 inline bool asio_handler_is_continuation(
304 buffered_read_some_handler<
305 MutableBufferSequence, ReadHandler>* this_handler)
307 return boost_asio_handler_cont_helpers::is_continuation(
308 this_handler->handler_);
311 template <typename Function, typename MutableBufferSequence,
312 typename ReadHandler>
313 inline void asio_handler_invoke(Function& function,
314 buffered_read_some_handler<
315 MutableBufferSequence, ReadHandler>* this_handler)
317 boost_asio_handler_invoke_helpers::invoke(
318 function, this_handler->handler_);
321 template <typename Function, typename MutableBufferSequence,
322 typename ReadHandler>
323 inline void asio_handler_invoke(const Function& function,
324 buffered_read_some_handler<
325 MutableBufferSequence, ReadHandler>* this_handler)
327 boost_asio_handler_invoke_helpers::invoke(
328 function, this_handler->handler_);
330 } // namespace detail
332 #if !defined(GENERATING_DOCUMENTATION)
334 template <typename MutableBufferSequence,
335 typename ReadHandler, typename Allocator>
336 struct associated_allocator<
337 detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,
340 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
343 const detail::buffered_read_some_handler<
344 MutableBufferSequence, ReadHandler>& h,
345 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
347 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
351 template <typename MutableBufferSequence,
352 typename ReadHandler, typename Executor>
353 struct associated_executor<
354 detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,
357 typedef typename associated_executor<ReadHandler, Executor>::type type;
360 const detail::buffered_read_some_handler<
361 MutableBufferSequence, ReadHandler>& h,
362 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
364 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
368 #endif // !defined(GENERATING_DOCUMENTATION)
370 template <typename Stream>
371 template <typename MutableBufferSequence, typename ReadHandler>
372 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
373 void (boost::system::error_code, std::size_t))
374 buffered_read_stream<Stream>::async_read_some(
375 const MutableBufferSequence& buffers,
376 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
378 // If you get an error on the following line it means that your handler does
379 // not meet the documented type requirements for a ReadHandler.
380 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
382 async_completion<ReadHandler,
383 void (boost::system::error_code, std::size_t)> init(handler);
385 using boost::asio::buffer_size;
386 if (buffer_size(buffers) == 0 || !storage_.empty())
388 next_layer_.async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0),
389 detail::buffered_read_some_handler<
390 MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
391 ReadHandler, void (boost::system::error_code, std::size_t))>(
392 storage_, buffers, init.completion_handler));
396 this->async_fill(detail::buffered_read_some_handler<
397 MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
398 ReadHandler, void (boost::system::error_code, std::size_t))>(
399 storage_, buffers, init.completion_handler));
402 return init.result.get();
405 template <typename Stream>
406 template <typename MutableBufferSequence>
407 std::size_t buffered_read_stream<Stream>::peek(
408 const MutableBufferSequence& buffers)
410 if (storage_.empty())
412 return this->peek_copy(buffers);
415 template <typename Stream>
416 template <typename MutableBufferSequence>
417 std::size_t buffered_read_stream<Stream>::peek(
418 const MutableBufferSequence& buffers, boost::system::error_code& ec)
420 ec = boost::system::error_code();
421 if (storage_.empty() && !this->fill(ec))
423 return this->peek_copy(buffers);
429 #include <boost/asio/detail/pop_options.hpp>
431 #endif // BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP