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