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