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