PageRenderTime 205ms CodeModel.GetById 127ms app.highlight 70ms RepoModel.GetById 1ms app.codeStats 1ms

/Src/Dependencies/Boost/boost/asio/impl/read_until.hpp

http://hadesmem.googlecode.com/
C++ Header | 1086 lines | 882 code | 112 blank | 92 comment | 108 complexity | f0646d20a0e3a9eafb4b98f87473efc0 MD5 | raw file
   1//
   2// impl/read_until.hpp
   3// ~~~~~~~~~~~~~~~~~~~
   4//
   5// Copyright (c) 2003-2011 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_READ_UNTIL_HPP
  12#define BOOST_ASIO_IMPL_READ_UNTIL_HPP
  13
  14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
  15# pragma once
  16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  17
  18#include <algorithm>
  19#include <string>
  20#include <vector>
  21#include <utility>
  22#include <boost/limits.hpp>
  23#include <boost/asio/buffer.hpp>
  24#include <boost/asio/buffers_iterator.hpp>
  25#include <boost/asio/detail/bind_handler.hpp>
  26#include <boost/asio/detail/handler_alloc_helpers.hpp>
  27#include <boost/asio/detail/handler_invoke_helpers.hpp>
  28#include <boost/asio/detail/handler_type_requirements.hpp>
  29#include <boost/asio/detail/throw_error.hpp>
  30
  31#include <boost/asio/detail/push_options.hpp>
  32
  33namespace boost {
  34namespace asio {
  35
  36template <typename SyncReadStream, typename Allocator>
  37inline std::size_t read_until(SyncReadStream& s,
  38    boost::asio::basic_streambuf<Allocator>& b, char delim)
  39{
  40  boost::system::error_code ec;
  41  std::size_t bytes_transferred = read_until(s, b, delim, ec);
  42  boost::asio::detail::throw_error(ec, "read_until");
  43  return bytes_transferred;
  44}
  45
  46template <typename SyncReadStream, typename Allocator>
  47std::size_t read_until(SyncReadStream& s,
  48    boost::asio::basic_streambuf<Allocator>& b, char delim,
  49    boost::system::error_code& ec)
  50{
  51  std::size_t search_position = 0;
  52  for (;;)
  53  {
  54    // Determine the range of the data to be searched.
  55    typedef typename boost::asio::basic_streambuf<
  56      Allocator>::const_buffers_type const_buffers_type;
  57    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
  58    const_buffers_type buffers = b.data();
  59    iterator begin = iterator::begin(buffers);
  60    iterator start_pos = begin + search_position;
  61    iterator end = iterator::end(buffers);
  62
  63    // Look for a match.
  64    iterator iter = std::find(start_pos, end, delim);
  65    if (iter != end)
  66    {
  67      // Found a match. We're done.
  68      ec = boost::system::error_code();
  69      return iter - begin + 1;
  70    }
  71    else
  72    {
  73      // No match. Next search can start with the new data.
  74      search_position = end - begin;
  75    }
  76
  77    // Check if buffer is full.
  78    if (b.size() == b.max_size())
  79    {
  80      ec = error::not_found;
  81      return 0;
  82    }
  83
  84    // Need more data.
  85    std::size_t bytes_to_read = read_size_helper(b, 65536);
  86    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
  87    if (ec)
  88      return 0;
  89  }
  90}
  91
  92template <typename SyncReadStream, typename Allocator>
  93inline std::size_t read_until(SyncReadStream& s,
  94    boost::asio::basic_streambuf<Allocator>& b, const std::string& delim)
  95{
  96  boost::system::error_code ec;
  97  std::size_t bytes_transferred = read_until(s, b, delim, ec);
  98  boost::asio::detail::throw_error(ec, "read_until");
  99  return bytes_transferred;
 100}
 101
 102namespace detail
 103{
 104  // Algorithm that finds a subsequence of equal values in a sequence. Returns
 105  // (iterator,true) if a full match was found, in which case the iterator
 106  // points to the beginning of the match. Returns (iterator,false) if a
 107  // partial match was found at the end of the first sequence, in which case
 108  // the iterator points to the beginning of the partial match. Returns
 109  // (last1,false) if no full or partial match was found.
 110  template <typename Iterator1, typename Iterator2>
 111  std::pair<Iterator1, bool> partial_search(
 112      Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
 113  {
 114    for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
 115    {
 116      Iterator1 test_iter1 = iter1;
 117      Iterator2 test_iter2 = first2;
 118      for (;; ++test_iter1, ++test_iter2)
 119      {
 120        if (test_iter2 == last2)
 121          return std::make_pair(iter1, true);
 122        if (test_iter1 == last1)
 123        {
 124          if (test_iter2 != first2)
 125            return std::make_pair(iter1, false);
 126          else
 127            break;
 128        }
 129        if (*test_iter1 != *test_iter2)
 130          break;
 131      }
 132    }
 133    return std::make_pair(last1, false);
 134  }
 135} // namespace detail
 136
 137template <typename SyncReadStream, typename Allocator>
 138std::size_t read_until(SyncReadStream& s,
 139    boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
 140    boost::system::error_code& ec)
 141{
 142  std::size_t search_position = 0;
 143  for (;;)
 144  {
 145    // Determine the range of the data to be searched.
 146    typedef typename boost::asio::basic_streambuf<
 147      Allocator>::const_buffers_type const_buffers_type;
 148    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
 149    const_buffers_type buffers = b.data();
 150    iterator begin = iterator::begin(buffers);
 151    iterator start_pos = begin + search_position;
 152    iterator end = iterator::end(buffers);
 153
 154    // Look for a match.
 155    std::pair<iterator, bool> result = detail::partial_search(
 156        start_pos, end, delim.begin(), delim.end());
 157    if (result.first != end)
 158    {
 159      if (result.second)
 160      {
 161        // Full match. We're done.
 162        ec = boost::system::error_code();
 163        return result.first - begin + delim.length();
 164      }
 165      else
 166      {
 167        // Partial match. Next search needs to start from beginning of match.
 168        search_position = result.first - begin;
 169      }
 170    }
 171    else
 172    {
 173      // No match. Next search can start with the new data.
 174      search_position = end - begin;
 175    }
 176
 177    // Check if buffer is full.
 178    if (b.size() == b.max_size())
 179    {
 180      ec = error::not_found;
 181      return 0;
 182    }
 183
 184    // Need more data.
 185    std::size_t bytes_to_read = read_size_helper(b, 65536);
 186    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
 187    if (ec)
 188      return 0;
 189  }
 190}
 191
 192template <typename SyncReadStream, typename Allocator>
 193inline std::size_t read_until(SyncReadStream& s,
 194    boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
 195{
 196  boost::system::error_code ec;
 197  std::size_t bytes_transferred = read_until(s, b, expr, ec);
 198  boost::asio::detail::throw_error(ec, "read_until");
 199  return bytes_transferred;
 200}
 201
 202template <typename SyncReadStream, typename Allocator>
 203std::size_t read_until(SyncReadStream& s,
 204    boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
 205    boost::system::error_code& ec)
 206{
 207  std::size_t search_position = 0;
 208  for (;;)
 209  {
 210    // Determine the range of the data to be searched.
 211    typedef typename boost::asio::basic_streambuf<
 212      Allocator>::const_buffers_type const_buffers_type;
 213    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
 214    const_buffers_type buffers = b.data();
 215    iterator begin = iterator::begin(buffers);
 216    iterator start_pos = begin + search_position;
 217    iterator end = iterator::end(buffers);
 218
 219    // Look for a match.
 220    boost::match_results<iterator,
 221      typename std::vector<boost::sub_match<iterator> >::allocator_type>
 222        match_results;
 223    if (regex_search(start_pos, end, match_results, expr,
 224          boost::match_default | boost::match_partial))
 225    {
 226      if (match_results[0].matched)
 227      {
 228        // Full match. We're done.
 229        ec = boost::system::error_code();
 230        return match_results[0].second - begin;
 231      }
 232      else
 233      {
 234        // Partial match. Next search needs to start from beginning of match.
 235        search_position = match_results[0].first - begin;
 236      }
 237    }
 238    else
 239    {
 240      // No match. Next search can start with the new data.
 241      search_position = end - begin;
 242    }
 243
 244    // Check if buffer is full.
 245    if (b.size() == b.max_size())
 246    {
 247      ec = error::not_found;
 248      return 0;
 249    }
 250
 251    // Need more data.
 252    std::size_t bytes_to_read = read_size_helper(b, 65536);
 253    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
 254    if (ec)
 255      return 0;
 256  }
 257}
 258
 259template <typename SyncReadStream, typename Allocator, typename MatchCondition>
 260std::size_t read_until(SyncReadStream& s,
 261    boost::asio::basic_streambuf<Allocator>& b,
 262    MatchCondition match_condition, boost::system::error_code& ec,
 263    typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
 264{
 265  std::size_t search_position = 0;
 266  for (;;)
 267  {
 268    // Determine the range of the data to be searched.
 269    typedef typename boost::asio::basic_streambuf<
 270      Allocator>::const_buffers_type const_buffers_type;
 271    typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
 272    const_buffers_type buffers = b.data();
 273    iterator begin = iterator::begin(buffers);
 274    iterator start_pos = begin + search_position;
 275    iterator end = iterator::end(buffers);
 276
 277    // Look for a match.
 278    std::pair<iterator, bool> result = match_condition(start_pos, end);
 279    if (result.second)
 280    {
 281      // Full match. We're done.
 282      ec = boost::system::error_code();
 283      return result.first - begin;
 284    }
 285    else if (result.first != end)
 286    {
 287      // Partial match. Next search needs to start from beginning of match.
 288      search_position = result.first - begin;
 289    }
 290    else
 291    {
 292      // No match. Next search can start with the new data.
 293      search_position = end - begin;
 294    }
 295
 296    // Check if buffer is full.
 297    if (b.size() == b.max_size())
 298    {
 299      ec = error::not_found;
 300      return 0;
 301    }
 302
 303    // Need more data.
 304    std::size_t bytes_to_read = read_size_helper(b, 65536);
 305    b.commit(s.read_some(b.prepare(bytes_to_read), ec));
 306    if (ec)
 307      return 0;
 308  }
 309}
 310
 311template <typename SyncReadStream, typename Allocator, typename MatchCondition>
 312inline std::size_t read_until(SyncReadStream& s,
 313    boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
 314    typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
 315{
 316  boost::system::error_code ec;
 317  std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
 318  boost::asio::detail::throw_error(ec, "read_until");
 319  return bytes_transferred;
 320}
 321
 322namespace detail
 323{
 324  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 325  class read_until_delim_op
 326  {
 327  public:
 328    read_until_delim_op(AsyncReadStream& stream,
 329        boost::asio::basic_streambuf<Allocator>& streambuf,
 330        char delim, ReadHandler& handler)
 331      : stream_(stream),
 332        streambuf_(streambuf),
 333        delim_(delim),
 334        search_position_(0),
 335        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
 336    {
 337    }
 338
 339#if defined(BOOST_ASIO_HAS_MOVE)
 340    read_until_delim_op(const read_until_delim_op& other)
 341      : stream_(other.stream_),
 342        streambuf_(other.streambuf_),
 343        delim_(other.delim_),
 344        search_position_(other.search_position_),
 345        handler_(other.handler_)
 346    {
 347    }
 348
 349    read_until_delim_op(read_until_delim_op&& other)
 350      : stream_(other.stream_),
 351        streambuf_(other.streambuf_),
 352        delim_(other.delim_),
 353        search_position_(other.search_position_),
 354        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
 355    {
 356    }
 357#endif // defined(BOOST_ASIO_HAS_MOVE)
 358
 359    void operator()(const boost::system::error_code& ec,
 360        std::size_t bytes_transferred, int start = 0)
 361    {
 362      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
 363      std::size_t bytes_to_read;
 364      switch (start)
 365      {
 366      case 1:
 367        for (;;)
 368        {
 369          {
 370            // Determine the range of the data to be searched.
 371            typedef typename boost::asio::basic_streambuf<
 372              Allocator>::const_buffers_type const_buffers_type;
 373            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
 374            const_buffers_type buffers = streambuf_.data();
 375            iterator begin = iterator::begin(buffers);
 376            iterator start_pos = begin + search_position_;
 377            iterator end = iterator::end(buffers);
 378
 379            // Look for a match.
 380            iterator iter = std::find(start_pos, end, delim_);
 381            if (iter != end)
 382            {
 383              // Found a match. We're done.
 384              search_position_ = iter - begin + 1;
 385              bytes_to_read = 0;
 386            }
 387
 388            // No match yet. Check if buffer is full.
 389            else if (streambuf_.size() == streambuf_.max_size())
 390            {
 391              search_position_ = not_found;
 392              bytes_to_read = 0;
 393            }
 394
 395            // Need to read some more data.
 396            else
 397            {
 398              // Next search can start with the new data.
 399              search_position_ = end - begin;
 400              bytes_to_read = read_size_helper(streambuf_, 65536);
 401            }
 402          }
 403
 404          // Check if we're done.
 405          if (!start && bytes_to_read == 0)
 406            break;
 407
 408          // Start a new asynchronous read operation to obtain more data.
 409          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
 410              BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this));
 411          return; default:
 412          streambuf_.commit(bytes_transferred);
 413          if (ec || bytes_transferred == 0)
 414            break;
 415        }
 416
 417        const boost::system::error_code result_ec =
 418          (search_position_ == not_found)
 419          ? error::not_found : ec;
 420
 421        const std::size_t result_n =
 422          (ec || search_position_ == not_found)
 423          ? 0 : search_position_;
 424
 425        handler_(result_ec, result_n);
 426      }
 427    }
 428
 429  //private:
 430    AsyncReadStream& stream_;
 431    boost::asio::basic_streambuf<Allocator>& streambuf_;
 432    char delim_;
 433    std::size_t search_position_;
 434    ReadHandler handler_;
 435  };
 436
 437  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 438  inline void* asio_handler_allocate(std::size_t size,
 439      read_until_delim_op<AsyncReadStream,
 440        Allocator, ReadHandler>* this_handler)
 441  {
 442    return boost_asio_handler_alloc_helpers::allocate(
 443        size, this_handler->handler_);
 444  }
 445
 446  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 447  inline void asio_handler_deallocate(void* pointer, std::size_t size,
 448      read_until_delim_op<AsyncReadStream,
 449        Allocator, ReadHandler>* this_handler)
 450  {
 451    boost_asio_handler_alloc_helpers::deallocate(
 452        pointer, size, this_handler->handler_);
 453  }
 454
 455  template <typename Function, typename AsyncReadStream, typename Allocator,
 456      typename ReadHandler>
 457  inline void asio_handler_invoke(Function& function,
 458      read_until_delim_op<AsyncReadStream,
 459        Allocator, ReadHandler>* this_handler)
 460  {
 461    boost_asio_handler_invoke_helpers::invoke(
 462        function, this_handler->handler_);
 463  }
 464
 465  template <typename Function, typename AsyncReadStream, typename Allocator,
 466      typename ReadHandler>
 467  inline void asio_handler_invoke(const Function& function,
 468      read_until_delim_op<AsyncReadStream,
 469        Allocator, ReadHandler>* this_handler)
 470  {
 471    boost_asio_handler_invoke_helpers::invoke(
 472        function, this_handler->handler_);
 473  }
 474
 475  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 476  inline read_until_delim_op<AsyncReadStream, Allocator, ReadHandler>
 477  make_read_until_delim_op(AsyncReadStream& s,
 478      boost::asio::basic_streambuf<Allocator>& b,
 479      char delim, ReadHandler handler)
 480  {
 481    return read_until_delim_op<AsyncReadStream, Allocator, ReadHandler>(
 482        s, b, delim, handler);
 483  }
 484} // namespace detail
 485
 486template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 487void async_read_until(AsyncReadStream& s,
 488    boost::asio::basic_streambuf<Allocator>& b, char delim,
 489    BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
 490{
 491  // If you get an error on the following line it means that your handler does
 492  // not meet the documented type requirements for a ReadHandler.
 493  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
 494
 495  detail::make_read_until_delim_op(
 496    s, b, delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))(
 497      boost::system::error_code(), 0, 1);
 498}
 499
 500namespace detail
 501{
 502  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 503  class read_until_delim_string_op
 504  {
 505  public:
 506    read_until_delim_string_op(AsyncReadStream& stream,
 507        boost::asio::basic_streambuf<Allocator>& streambuf,
 508        const std::string& delim, ReadHandler& handler)
 509      : stream_(stream),
 510        streambuf_(streambuf),
 511        delim_(delim),
 512        search_position_(0),
 513        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
 514    {
 515    }
 516
 517#if defined(BOOST_ASIO_HAS_MOVE)
 518    read_until_delim_string_op(const read_until_delim_string_op& other)
 519      : stream_(other.stream_),
 520        streambuf_(other.streambuf_),
 521        delim_(other.delim_),
 522        search_position_(other.search_position_),
 523        handler_(other.handler_)
 524    {
 525    }
 526
 527    read_until_delim_string_op(read_until_delim_string_op&& other)
 528      : stream_(other.stream_),
 529        streambuf_(other.streambuf_),
 530        delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
 531        search_position_(other.search_position_),
 532        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
 533    {
 534    }
 535#endif // defined(BOOST_ASIO_HAS_MOVE)
 536
 537    void operator()(const boost::system::error_code& ec,
 538        std::size_t bytes_transferred, int start = 0)
 539    {
 540      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
 541      std::size_t bytes_to_read;
 542      switch (start)
 543      {
 544      case 1:
 545        for (;;)
 546        {
 547          {
 548            // Determine the range of the data to be searched.
 549            typedef typename boost::asio::basic_streambuf<
 550              Allocator>::const_buffers_type const_buffers_type;
 551            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
 552            const_buffers_type buffers = streambuf_.data();
 553            iterator begin = iterator::begin(buffers);
 554            iterator start_pos = begin + search_position_;
 555            iterator end = iterator::end(buffers);
 556
 557            // Look for a match.
 558            std::pair<iterator, bool> result = detail::partial_search(
 559                start_pos, end, delim_.begin(), delim_.end());
 560            if (result.first != end && result.second)
 561            {
 562              // Full match. We're done.
 563              search_position_ = result.first - begin + delim_.length();
 564              bytes_to_read = 0;
 565            }
 566
 567            // No match yet. Check if buffer is full.
 568            else if (streambuf_.size() == streambuf_.max_size())
 569            {
 570              search_position_ = not_found;
 571              bytes_to_read = 0;
 572            }
 573
 574            // Need to read some more data.
 575            else
 576            {
 577              if (result.first != end)
 578              {
 579                // Partial match. Next search needs to start from beginning of
 580                // match.
 581                search_position_ = result.first - begin;
 582              }
 583              else
 584              {
 585                // Next search can start with the new data.
 586                search_position_ = end - begin;
 587              }
 588
 589              bytes_to_read = read_size_helper(streambuf_, 65536);
 590            }
 591          }
 592
 593          // Check if we're done.
 594          if (!start && bytes_to_read == 0)
 595            break;
 596
 597          // Start a new asynchronous read operation to obtain more data.
 598          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
 599              BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this));
 600          return; default:
 601          streambuf_.commit(bytes_transferred);
 602          if (ec || bytes_transferred == 0)
 603            break;
 604        }
 605
 606        const boost::system::error_code result_ec =
 607          (search_position_ == not_found)
 608          ? error::not_found : ec;
 609
 610        const std::size_t result_n =
 611          (ec || search_position_ == not_found)
 612          ? 0 : search_position_;
 613
 614        handler_(result_ec, result_n);
 615      }
 616    }
 617
 618  //private:
 619    AsyncReadStream& stream_;
 620    boost::asio::basic_streambuf<Allocator>& streambuf_;
 621    std::string delim_;
 622    std::size_t search_position_;
 623    ReadHandler handler_;
 624  };
 625
 626  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 627  inline void* asio_handler_allocate(std::size_t size,
 628      read_until_delim_string_op<AsyncReadStream,
 629        Allocator, ReadHandler>* this_handler)
 630  {
 631    return boost_asio_handler_alloc_helpers::allocate(
 632        size, this_handler->handler_);
 633  }
 634
 635  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 636  inline void asio_handler_deallocate(void* pointer, std::size_t size,
 637      read_until_delim_string_op<AsyncReadStream,
 638        Allocator, ReadHandler>* this_handler)
 639  {
 640    boost_asio_handler_alloc_helpers::deallocate(
 641        pointer, size, this_handler->handler_);
 642  }
 643
 644  template <typename Function, typename AsyncReadStream,
 645      typename Allocator, typename ReadHandler>
 646  inline void asio_handler_invoke(Function& function,
 647      read_until_delim_string_op<AsyncReadStream,
 648        Allocator, ReadHandler>* this_handler)
 649  {
 650    boost_asio_handler_invoke_helpers::invoke(
 651        function, this_handler->handler_);
 652  }
 653
 654  template <typename Function, typename AsyncReadStream,
 655      typename Allocator, typename ReadHandler>
 656  inline void asio_handler_invoke(const Function& function,
 657      read_until_delim_string_op<AsyncReadStream,
 658        Allocator, ReadHandler>* this_handler)
 659  {
 660    boost_asio_handler_invoke_helpers::invoke(
 661        function, this_handler->handler_);
 662  }
 663
 664  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 665  inline read_until_delim_string_op<AsyncReadStream, Allocator, ReadHandler>
 666  make_read_until_delim_string_op(AsyncReadStream& s,
 667      boost::asio::basic_streambuf<Allocator>& b,
 668      const std::string& delim, ReadHandler handler)
 669  {
 670    return read_until_delim_string_op<AsyncReadStream, Allocator, ReadHandler>(
 671        s, b, delim, handler);
 672  }
 673} // namespace detail
 674
 675template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 676void async_read_until(AsyncReadStream& s,
 677    boost::asio::basic_streambuf<Allocator>& b, const std::string& delim,
 678    BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
 679{
 680  // If you get an error on the following line it means that your handler does
 681  // not meet the documented type requirements for a ReadHandler.
 682  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
 683
 684  detail::make_read_until_delim_string_op(
 685    s, b, delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))(
 686      boost::system::error_code(), 0, 1);
 687}
 688
 689namespace detail
 690{
 691  template <typename AsyncReadStream, typename Allocator,
 692      typename RegEx, typename ReadHandler>
 693  class read_until_expr_op
 694  {
 695  public:
 696    read_until_expr_op(AsyncReadStream& stream,
 697        boost::asio::basic_streambuf<Allocator>& streambuf,
 698        const boost::regex& expr, ReadHandler& handler)
 699      : stream_(stream),
 700        streambuf_(streambuf),
 701        expr_(expr),
 702        search_position_(0),
 703        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
 704    {
 705    }
 706
 707#if defined(BOOST_ASIO_HAS_MOVE)
 708    read_until_expr_op(const read_until_expr_op& other)
 709      : stream_(other.stream_),
 710        streambuf_(other.streambuf_),
 711        expr_(other.expr_),
 712        search_position_(other.search_position_),
 713        handler_(other.handler_)
 714    {
 715    }
 716
 717    read_until_expr_op(read_until_expr_op&& other)
 718      : stream_(other.stream_),
 719        streambuf_(other.streambuf_),
 720        expr_(other.expr_),
 721        search_position_(other.search_position_),
 722        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
 723    {
 724    }
 725#endif // defined(BOOST_ASIO_HAS_MOVE)
 726
 727    void operator()(const boost::system::error_code& ec,
 728        std::size_t bytes_transferred, int start = 0)
 729    {
 730      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
 731      std::size_t bytes_to_read;
 732      switch (start)
 733      {
 734      case 1:
 735        for (;;)
 736        {
 737          {
 738            // Determine the range of the data to be searched.
 739            typedef typename boost::asio::basic_streambuf<
 740              Allocator>::const_buffers_type const_buffers_type;
 741            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
 742            const_buffers_type buffers = streambuf_.data();
 743            iterator begin = iterator::begin(buffers);
 744            iterator start_pos = begin + search_position_;
 745            iterator end = iterator::end(buffers);
 746
 747            // Look for a match.
 748            boost::match_results<iterator,
 749              typename std::vector<boost::sub_match<iterator> >::allocator_type>
 750                match_results;
 751            bool match = regex_search(start_pos, end, match_results, expr_,
 752                boost::match_default | boost::match_partial);
 753            if (match && match_results[0].matched)
 754            {
 755              // Full match. We're done.
 756              search_position_ = match_results[0].second - begin;
 757              bytes_to_read = 0;
 758            }
 759
 760            // No match yet. Check if buffer is full.
 761            else if (streambuf_.size() == streambuf_.max_size())
 762            {
 763              search_position_ = not_found;
 764              bytes_to_read = 0;
 765            }
 766
 767            // Need to read some more data.
 768            else
 769            {
 770              if (match)
 771              {
 772                // Partial match. Next search needs to start from beginning of
 773                // match.
 774                search_position_ = match_results[0].first - begin;
 775              }
 776              else
 777              {
 778                // Next search can start with the new data.
 779                search_position_ = end - begin;
 780              }
 781
 782              bytes_to_read = read_size_helper(streambuf_, 65536);
 783            }
 784          }
 785
 786          // Check if we're done.
 787          if (!start && bytes_to_read == 0)
 788            break;
 789
 790          // Start a new asynchronous read operation to obtain more data.
 791          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
 792              BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this));
 793          return; default:
 794          streambuf_.commit(bytes_transferred);
 795          if (ec || bytes_transferred == 0)
 796            break;
 797        }
 798
 799        const boost::system::error_code result_ec =
 800          (search_position_ == not_found)
 801          ? error::not_found : ec;
 802
 803        const std::size_t result_n =
 804          (ec || search_position_ == not_found)
 805          ? 0 : search_position_;
 806
 807        handler_(result_ec, result_n);
 808      }
 809    }
 810
 811  //private:
 812    AsyncReadStream& stream_;
 813    boost::asio::basic_streambuf<Allocator>& streambuf_;
 814    RegEx expr_;
 815    std::size_t search_position_;
 816    ReadHandler handler_;
 817  };
 818
 819  template <typename AsyncReadStream, typename Allocator,
 820      typename RegEx, typename ReadHandler>
 821  inline void* asio_handler_allocate(std::size_t size,
 822      read_until_expr_op<AsyncReadStream,
 823        Allocator, RegEx, ReadHandler>* this_handler)
 824  {
 825    return boost_asio_handler_alloc_helpers::allocate(
 826        size, this_handler->handler_);
 827  }
 828
 829  template <typename AsyncReadStream, typename Allocator,
 830      typename RegEx, typename ReadHandler>
 831  inline void asio_handler_deallocate(void* pointer, std::size_t size,
 832      read_until_expr_op<AsyncReadStream,
 833        Allocator, RegEx, ReadHandler>* this_handler)
 834  {
 835    boost_asio_handler_alloc_helpers::deallocate(
 836        pointer, size, this_handler->handler_);
 837  }
 838
 839  template <typename Function, typename AsyncReadStream, typename Allocator,
 840      typename RegEx, typename ReadHandler>
 841  inline void asio_handler_invoke(Function& function,
 842      read_until_expr_op<AsyncReadStream,
 843        Allocator, RegEx, ReadHandler>* this_handler)
 844  {
 845    boost_asio_handler_invoke_helpers::invoke(
 846        function, this_handler->handler_);
 847  }
 848
 849  template <typename Function, typename AsyncReadStream, typename Allocator,
 850      typename RegEx, typename ReadHandler>
 851  inline void asio_handler_invoke(const Function& function,
 852      read_until_expr_op<AsyncReadStream,
 853        Allocator, RegEx, ReadHandler>* this_handler)
 854  {
 855    boost_asio_handler_invoke_helpers::invoke(
 856        function, this_handler->handler_);
 857  }
 858
 859  template <typename AsyncReadStream, typename Allocator,
 860      typename RegEx, typename ReadHandler>
 861  inline read_until_expr_op<AsyncReadStream, Allocator, RegEx, ReadHandler>
 862  make_read_until_expr_op(AsyncReadStream& s,
 863      boost::asio::basic_streambuf<Allocator>& b,
 864      const boost::regex& expr, ReadHandler handler)
 865  {
 866    return read_until_expr_op<AsyncReadStream, Allocator, RegEx, ReadHandler>(
 867        s, b, expr, handler);
 868  }
 869} // namespace detail
 870
 871template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
 872void async_read_until(AsyncReadStream& s,
 873    boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
 874    BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
 875{
 876  // If you get an error on the following line it means that your handler does
 877  // not meet the documented type requirements for a ReadHandler.
 878  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
 879
 880  detail::make_read_until_expr_op(
 881    s, b, expr, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))(
 882      boost::system::error_code(), 0, 1);
 883}
 884
 885namespace detail
 886{
 887  template <typename AsyncReadStream, typename Allocator,
 888      typename MatchCondition, typename ReadHandler>
 889  class read_until_match_op
 890  {
 891  public:
 892    read_until_match_op(AsyncReadStream& stream,
 893        boost::asio::basic_streambuf<Allocator>& streambuf,
 894        MatchCondition match_condition, ReadHandler& handler)
 895      : stream_(stream),
 896        streambuf_(streambuf),
 897        match_condition_(match_condition),
 898        search_position_(0),
 899        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
 900    {
 901    }
 902
 903#if defined(BOOST_ASIO_HAS_MOVE)
 904    read_until_match_op(const read_until_match_op& other)
 905      : stream_(other.stream_),
 906        streambuf_(other.streambuf_),
 907        match_condition_(other.match_condition_),
 908        search_position_(other.search_position_),
 909        handler_(other.handler_)
 910    {
 911    }
 912
 913    read_until_match_op(read_until_match_op&& other)
 914      : stream_(other.stream_),
 915        streambuf_(other.streambuf_),
 916        match_condition_(other.match_condition_),
 917        search_position_(other.search_position_),
 918        handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
 919    {
 920    }
 921#endif // defined(BOOST_ASIO_HAS_MOVE)
 922
 923    void operator()(const boost::system::error_code& ec,
 924        std::size_t bytes_transferred, int start = 0)
 925    {
 926      const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
 927      std::size_t bytes_to_read;
 928      switch (start)
 929      {
 930      case 1:
 931        for (;;)
 932        {
 933          {
 934            // Determine the range of the data to be searched.
 935            typedef typename boost::asio::basic_streambuf<
 936              Allocator>::const_buffers_type const_buffers_type;
 937            typedef boost::asio::buffers_iterator<const_buffers_type> iterator;
 938            const_buffers_type buffers = streambuf_.data();
 939            iterator begin = iterator::begin(buffers);
 940            iterator start_pos = begin + search_position_;
 941            iterator end = iterator::end(buffers);
 942
 943            // Look for a match.
 944            std::pair<iterator, bool> result = match_condition_(start_pos, end);
 945            if (result.second)
 946            {
 947              // Full match. We're done.
 948              search_position_ = result.first - begin;
 949              bytes_to_read = 0;
 950            }
 951
 952            // No match yet. Check if buffer is full.
 953            else if (streambuf_.size() == streambuf_.max_size())
 954            {
 955              search_position_ = not_found;
 956              bytes_to_read = 0;
 957            }
 958
 959            // Need to read some more data.
 960            else
 961            {
 962              if (result.first != end)
 963              {
 964                // Partial match. Next search needs to start from beginning of
 965                // match.
 966                search_position_ = result.first - begin;
 967              }
 968              else
 969              {
 970                // Next search can start with the new data.
 971                search_position_ = end - begin;
 972              }
 973
 974              bytes_to_read = read_size_helper(streambuf_, 65536);
 975            }
 976          }
 977
 978          // Check if we're done.
 979          if (!start && bytes_to_read == 0)
 980            break;
 981
 982          // Start a new asynchronous read operation to obtain more data.
 983          stream_.async_read_some(streambuf_.prepare(bytes_to_read),
 984              BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this));
 985          return; default:
 986          streambuf_.commit(bytes_transferred);
 987          if (ec || bytes_transferred == 0)
 988            break;
 989        }
 990
 991        const boost::system::error_code result_ec =
 992          (search_position_ == not_found)
 993          ? error::not_found : ec;
 994
 995        const std::size_t result_n =
 996          (ec || search_position_ == not_found)
 997          ? 0 : search_position_;
 998
 999        handler_(result_ec, result_n);
1000      }
1001    }
1002
1003  //private:
1004    AsyncReadStream& stream_;
1005    boost::asio::basic_streambuf<Allocator>& streambuf_;
1006    MatchCondition match_condition_;
1007    std::size_t search_position_;
1008    ReadHandler handler_;
1009  };
1010
1011  template <typename AsyncReadStream, typename Allocator,
1012      typename MatchCondition, typename ReadHandler>
1013  inline void* asio_handler_allocate(std::size_t size,
1014      read_until_match_op<AsyncReadStream,
1015        Allocator, MatchCondition, ReadHandler>* this_handler)
1016  {
1017    return boost_asio_handler_alloc_helpers::allocate(
1018        size, this_handler->handler_);
1019  }
1020
1021  template <typename AsyncReadStream, typename Allocator,
1022      typename MatchCondition, typename ReadHandler>
1023  inline void asio_handler_deallocate(void* pointer, std::size_t size,
1024      read_until_match_op<AsyncReadStream,
1025        Allocator, MatchCondition, ReadHandler>* this_handler)
1026  {
1027    boost_asio_handler_alloc_helpers::deallocate(
1028        pointer, size, this_handler->handler_);
1029  }
1030
1031  template <typename Function, typename AsyncReadStream, typename Allocator,
1032      typename MatchCondition, typename ReadHandler>
1033  inline void asio_handler_invoke(Function& function,
1034      read_until_match_op<AsyncReadStream,
1035        Allocator, MatchCondition, ReadHandler>* this_handler)
1036  {
1037    boost_asio_handler_invoke_helpers::invoke(
1038        function, this_handler->handler_);
1039  }
1040
1041  template <typename Function, typename AsyncReadStream, typename Allocator,
1042      typename MatchCondition, typename ReadHandler>
1043  inline void asio_handler_invoke(const Function& function,
1044      read_until_match_op<AsyncReadStream,
1045        Allocator, MatchCondition, ReadHandler>* this_handler)
1046  {
1047    boost_asio_handler_invoke_helpers::invoke(
1048        function, this_handler->handler_);
1049  }
1050
1051  template <typename AsyncReadStream, typename Allocator,
1052      typename MatchCondition, typename ReadHandler>
1053  inline read_until_match_op<AsyncReadStream, Allocator,
1054      MatchCondition, ReadHandler>
1055  make_read_until_match_op(AsyncReadStream& s,
1056      boost::asio::basic_streambuf<Allocator>& b,
1057      MatchCondition match_condition, ReadHandler handler)
1058  {
1059    return read_until_match_op<AsyncReadStream,
1060      Allocator, MatchCondition, ReadHandler>(
1061        s, b, match_condition, handler);
1062  }
1063} // namespace detail
1064
1065template <typename AsyncReadStream, typename Allocator,
1066    typename MatchCondition, typename ReadHandler>
1067void async_read_until(AsyncReadStream& s,
1068    boost::asio::basic_streambuf<Allocator>& b,
1069    MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1070    typename boost::enable_if<is_match_condition<MatchCondition> >::type*)
1071{
1072  // If you get an error on the following line it means that your handler does
1073  // not meet the documented type requirements for a ReadHandler.
1074  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1075
1076  detail::make_read_until_match_op(
1077    s, b, match_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))(
1078      boost::system::error_code(), 0, 1);
1079}
1080
1081} // namespace asio
1082} // namespace boost
1083
1084#include <boost/asio/detail/pop_options.hpp>
1085
1086#endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP