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 | |
25 | namespace boost { |
26 | namespace asio { |
27 | |
28 | template <typename Stream> |
29 | std::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(length: storage_.capacity()); |
35 | storage_.resize(length: previous_size + next_layer_.read_some(buffer( |
36 | b: storage_.data() + previous_size, |
37 | max_size_in_bytes: storage_.size() - previous_size))); |
38 | resize_guard.commit(); |
39 | return storage_.size() - previous_size; |
40 | } |
41 | |
42 | template <typename Stream> |
43 | std::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(length: storage_.capacity()); |
49 | storage_.resize(length: previous_size + next_layer_.read_some(buffer( |
50 | b: storage_.data() + previous_size, |
51 | max_size_in_bytes: storage_.size() - previous_size), |
52 | ec)); |
53 | resize_guard.commit(); |
54 | return storage_.size() - previous_size; |
55 | } |
56 | |
57 | namespace 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(length: 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 | |
141 | template <typename Stream> |
142 | template <typename ReadHandler> |
143 | BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, |
144 | void (boost::system::error_code, std::size_t)) |
145 | buffered_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(length: storage_.capacity()); |
158 | next_layer_.async_read_some( |
159 | buffer( |
160 | b: storage_.data() + previous_size, |
161 | max_size_in_bytes: 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 | |
169 | template <typename Stream> |
170 | template <typename MutableBufferSequence> |
171 | std::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 | |
183 | template <typename Stream> |
184 | template <typename MutableBufferSequence> |
185 | std::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 | |
199 | namespace 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(count: 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 | |
299 | template <typename Stream> |
300 | template <typename MutableBufferSequence, typename ReadHandler> |
301 | BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, |
302 | void (boost::system::error_code, std::size_t)) |
303 | buffered_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 | |
334 | template <typename Stream> |
335 | template <typename MutableBufferSequence> |
336 | std::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 | |
344 | template <typename Stream> |
345 | template <typename MutableBufferSequence> |
346 | std::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 | |