1//
2// impl/buffered_read_stream.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2015 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_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
18#include <boost/asio/detail/handler_alloc_helpers.hpp>
19#include <boost/asio/detail/handler_cont_helpers.hpp>
20#include <boost/asio/detail/handler_invoke_helpers.hpp>
21#include <boost/asio/detail/handler_type_requirements.hpp>
22
23#include <boost/asio/detail/push_options.hpp>
24
25namespace boost {
26namespace asio {
27
28template <typename Stream>
29std::size_t buffered_read_stream<Stream>::fill()
30{
31 detail::buffer_resize_guard<detail::buffered_stream_storage>
32 resize_guard(storage_);
33 std::size_t previous_size = storage_.size();
34 storage_.resize(storage_.capacity());
35 storage_.resize(previous_size + next_layer_.read_some(buffer(
36 storage_.data() + previous_size,
37 storage_.size() - previous_size)));
38 resize_guard.commit();
39 return storage_.size() - previous_size;
40}
41
42template <typename Stream>
43std::size_t buffered_read_stream<Stream>::fill(boost::system::error_code& ec)
44{
45 detail::buffer_resize_guard<detail::buffered_stream_storage>
46 resize_guard(storage_);
47 std::size_t previous_size = storage_.size();
48 storage_.resize(storage_.capacity());
49 storage_.resize(previous_size + next_layer_.read_some(buffer(
50 storage_.data() + previous_size,
51 storage_.size() - previous_size),
52 ec));
53 resize_guard.commit();
54 return storage_.size() - previous_size;
55}
56
57namespace detail
58{
59 template <typename ReadHandler>
60 class buffered_fill_handler
61 {
62 public:
63 buffered_fill_handler(detail::buffered_stream_storage& storage,
64 std::size_t previous_size, ReadHandler& handler)
65 : storage_(storage),
66 previous_size_(previous_size),
67 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
68 {
69 }
70
71#if defined(BOOST_ASIO_HAS_MOVE)
72 buffered_fill_handler(const buffered_fill_handler& other)
73 : storage_(other.storage_),
74 previous_size_(other.previous_size_),
75 handler_(other.handler_)
76 {
77 }
78
79 buffered_fill_handler(buffered_fill_handler&& other)
80 : storage_(other.storage_),
81 previous_size_(other.previous_size_),
82 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
83 {
84 }
85#endif // defined(BOOST_ASIO_HAS_MOVE)
86
87 void operator()(const boost::system::error_code& ec,
88 const std::size_t bytes_transferred)
89 {
90 storage_.resize(previous_size_ + bytes_transferred);
91 handler_(ec, bytes_transferred);
92 }
93
94 //private:
95 detail::buffered_stream_storage& storage_;
96 std::size_t previous_size_;
97 ReadHandler handler_;
98 };
99
100 template <typename ReadHandler>
101 inline void* asio_handler_allocate(std::size_t size,
102 buffered_fill_handler<ReadHandler>* this_handler)
103 {
104 return boost_asio_handler_alloc_helpers::allocate(
105 size, this_handler->handler_);
106 }
107
108 template <typename ReadHandler>
109 inline void asio_handler_deallocate(void* pointer, std::size_t size,
110 buffered_fill_handler<ReadHandler>* this_handler)
111 {
112 boost_asio_handler_alloc_helpers::deallocate(
113 pointer, size, this_handler->handler_);
114 }
115
116 template <typename ReadHandler>
117 inline bool asio_handler_is_continuation(
118 buffered_fill_handler<ReadHandler>* this_handler)
119 {
120 return boost_asio_handler_cont_helpers::is_continuation(
121 this_handler->handler_);
122 }
123
124 template <typename Function, typename ReadHandler>
125 inline void asio_handler_invoke(Function& function,
126 buffered_fill_handler<ReadHandler>* this_handler)
127 {
128 boost_asio_handler_invoke_helpers::invoke(
129 function, this_handler->handler_);
130 }
131
132 template <typename Function, typename ReadHandler>
133 inline void asio_handler_invoke(const Function& function,
134 buffered_fill_handler<ReadHandler>* this_handler)
135 {
136 boost_asio_handler_invoke_helpers::invoke(
137 function, this_handler->handler_);
138 }
139} // namespace detail
140
141template <typename Stream>
142template <typename ReadHandler>
143BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
144 void (boost::system::error_code, std::size_t))
145buffered_read_stream<Stream>::async_fill(
146 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
147{
148 // If you get an error on the following line it means that your handler does
149 // not meet the documented type requirements for a ReadHandler.
150 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
151
152 detail::async_result_init<
153 ReadHandler, void (boost::system::error_code, std::size_t)> init(
154 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
155
156 std::size_t previous_size = storage_.size();
157 storage_.resize(storage_.capacity());
158 next_layer_.async_read_some(
159 buffer(
160 storage_.data() + previous_size,
161 storage_.size() - previous_size),
162 detail::buffered_fill_handler<BOOST_ASIO_HANDLER_TYPE(
163 ReadHandler, void (boost::system::error_code, std::size_t))>(
164 storage_, previous_size, init.handler));
165
166 return init.result.get();
167}
168
169template <typename Stream>
170template <typename MutableBufferSequence>
171std::size_t buffered_read_stream<Stream>::read_some(
172 const MutableBufferSequence& buffers)
173{
174 if (boost::asio::buffer_size(buffers) == 0)
175 return 0;
176
177 if (storage_.empty())
178 this->fill();
179
180 return this->copy(buffers);
181}
182
183template <typename Stream>
184template <typename MutableBufferSequence>
185std::size_t buffered_read_stream<Stream>::read_some(
186 const MutableBufferSequence& buffers, boost::system::error_code& ec)
187{
188 ec = boost::system::error_code();
189
190 if (boost::asio::buffer_size(buffers) == 0)
191 return 0;
192
193 if (storage_.empty() && !this->fill(ec))
194 return 0;
195
196 return this->copy(buffers);
197}
198
199namespace detail
200{
201 template <typename MutableBufferSequence, typename ReadHandler>
202 class buffered_read_some_handler
203 {
204 public:
205 buffered_read_some_handler(detail::buffered_stream_storage& storage,
206 const MutableBufferSequence& buffers, ReadHandler& handler)
207 : storage_(storage),
208 buffers_(buffers),
209 handler_(handler)
210 {
211 }
212
213#if defined(BOOST_ASIO_HAS_MOVE)
214 buffered_read_some_handler(const buffered_read_some_handler& other)
215 : storage_(other.storage_),
216 buffers_(other.buffers_),
217 handler_(other.handler_)
218 {
219 }
220
221 buffered_read_some_handler(buffered_read_some_handler&& other)
222 : storage_(other.storage_),
223 buffers_(other.buffers_),
224 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
225 {
226 }
227#endif // defined(BOOST_ASIO_HAS_MOVE)
228
229 void operator()(const boost::system::error_code& ec, std::size_t)
230 {
231 if (ec || storage_.empty())
232 {
233 const std::size_t length = 0;
234 handler_(ec, length);
235 }
236 else
237 {
238 const std::size_t bytes_copied = boost::asio::buffer_copy(
239 buffers_, storage_.data(), storage_.size());
240 storage_.consume(bytes_copied);
241 handler_(ec, bytes_copied);
242 }
243 }
244
245 //private:
246 detail::buffered_stream_storage& storage_;
247 MutableBufferSequence buffers_;
248 ReadHandler handler_;
249 };
250
251 template <typename MutableBufferSequence, typename ReadHandler>
252 inline void* asio_handler_allocate(std::size_t size,
253 buffered_read_some_handler<
254 MutableBufferSequence, ReadHandler>* this_handler)
255 {
256 return boost_asio_handler_alloc_helpers::allocate(
257 size, this_handler->handler_);
258 }
259
260 template <typename MutableBufferSequence, typename ReadHandler>
261 inline void asio_handler_deallocate(void* pointer, std::size_t size,
262 buffered_read_some_handler<
263 MutableBufferSequence, ReadHandler>* this_handler)
264 {
265 boost_asio_handler_alloc_helpers::deallocate(
266 pointer, size, this_handler->handler_);
267 }
268
269 template <typename MutableBufferSequence, typename ReadHandler>
270 inline bool asio_handler_is_continuation(
271 buffered_read_some_handler<
272 MutableBufferSequence, ReadHandler>* this_handler)
273 {
274 return boost_asio_handler_cont_helpers::is_continuation(
275 this_handler->handler_);
276 }
277
278 template <typename Function, typename MutableBufferSequence,
279 typename ReadHandler>
280 inline void asio_handler_invoke(Function& function,
281 buffered_read_some_handler<
282 MutableBufferSequence, ReadHandler>* this_handler)
283 {
284 boost_asio_handler_invoke_helpers::invoke(
285 function, this_handler->handler_);
286 }
287
288 template <typename Function, typename MutableBufferSequence,
289 typename ReadHandler>
290 inline void asio_handler_invoke(const Function& function,
291 buffered_read_some_handler<
292 MutableBufferSequence, ReadHandler>* this_handler)
293 {
294 boost_asio_handler_invoke_helpers::invoke(
295 function, this_handler->handler_);
296 }
297} // namespace detail
298
299template <typename Stream>
300template <typename MutableBufferSequence, typename ReadHandler>
301BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
302 void (boost::system::error_code, std::size_t))
303buffered_read_stream<Stream>::async_read_some(
304 const MutableBufferSequence& buffers,
305 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
306{
307 // If you get an error on the following line it means that your handler does
308 // not meet the documented type requirements for a ReadHandler.
309 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
310
311 detail::async_result_init<
312 ReadHandler, void (boost::system::error_code, std::size_t)> init(
313 BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
314
315 if (boost::asio::buffer_size(buffers) == 0 || !storage_.empty())
316 {
317 next_layer_.async_read_some(boost::asio::mutable_buffers_1(0, 0),
318 detail::buffered_read_some_handler<
319 MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
320 ReadHandler, void (boost::system::error_code, std::size_t))>(
321 storage_, buffers, init.handler));
322 }
323 else
324 {
325 this->async_fill(detail::buffered_read_some_handler<
326 MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
327 ReadHandler, void (boost::system::error_code, std::size_t))>(
328 storage_, buffers, init.handler));
329 }
330
331 return init.result.get();
332}
333
334template <typename Stream>
335template <typename MutableBufferSequence>
336std::size_t buffered_read_stream<Stream>::peek(
337 const MutableBufferSequence& buffers)
338{
339 if (storage_.empty())
340 this->fill();
341 return this->peek_copy(buffers);
342}
343
344template <typename Stream>
345template <typename MutableBufferSequence>
346std::size_t buffered_read_stream<Stream>::peek(
347 const MutableBufferSequence& buffers, boost::system::error_code& ec)
348{
349 ec = boost::system::error_code();
350 if (storage_.empty() && !this->fill(ec))
351 return 0;
352 return this->peek_copy(buffers);
353}
354
355} // namespace asio
356} // namespace boost
357
358#include <boost/asio/detail/pop_options.hpp>
359
360#endif // BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP
361