Home | History | Annotate | Download | only in impl
      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 
     30 namespace asio {
     31 
     32 template <typename SyncWriteStream, typename ConstBufferSequence,
     33     typename CompletionCondition>
     34 std::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 
     54 template <typename SyncWriteStream, typename ConstBufferSequence>
     55 inline 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 
     63 template <typename SyncWriteStream, typename ConstBufferSequence>
     64 inline 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 
     70 template <typename SyncWriteStream, typename ConstBufferSequence,
     71     typename CompletionCondition>
     72 inline 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 
     82 namespace 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 
    521 template <typename AsyncWriteStream, typename ConstBufferSequence,
    522   typename CompletionCondition, typename WriteHandler>
    523 inline ASIO_INITFN_RESULT_TYPE(WriteHandler,
    524     void (asio::error_code, std::size_t))
    525 async_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 
    546 template <typename AsyncWriteStream, typename ConstBufferSequence,
    547     typename WriteHandler>
    548 inline ASIO_INITFN_RESULT_TYPE(WriteHandler,
    549     void (asio::error_code, std::size_t))
    550 async_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