Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / asio / impl / buffered_write_stream.hpp
1 //
2 // impl/buffered_write_stream.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 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_WRITE_STREAM_HPP
12 #define BOOST_ASIO_IMPL_BUFFERED_WRITE_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/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>
24 #include <boost/asio/detail/non_const_lvalue.hpp>
25
26 #include <boost/asio/detail/push_options.hpp>
27
28 namespace boost {
29 namespace asio {
30
31 template <typename Stream>
32 std::size_t buffered_write_stream<Stream>::flush()
33 {
34   std::size_t bytes_written = write(next_layer_,
35       buffer(storage_.data(), storage_.size()));
36   storage_.consume(bytes_written);
37   return bytes_written;
38 }
39
40 template <typename Stream>
41 std::size_t buffered_write_stream<Stream>::flush(boost::system::error_code& ec)
42 {
43   std::size_t bytes_written = write(next_layer_,
44       buffer(storage_.data(), storage_.size()),
45       transfer_all(), ec);
46   storage_.consume(bytes_written);
47   return bytes_written;
48 }
49
50 namespace detail
51 {
52   template <typename WriteHandler>
53   class buffered_flush_handler
54   {
55   public:
56     buffered_flush_handler(detail::buffered_stream_storage& storage,
57         WriteHandler& handler)
58       : storage_(storage),
59         handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
60     {
61     }
62
63 #if defined(BOOST_ASIO_HAS_MOVE)
64     buffered_flush_handler(const buffered_flush_handler& other)
65       : storage_(other.storage_),
66         handler_(other.handler_)
67     {
68     }
69
70     buffered_flush_handler(buffered_flush_handler&& other)
71       : storage_(other.storage_),
72         handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
73     {
74     }
75 #endif // defined(BOOST_ASIO_HAS_MOVE)
76
77     void operator()(const boost::system::error_code& ec,
78         const std::size_t bytes_written)
79     {
80       storage_.consume(bytes_written);
81       handler_(ec, bytes_written);
82     }
83
84   //private:
85     detail::buffered_stream_storage& storage_;
86     WriteHandler handler_;
87   };
88
89   template <typename WriteHandler>
90   inline void* asio_handler_allocate(std::size_t size,
91       buffered_flush_handler<WriteHandler>* this_handler)
92   {
93     return boost_asio_handler_alloc_helpers::allocate(
94         size, this_handler->handler_);
95   }
96
97   template <typename WriteHandler>
98   inline void asio_handler_deallocate(void* pointer, std::size_t size,
99       buffered_flush_handler<WriteHandler>* this_handler)
100   {
101     boost_asio_handler_alloc_helpers::deallocate(
102         pointer, size, this_handler->handler_);
103   }
104
105   template <typename WriteHandler>
106   inline bool asio_handler_is_continuation(
107       buffered_flush_handler<WriteHandler>* this_handler)
108   {
109     return boost_asio_handler_cont_helpers::is_continuation(
110           this_handler->handler_);
111   }
112
113   template <typename Function, typename WriteHandler>
114   inline void asio_handler_invoke(Function& function,
115       buffered_flush_handler<WriteHandler>* this_handler)
116   {
117     boost_asio_handler_invoke_helpers::invoke(
118         function, this_handler->handler_);
119   }
120
121   template <typename Function, typename WriteHandler>
122   inline void asio_handler_invoke(const Function& function,
123       buffered_flush_handler<WriteHandler>* this_handler)
124   {
125     boost_asio_handler_invoke_helpers::invoke(
126         function, this_handler->handler_);
127   }
128
129   template <typename Stream>
130   class initiate_async_buffered_flush
131   {
132   public:
133     typedef typename remove_reference<
134       Stream>::type::lowest_layer_type::executor_type executor_type;
135
136     explicit initiate_async_buffered_flush(Stream& next_layer)
137       : next_layer_(next_layer)
138     {
139     }
140
141     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
142     {
143       return next_layer_.lowest_layer().get_executor();
144     }
145
146     template <typename WriteHandler>
147     void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
148         buffered_stream_storage* storage) const
149     {
150       // If you get an error on the following line it means that your handler
151       // does not meet the documented type requirements for a WriteHandler.
152       BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
153
154       non_const_lvalue<WriteHandler> handler2(handler);
155       async_write(next_layer_, buffer(storage->data(), storage->size()),
156           buffered_flush_handler<typename decay<WriteHandler>::type>(
157             *storage, handler2.value));
158     }
159
160   private:
161     Stream& next_layer_;
162   };
163 } // namespace detail
164
165 #if !defined(GENERATING_DOCUMENTATION)
166
167 template <typename WriteHandler, typename Allocator>
168 struct associated_allocator<
169     detail::buffered_flush_handler<WriteHandler>, Allocator>
170 {
171   typedef typename associated_allocator<WriteHandler, Allocator>::type type;
172
173   static type get(const detail::buffered_flush_handler<WriteHandler>& h,
174       const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
175   {
176     return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
177   }
178 };
179
180 template <typename WriteHandler, typename Executor>
181 struct associated_executor<
182     detail::buffered_flush_handler<WriteHandler>, Executor>
183 {
184   typedef typename associated_executor<WriteHandler, Executor>::type type;
185
186   static type get(const detail::buffered_flush_handler<WriteHandler>& h,
187       const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
188   {
189     return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
190   }
191 };
192
193 #endif // !defined(GENERATING_DOCUMENTATION)
194
195 template <typename Stream>
196 template <
197     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
198       std::size_t)) WriteHandler>
199 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
200     void (boost::system::error_code, std::size_t))
201 buffered_write_stream<Stream>::async_flush(
202     BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
203 {
204   return async_initiate<WriteHandler,
205     void (boost::system::error_code, std::size_t)>(
206       detail::initiate_async_buffered_flush<Stream>(next_layer_),
207       handler, &storage_);
208 }
209
210 template <typename Stream>
211 template <typename ConstBufferSequence>
212 std::size_t buffered_write_stream<Stream>::write_some(
213     const ConstBufferSequence& buffers)
214 {
215   using boost::asio::buffer_size;
216   if (buffer_size(buffers) == 0)
217     return 0;
218
219   if (storage_.size() == storage_.capacity())
220     this->flush();
221
222   return this->copy(buffers);
223 }
224
225 template <typename Stream>
226 template <typename ConstBufferSequence>
227 std::size_t buffered_write_stream<Stream>::write_some(
228     const ConstBufferSequence& buffers, boost::system::error_code& ec)
229 {
230   ec = boost::system::error_code();
231
232   using boost::asio::buffer_size;
233   if (buffer_size(buffers) == 0)
234     return 0;
235
236   if (storage_.size() == storage_.capacity() && !flush(ec))
237     return 0;
238
239   return this->copy(buffers);
240 }
241
242 namespace detail
243 {
244   template <typename ConstBufferSequence, typename WriteHandler>
245   class buffered_write_some_handler
246   {
247   public:
248     buffered_write_some_handler(detail::buffered_stream_storage& storage,
249         const ConstBufferSequence& buffers, WriteHandler& handler)
250       : storage_(storage),
251         buffers_(buffers),
252         handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
253     {
254     }
255
256 #if defined(BOOST_ASIO_HAS_MOVE)
257       buffered_write_some_handler(const buffered_write_some_handler& other)
258         : storage_(other.storage_),
259           buffers_(other.buffers_),
260           handler_(other.handler_)
261       {
262       }
263
264       buffered_write_some_handler(buffered_write_some_handler&& other)
265         : storage_(other.storage_),
266           buffers_(other.buffers_),
267           handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
268       {
269       }
270 #endif // defined(BOOST_ASIO_HAS_MOVE)
271
272     void operator()(const boost::system::error_code& ec, std::size_t)
273     {
274       if (ec)
275       {
276         const std::size_t length = 0;
277         handler_(ec, length);
278       }
279       else
280       {
281         using boost::asio::buffer_size;
282         std::size_t orig_size = storage_.size();
283         std::size_t space_avail = storage_.capacity() - orig_size;
284         std::size_t bytes_avail = buffer_size(buffers_);
285         std::size_t length = bytes_avail < space_avail
286           ? bytes_avail : space_avail;
287         storage_.resize(orig_size + length);
288         const std::size_t bytes_copied = boost::asio::buffer_copy(
289             storage_.data() + orig_size, buffers_, length);
290         handler_(ec, bytes_copied);
291       }
292     }
293
294   //private:
295     detail::buffered_stream_storage& storage_;
296     ConstBufferSequence buffers_;
297     WriteHandler handler_;
298   };
299
300   template <typename ConstBufferSequence, typename WriteHandler>
301   inline void* asio_handler_allocate(std::size_t size,
302       buffered_write_some_handler<
303         ConstBufferSequence, WriteHandler>* this_handler)
304   {
305     return boost_asio_handler_alloc_helpers::allocate(
306         size, this_handler->handler_);
307   }
308
309   template <typename ConstBufferSequence, typename WriteHandler>
310   inline void asio_handler_deallocate(void* pointer, std::size_t size,
311       buffered_write_some_handler<
312         ConstBufferSequence, WriteHandler>* this_handler)
313   {
314     boost_asio_handler_alloc_helpers::deallocate(
315         pointer, size, this_handler->handler_);
316   }
317
318   template <typename ConstBufferSequence, typename WriteHandler>
319   inline bool asio_handler_is_continuation(
320       buffered_write_some_handler<
321         ConstBufferSequence, WriteHandler>* this_handler)
322   {
323     return boost_asio_handler_cont_helpers::is_continuation(
324           this_handler->handler_);
325   }
326
327   template <typename Function, typename ConstBufferSequence,
328       typename WriteHandler>
329   inline void asio_handler_invoke(Function& function,
330       buffered_write_some_handler<
331         ConstBufferSequence, WriteHandler>* this_handler)
332   {
333     boost_asio_handler_invoke_helpers::invoke(
334         function, this_handler->handler_);
335   }
336
337   template <typename Function, typename ConstBufferSequence,
338       typename WriteHandler>
339   inline void asio_handler_invoke(const Function& function,
340       buffered_write_some_handler<
341         ConstBufferSequence, WriteHandler>* this_handler)
342   {
343     boost_asio_handler_invoke_helpers::invoke(
344         function, this_handler->handler_);
345   }
346
347   template <typename Stream>
348   class initiate_async_buffered_write_some
349   {
350   public:
351     typedef typename remove_reference<
352       Stream>::type::lowest_layer_type::executor_type executor_type;
353
354     explicit initiate_async_buffered_write_some(Stream& next_layer)
355       : next_layer_(next_layer)
356     {
357     }
358
359     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
360     {
361       return next_layer_.lowest_layer().get_executor();
362     }
363
364     template <typename WriteHandler, typename ConstBufferSequence>
365     void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
366         buffered_stream_storage* storage,
367         const ConstBufferSequence& buffers) const
368     {
369       // If you get an error on the following line it means that your handler
370       // does not meet the documented type requirements for a WriteHandler.
371       BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
372
373       using boost::asio::buffer_size;
374       non_const_lvalue<WriteHandler> handler2(handler);
375       if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
376       {
377         next_layer_.async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0),
378             buffered_write_some_handler<ConstBufferSequence,
379               typename decay<WriteHandler>::type>(
380                 *storage, buffers, handler2.value));
381       }
382       else
383       {
384         initiate_async_buffered_flush<Stream>(this->next_layer_)(
385             buffered_write_some_handler<ConstBufferSequence,
386               typename decay<WriteHandler>::type>(
387                 *storage, buffers, handler2.value),
388             storage);
389       }
390     }
391
392   private:
393     Stream& next_layer_;
394   };
395 } // namespace detail
396
397 #if !defined(GENERATING_DOCUMENTATION)
398
399 template <typename ConstBufferSequence,
400     typename WriteHandler, typename Allocator>
401 struct associated_allocator<
402     detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
403     Allocator>
404 {
405   typedef typename associated_allocator<WriteHandler, Allocator>::type type;
406
407   static type get(
408       const detail::buffered_write_some_handler<
409         ConstBufferSequence, WriteHandler>& h,
410       const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
411   {
412     return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
413   }
414 };
415
416 template <typename ConstBufferSequence,
417     typename WriteHandler, typename Executor>
418 struct associated_executor<
419     detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
420     Executor>
421 {
422   typedef typename associated_executor<WriteHandler, Executor>::type type;
423
424   static type get(
425       const detail::buffered_write_some_handler<
426         ConstBufferSequence, WriteHandler>& h,
427       const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
428   {
429     return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
430   }
431 };
432
433 #endif // !defined(GENERATING_DOCUMENTATION)
434
435 template <typename Stream>
436 template <typename ConstBufferSequence,
437     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
438       std::size_t)) WriteHandler>
439 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
440     void (boost::system::error_code, std::size_t))
441 buffered_write_stream<Stream>::async_write_some(
442     const ConstBufferSequence& buffers,
443     BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
444 {
445   return async_initiate<WriteHandler,
446     void (boost::system::error_code, std::size_t)>(
447       detail::initiate_async_buffered_write_some<Stream>(next_layer_),
448       handler, &storage_, buffers);
449 }
450
451 template <typename Stream>
452 template <typename ConstBufferSequence>
453 std::size_t buffered_write_stream<Stream>::copy(
454     const ConstBufferSequence& buffers)
455 {
456   using boost::asio::buffer_size;
457   std::size_t orig_size = storage_.size();
458   std::size_t space_avail = storage_.capacity() - orig_size;
459   std::size_t bytes_avail = buffer_size(buffers);
460   std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
461   storage_.resize(orig_size + length);
462   return boost::asio::buffer_copy(
463       storage_.data() + orig_size, buffers, length);
464 }
465
466 } // namespace asio
467 } // namespace boost
468
469 #include <boost/asio/detail/pop_options.hpp>
470
471 #endif // BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP