1//
2// impl/write.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 ASIO_IMPL_WRITE_HPP
12#define ASIO_IMPL_WRITE_HPP
13
14
15#include "asio/buffer.hpp"
16#include "asio/completion_condition.hpp"
17#include "asio/detail/array_fwd.hpp"
18#include "asio/detail/base_from_completion_cond.hpp"
19#include "asio/detail/bind_handler.hpp"
20#include "asio/detail/consuming_buffers.hpp"
21#include "asio/detail/dependent_type.hpp"
22#include "asio/detail/handler_alloc_helpers.hpp"
23#include "asio/detail/handler_cont_helpers.hpp"
24#include "asio/detail/handler_invoke_helpers.hpp"
25#include "asio/detail/handler_type_requirements.hpp"
26#include "asio/detail/throw_error.hpp"
27
28#include "asio/detail/push_options.hpp"
29
30namespace asio {
31
32template <typename SyncWriteStream, typename ConstBufferSequence,
33    typename CompletionCondition>
34std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
35    CompletionCondition completion_condition, asio::error_code& ec)
36{
37  ec = asio::error_code();
38  asio::detail::consuming_buffers<
39    const_buffer, ConstBufferSequence> tmp(buffers);
40  std::size_t total_transferred = 0;
41  tmp.prepare(detail::adapt_completion_condition_result(
42        completion_condition(ec, total_transferred)));
43  while (tmp.begin() != tmp.end())
44  {
45    std::size_t bytes_transferred = s.write_some(tmp, ec);
46    tmp.consume(bytes_transferred);
47    total_transferred += bytes_transferred;
48    tmp.prepare(detail::adapt_completion_condition_result(
49          completion_condition(ec, total_transferred)));
50  }
51  return total_transferred;
52}
53
54template <typename SyncWriteStream, typename ConstBufferSequence>
55inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers)
56{
57  asio::error_code ec;
58  std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);
59  asio::detail::throw_error(ec, "write");
60  return bytes_transferred;
61}
62
63template <typename SyncWriteStream, typename ConstBufferSequence>
64inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
65    asio::error_code& ec)
66{
67  return write(s, buffers, transfer_all(), ec);
68}
69
70template <typename SyncWriteStream, typename ConstBufferSequence,
71    typename CompletionCondition>
72inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
73    CompletionCondition completion_condition)
74{
75  asio::error_code ec;
76  std::size_t bytes_transferred = write(s, buffers, completion_condition, ec);
77  asio::detail::throw_error(ec, "write");
78  return bytes_transferred;
79}
80
81
82namespace detail
83{
84  template <typename AsyncWriteStream, typename ConstBufferSequence,
85      typename CompletionCondition, typename WriteHandler>
86  class write_op
87    : detail::base_from_completion_cond<CompletionCondition>
88  {
89  public:
90    write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers,
91        CompletionCondition completion_condition, WriteHandler& handler)
92      : detail::base_from_completion_cond<
93          CompletionCondition>(completion_condition),
94        stream_(stream),
95        buffers_(buffers),
96        start_(0),
97        total_transferred_(0),
98        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
99    {
100    }
101
102    write_op(const write_op& other)
103      : detail::base_from_completion_cond<CompletionCondition>(other),
104        stream_(other.stream_),
105        buffers_(other.buffers_),
106        start_(other.start_),
107        total_transferred_(other.total_transferred_),
108        handler_(other.handler_)
109    {
110    }
111
112    write_op(write_op&& other)
113      : detail::base_from_completion_cond<CompletionCondition>(other),
114        stream_(other.stream_),
115        buffers_(other.buffers_),
116        start_(other.start_),
117        total_transferred_(other.total_transferred_),
118        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
119    {
120    }
121
122    void operator()(const asio::error_code& ec,
123        std::size_t bytes_transferred, int start = 0)
124    {
125      switch (start_ = start)
126      {
127        case 1:
128        buffers_.prepare(this->check_for_completion(ec, total_transferred_));
129        for (;;)
130        {
131          stream_.async_write_some(buffers_,
132              ASIO_MOVE_CAST(write_op)(*this));
133          return; default:
134          total_transferred_ += bytes_transferred;
135          buffers_.consume(bytes_transferred);
136          buffers_.prepare(this->check_for_completion(ec, total_transferred_));
137          if ((!ec && bytes_transferred == 0)
138              || buffers_.begin() == buffers_.end())
139            break;
140        }
141
142        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
143      }
144    }
145
146  //private:
147    AsyncWriteStream& stream_;
148    asio::detail::consuming_buffers<
149      const_buffer, ConstBufferSequence> buffers_;
150    int start_;
151    std::size_t total_transferred_;
152    WriteHandler handler_;
153  };
154
155  template <typename AsyncWriteStream,
156      typename CompletionCondition, typename WriteHandler>
157  class write_op<AsyncWriteStream, asio::mutable_buffers_1,
158      CompletionCondition, WriteHandler>
159    : detail::base_from_completion_cond<CompletionCondition>
160  {
161  public:
162    write_op(AsyncWriteStream& stream,
163        const asio::mutable_buffers_1& buffers,
164        CompletionCondition completion_condition,
165        WriteHandler& handler)
166      : detail::base_from_completion_cond<
167          CompletionCondition>(completion_condition),
168        stream_(stream),
169        buffer_(buffers),
170        start_(0),
171        total_transferred_(0),
172        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
173    {
174    }
175
176    write_op(const write_op& other)
177      : detail::base_from_completion_cond<CompletionCondition>(other),
178        stream_(other.stream_),
179        buffer_(other.buffer_),
180        start_(other.start_),
181        total_transferred_(other.total_transferred_),
182        handler_(other.handler_)
183    {
184    }
185
186    write_op(write_op&& other)
187      : detail::base_from_completion_cond<CompletionCondition>(other),
188        stream_(other.stream_),
189        buffer_(other.buffer_),
190        start_(other.start_),
191        total_transferred_(other.total_transferred_),
192        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
193    {
194    }
195
196    void operator()(const asio::error_code& ec,
197        std::size_t bytes_transferred, int start = 0)
198    {
199      std::size_t n = 0;
200      switch (start_ = start)
201      {
202        case 1:
203        n = this->check_for_completion(ec, total_transferred_);
204        for (;;)
205        {
206          stream_.async_write_some(
207              asio::buffer(buffer_ + total_transferred_, n),
208              ASIO_MOVE_CAST(write_op)(*this));
209          return; default:
210          total_transferred_ += bytes_transferred;
211          if ((!ec && bytes_transferred == 0)
212              || (n = this->check_for_completion(ec, total_transferred_)) == 0
213              || total_transferred_ == asio::buffer_size(buffer_))
214            break;
215        }
216
217        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
218      }
219    }
220
221  //private:
222    AsyncWriteStream& stream_;
223    asio::mutable_buffer buffer_;
224    int start_;
225    std::size_t total_transferred_;
226    WriteHandler handler_;
227  };
228
229  template <typename AsyncWriteStream,
230      typename CompletionCondition, typename WriteHandler>
231  class write_op<AsyncWriteStream, asio::const_buffers_1,
232      CompletionCondition, WriteHandler>
233    : detail::base_from_completion_cond<CompletionCondition>
234  {
235  public:
236    write_op(AsyncWriteStream& stream,
237        const asio::const_buffers_1& buffers,
238        CompletionCondition completion_condition,
239        WriteHandler& handler)
240      : detail::base_from_completion_cond<
241          CompletionCondition>(completion_condition),
242        stream_(stream),
243        buffer_(buffers),
244        start_(0),
245        total_transferred_(0),
246        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
247    {
248    }
249
250    write_op(const write_op& other)
251      : detail::base_from_completion_cond<CompletionCondition>(other),
252        stream_(other.stream_),
253        buffer_(other.buffer_),
254        start_(other.start_),
255        total_transferred_(other.total_transferred_),
256        handler_(other.handler_)
257    {
258    }
259
260    write_op(write_op&& other)
261      : detail::base_from_completion_cond<CompletionCondition>(other),
262        stream_(other.stream_),
263        buffer_(other.buffer_),
264        start_(other.start_),
265        total_transferred_(other.total_transferred_),
266        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
267    {
268    }
269
270    void operator()(const asio::error_code& ec,
271        std::size_t bytes_transferred, int start = 0)
272    {
273      std::size_t n = 0;
274      switch (start_ = start)
275      {
276        case 1:
277        n = this->check_for_completion(ec, total_transferred_);
278        for (;;)
279        {
280          stream_.async_write_some(
281              asio::buffer(buffer_ + total_transferred_, n),
282              ASIO_MOVE_CAST(write_op)(*this));
283          return; default:
284          total_transferred_ += bytes_transferred;
285          if ((!ec && bytes_transferred == 0)
286              || (n = this->check_for_completion(ec, total_transferred_)) == 0
287              || total_transferred_ == asio::buffer_size(buffer_))
288            break;
289        }
290
291        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
292      }
293    }
294
295  //private:
296    AsyncWriteStream& stream_;
297    asio::const_buffer buffer_;
298    int start_;
299    std::size_t total_transferred_;
300    WriteHandler handler_;
301  };
302
303  template <typename AsyncWriteStream, typename Elem,
304      typename CompletionCondition, typename WriteHandler>
305  class write_op<AsyncWriteStream, boost::array<Elem, 2>,
306      CompletionCondition, WriteHandler>
307    : detail::base_from_completion_cond<CompletionCondition>
308  {
309  public:
310    write_op(AsyncWriteStream& stream, const boost::array<Elem, 2>& buffers,
311        CompletionCondition completion_condition, WriteHandler& handler)
312      : detail::base_from_completion_cond<
313          CompletionCondition>(completion_condition),
314        stream_(stream),
315        buffers_(buffers),
316        start_(0),
317        total_transferred_(0),
318        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
319    {
320    }
321
322    write_op(const write_op& other)
323      : detail::base_from_completion_cond<CompletionCondition>(other),
324        stream_(other.stream_),
325        buffers_(other.buffers_),
326        start_(other.start_),
327        total_transferred_(other.total_transferred_),
328        handler_(other.handler_)
329    {
330    }
331
332    write_op(write_op&& other)
333      : detail::base_from_completion_cond<CompletionCondition>(other),
334        stream_(other.stream_),
335        buffers_(other.buffers_),
336        start_(other.start_),
337        total_transferred_(other.total_transferred_),
338        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
339    {
340    }
341
342    void operator()(const asio::error_code& ec,
343        std::size_t bytes_transferred, int start = 0)
344    {
345      typename asio::detail::dependent_type<Elem,
346          boost::array<asio::const_buffer, 2> >::type bufs = {{
347        asio::const_buffer(buffers_[0]),
348        asio::const_buffer(buffers_[1]) }};
349      std::size_t buffer_size0 = asio::buffer_size(bufs[0]);
350      std::size_t buffer_size1 = asio::buffer_size(bufs[1]);
351      std::size_t n = 0;
352      switch (start_ = start)
353      {
354        case 1:
355        n = this->check_for_completion(ec, total_transferred_);
356        for (;;)
357        {
358          bufs[0] = asio::buffer(bufs[0] + total_transferred_, n);
359          bufs[1] = asio::buffer(
360              bufs[1] + (total_transferred_ < buffer_size0
361                ? 0 : total_transferred_ - buffer_size0),
362              n - asio::buffer_size(bufs[0]));
363          stream_.async_write_some(bufs, ASIO_MOVE_CAST(write_op)(*this));
364          return; default:
365          total_transferred_ += bytes_transferred;
366          if ((!ec && bytes_transferred == 0)
367              || (n = this->check_for_completion(ec, total_transferred_)) == 0
368              || total_transferred_ == buffer_size0 + buffer_size1)
369            break;
370        }
371
372        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
373      }
374    }
375
376  //private:
377    AsyncWriteStream& stream_;
378    boost::array<Elem, 2> buffers_;
379    int start_;
380    std::size_t total_transferred_;
381    WriteHandler handler_;
382  };
383
384
385  template <typename AsyncWriteStream, typename Elem,
386      typename CompletionCondition, typename WriteHandler>
387  class write_op<AsyncWriteStream, std::array<Elem, 2>,
388      CompletionCondition, WriteHandler>
389    : detail::base_from_completion_cond<CompletionCondition>
390  {
391  public:
392    write_op(AsyncWriteStream& stream, const std::array<Elem, 2>& buffers,
393        CompletionCondition completion_condition, WriteHandler& handler)
394      : detail::base_from_completion_cond<
395          CompletionCondition>(completion_condition),
396        stream_(stream),
397        buffers_(buffers),
398        start_(0),
399        total_transferred_(0),
400        handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
401    {
402    }
403
404    write_op(const write_op& other)
405      : detail::base_from_completion_cond<CompletionCondition>(other),
406        stream_(other.stream_),
407        buffers_(other.buffers_),
408        start_(other.start_),
409        total_transferred_(other.total_transferred_),
410        handler_(other.handler_)
411    {
412    }
413
414    write_op(write_op&& other)
415      : detail::base_from_completion_cond<CompletionCondition>(other),
416        stream_(other.stream_),
417        buffers_(other.buffers_),
418        start_(other.start_),
419        total_transferred_(other.total_transferred_),
420        handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
421    {
422    }
423
424    void operator()(const asio::error_code& ec,
425        std::size_t bytes_transferred, int start = 0)
426    {
427      typename asio::detail::dependent_type<Elem,
428          std::array<asio::const_buffer, 2> >::type bufs = {{
429        asio::const_buffer(buffers_[0]),
430        asio::const_buffer(buffers_[1]) }};
431      std::size_t buffer_size0 = asio::buffer_size(bufs[0]);
432      std::size_t buffer_size1 = asio::buffer_size(bufs[1]);
433      std::size_t n = 0;
434      switch (start_ = start)
435      {
436        case 1:
437        n = this->check_for_completion(ec, total_transferred_);
438        for (;;)
439        {
440          bufs[0] = asio::buffer(bufs[0] + total_transferred_, n);
441          bufs[1] = asio::buffer(
442              bufs[1] + (total_transferred_ < buffer_size0
443                ? 0 : total_transferred_ - buffer_size0),
444              n - asio::buffer_size(bufs[0]));
445          stream_.async_write_some(bufs, ASIO_MOVE_CAST(write_op)(*this));
446          return; default:
447          total_transferred_ += bytes_transferred;
448          if ((!ec && bytes_transferred == 0)
449              || (n = this->check_for_completion(ec, total_transferred_)) == 0
450              || total_transferred_ == buffer_size0 + buffer_size1)
451            break;
452        }
453
454        handler_(ec, static_cast<const std::size_t&>(total_transferred_));
455      }
456    }
457
458  //private:
459    AsyncWriteStream& stream_;
460    std::array<Elem, 2> buffers_;
461    int start_;
462    std::size_t total_transferred_;
463    WriteHandler handler_;
464  };
465
466
467  template <typename AsyncWriteStream, typename ConstBufferSequence,
468      typename CompletionCondition, typename WriteHandler>
469  inline void* asio_handler_allocate(std::size_t size,
470      write_op<AsyncWriteStream, ConstBufferSequence,
471        CompletionCondition, WriteHandler>* this_handler)
472  {
473    return asio_handler_alloc_helpers::allocate(
474        size, this_handler->handler_);
475  }
476
477  template <typename AsyncWriteStream, typename ConstBufferSequence,
478      typename CompletionCondition, typename WriteHandler>
479  inline void asio_handler_deallocate(void* pointer, std::size_t size,
480      write_op<AsyncWriteStream, ConstBufferSequence,
481        CompletionCondition, WriteHandler>* this_handler)
482  {
483    asio_handler_alloc_helpers::deallocate(
484        pointer, size, this_handler->handler_);
485  }
486
487  template <typename AsyncWriteStream, typename ConstBufferSequence,
488      typename CompletionCondition, typename WriteHandler>
489  inline bool asio_handler_is_continuation(
490      write_op<AsyncWriteStream, ConstBufferSequence,
491        CompletionCondition, WriteHandler>* this_handler)
492  {
493    return this_handler->start_ == 0 ? true
494      : asio_handler_cont_helpers::is_continuation(
495          this_handler->handler_);
496  }
497
498  template <typename Function, typename AsyncWriteStream,
499      typename ConstBufferSequence, typename CompletionCondition,
500      typename WriteHandler>
501  inline void asio_handler_invoke(Function& function,
502      write_op<AsyncWriteStream, ConstBufferSequence,
503        CompletionCondition, WriteHandler>* this_handler)
504  {
505    asio_handler_invoke_helpers::invoke(
506        function, this_handler->handler_);
507  }
508
509  template <typename Function, typename AsyncWriteStream,
510      typename ConstBufferSequence, typename CompletionCondition,
511      typename WriteHandler>
512  inline void asio_handler_invoke(const Function& function,
513      write_op<AsyncWriteStream, ConstBufferSequence,
514        CompletionCondition, WriteHandler>* this_handler)
515  {
516    asio_handler_invoke_helpers::invoke(
517        function, this_handler->handler_);
518  }
519} // namespace detail
520
521template <typename AsyncWriteStream, typename ConstBufferSequence,
522  typename CompletionCondition, typename WriteHandler>
523inline ASIO_INITFN_RESULT_TYPE(WriteHandler,
524    void (asio::error_code, std::size_t))
525async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
526    CompletionCondition completion_condition,
527    ASIO_MOVE_ARG(WriteHandler) handler)
528{
529  // If you get an error on the following line it means that your handler does
530  // not meet the documented type requirements for a WriteHandler.
531  ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
532
533  detail::async_result_init<
534    WriteHandler, void (asio::error_code, std::size_t)> init(
535      ASIO_MOVE_CAST(WriteHandler)(handler));
536
537  detail::write_op<AsyncWriteStream, ConstBufferSequence,
538    CompletionCondition, ASIO_HANDLER_TYPE(
539      WriteHandler, void (asio::error_code, std::size_t))>(
540        s, buffers, completion_condition, init.handler)(
541          asio::error_code(), 0, 1);
542
543  return init.result.get();
544}
545
546template <typename AsyncWriteStream, typename ConstBufferSequence,
547    typename WriteHandler>
548inline ASIO_INITFN_RESULT_TYPE(WriteHandler,
549    void (asio::error_code, std::size_t))
550async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
551    ASIO_MOVE_ARG(WriteHandler) handler)
552{
553  // If you get an error on the following line it means that your handler does
554  // not meet the documented type requirements for a WriteHandler.
555  ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
556
557  detail::async_result_init<
558    WriteHandler, void (asio::error_code, std::size_t)> init(
559      ASIO_MOVE_CAST(WriteHandler)(handler));
560
561  detail::write_op<AsyncWriteStream, ConstBufferSequence,
562    detail::transfer_all_t, ASIO_HANDLER_TYPE(
563      WriteHandler, void (asio::error_code, std::size_t))>(
564        s, buffers, transfer_all(), init.handler)(
565          asio::error_code(), 0, 1);
566
567  return init.result.get();
568}
569
570
571} // namespace asio
572
573#include "asio/detail/pop_options.hpp"
574
575#endif // ASIO_IMPL_WRITE_HPP
576