PageRenderTime 54ms CodeModel.GetById 17ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 1ms

/src/contrib/boost/asio/impl/read_until.ipp

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