Realistic 3D camera system
3D camera system components
read_until.hpp
Go to the documentation of this file.
1 //
2 // impl/read_until.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_UNTIL_HPP
12 #define 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 "asio/buffer.hpp"
29 #include "asio/detail/limits.hpp"
31 
33 
34 namespace asio {
35 
36 template <typename SyncReadStream, typename Allocator>
37 inline std::size_t read_until(SyncReadStream& s,
39 {
41  std::size_t bytes_transferred = read_until(s, b, delim, ec);
42  asio::detail::throw_error(ec, "read_until");
43  return bytes_transferred;
44 }
45 
46 template <typename SyncReadStream, typename Allocator>
47 std::size_t read_until(SyncReadStream& s,
49  asio::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 asio::basic_streambuf<
56  Allocator>::const_buffers_type const_buffers_type;
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 = asio::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 
92 template <typename SyncReadStream, typename Allocator>
93 inline std::size_t read_until(SyncReadStream& s,
94  asio::basic_streambuf<Allocator>& b, const std::string& delim)
95 {
97  std::size_t bytes_transferred = read_until(s, b, delim, ec);
98  asio::detail::throw_error(ec, "read_until");
99  return bytes_transferred;
100 }
101 
102 namespace 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 
137 template <typename SyncReadStream, typename Allocator>
138 std::size_t read_until(SyncReadStream& s,
139  asio::basic_streambuf<Allocator>& b, const std::string& delim,
140  asio::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 asio::basic_streambuf<
147  Allocator>::const_buffers_type const_buffers_type;
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 = asio::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 
192 #if defined(ASIO_HAS_BOOST_REGEX)
193 
194 template <typename SyncReadStream, typename Allocator>
195 inline std::size_t read_until(SyncReadStream& s,
196  asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
197 {
198  asio::error_code ec;
199  std::size_t bytes_transferred = read_until(s, b, expr, ec);
200  asio::detail::throw_error(ec, "read_until");
201  return bytes_transferred;
202 }
203 
204 template <typename SyncReadStream, typename Allocator>
205 std::size_t read_until(SyncReadStream& s,
206  asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
207  asio::error_code& ec)
208 {
209  std::size_t search_position = 0;
210  for (;;)
211  {
212  // Determine the range of the data to be searched.
213  typedef typename asio::basic_streambuf<
214  Allocator>::const_buffers_type const_buffers_type;
216  const_buffers_type buffers = b.data();
217  iterator begin = iterator::begin(buffers);
218  iterator start_pos = begin + search_position;
219  iterator end = iterator::end(buffers);
220 
221  // Look for a match.
222  boost::match_results<iterator,
223  typename std::vector<boost::sub_match<iterator> >::allocator_type>
224  match_results;
225  if (regex_search(start_pos, end, match_results, expr,
226  boost::match_default | boost::match_partial))
227  {
228  if (match_results[0].matched)
229  {
230  // Full match. We're done.
231  ec = asio::error_code();
232  return match_results[0].second - begin;
233  }
234  else
235  {
236  // Partial match. Next search needs to start from beginning of match.
237  search_position = match_results[0].first - begin;
238  }
239  }
240  else
241  {
242  // No match. Next search can start with the new data.
243  search_position = end - begin;
244  }
245 
246  // Check if buffer is full.
247  if (b.size() == b.max_size())
248  {
249  ec = error::not_found;
250  return 0;
251  }
252 
253  // Need more data.
254  std::size_t bytes_to_read = read_size_helper(b, 65536);
255  b.commit(s.read_some(b.prepare(bytes_to_read), ec));
256  if (ec)
257  return 0;
258  }
259 }
260 
261 #endif // defined(ASIO_HAS_BOOST_REGEX)
262 
263 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
264 std::size_t read_until(SyncReadStream& s,
266  MatchCondition match_condition, asio::error_code& ec,
268 {
269  std::size_t search_position = 0;
270  for (;;)
271  {
272  // Determine the range of the data to be searched.
273  typedef typename asio::basic_streambuf<
274  Allocator>::const_buffers_type const_buffers_type;
276  const_buffers_type buffers = b.data();
277  iterator begin = iterator::begin(buffers);
278  iterator start_pos = begin + search_position;
279  iterator end = iterator::end(buffers);
280 
281  // Look for a match.
282  std::pair<iterator, bool> result = match_condition(start_pos, end);
283  if (result.second)
284  {
285  // Full match. We're done.
286  ec = asio::error_code();
287  return result.first - begin;
288  }
289  else if (result.first != end)
290  {
291  // Partial match. Next search needs to start from beginning of match.
292  search_position = result.first - begin;
293  }
294  else
295  {
296  // No match. Next search can start with the new data.
297  search_position = end - begin;
298  }
299 
300  // Check if buffer is full.
301  if (b.size() == b.max_size())
302  {
303  ec = error::not_found;
304  return 0;
305  }
306 
307  // Need more data.
308  std::size_t bytes_to_read = read_size_helper(b, 65536);
309  b.commit(s.read_some(b.prepare(bytes_to_read), ec));
310  if (ec)
311  return 0;
312  }
313 }
314 
315 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
316 inline std::size_t read_until(SyncReadStream& s,
319 {
320  asio::error_code ec;
321  std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
322  asio::detail::throw_error(ec, "read_until");
323  return bytes_transferred;
324 }
325 
326 namespace detail
327 {
328  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
330  {
331  public:
332  read_until_delim_op(AsyncReadStream& stream,
334  char delim, ReadHandler& handler)
335  : stream_(stream),
336  streambuf_(streambuf),
337  delim_(delim),
338  start_(0),
339  search_position_(0),
340  handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
341  {
342  }
343 
344 #if defined(ASIO_HAS_MOVE)
346  : stream_(other.stream_),
347  streambuf_(other.streambuf_),
348  delim_(other.delim_),
349  start_(other.start_),
350  search_position_(other.search_position_),
351  handler_(other.handler_)
352  {
353  }
354 
356  : stream_(other.stream_),
357  streambuf_(other.streambuf_),
358  delim_(other.delim_),
359  start_(other.start_),
360  search_position_(other.search_position_),
361  handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
362  {
363  }
364 #endif // defined(ASIO_HAS_MOVE)
365 
366  void operator()(const asio::error_code& ec,
367  std::size_t bytes_transferred, int start = 0)
368  {
369  const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
370  std::size_t bytes_to_read;
371  switch (start_ = start)
372  {
373  case 1:
374  for (;;)
375  {
376  {
377  // Determine the range of the data to be searched.
378  typedef typename asio::basic_streambuf<
379  Allocator>::const_buffers_type const_buffers_type;
381  const_buffers_type buffers = streambuf_.data();
382  iterator begin = iterator::begin(buffers);
383  iterator start_pos = begin + search_position_;
384  iterator end = iterator::end(buffers);
385 
386  // Look for a match.
387  iterator iter = std::find(start_pos, end, delim_);
388  if (iter != end)
389  {
390  // Found a match. We're done.
391  search_position_ = iter - begin + 1;
392  bytes_to_read = 0;
393  }
394 
395  // No match yet. Check if buffer is full.
396  else if (streambuf_.size() == streambuf_.max_size())
397  {
398  search_position_ = not_found;
399  bytes_to_read = 0;
400  }
401 
402  // Need to read some more data.
403  else
404  {
405  // Next search can start with the new data.
406  search_position_ = end - begin;
407  bytes_to_read = read_size_helper(streambuf_, 65536);
408  }
409  }
410 
411  // Check if we're done.
412  if (!start && bytes_to_read == 0)
413  break;
414 
415  // Start a new asynchronous read operation to obtain more data.
416  stream_.async_read_some(streambuf_.prepare(bytes_to_read),
418  return; default:
419  streambuf_.commit(bytes_transferred);
420  if (ec || bytes_transferred == 0)
421  break;
422  }
423 
424  const asio::error_code result_ec =
425  (search_position_ == not_found)
426  ? error::not_found : ec;
427 
428  const std::size_t result_n =
429  (ec || search_position_ == not_found)
430  ? 0 : search_position_;
431 
432  handler_(result_ec, result_n);
433  }
434  }
435 
436  //private:
437  AsyncReadStream& stream_;
439  char delim_;
440  int start_;
441  std::size_t search_position_;
442  ReadHandler handler_;
443  };
444 
445  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
446  inline void* asio_handler_allocate(std::size_t size,
447  read_until_delim_op<AsyncReadStream,
448  Allocator, ReadHandler>* this_handler)
449  {
451  size, this_handler->handler_);
452  }
453 
454  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
455  inline void asio_handler_deallocate(void* pointer, std::size_t size,
456  read_until_delim_op<AsyncReadStream,
457  Allocator, ReadHandler>* this_handler)
458  {
460  pointer, size, this_handler->handler_);
461  }
462 
463  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
465  read_until_delim_op<AsyncReadStream,
466  Allocator, ReadHandler>* this_handler)
467  {
468  return this_handler->start_ == 0 ? true
470  this_handler->handler_);
471  }
472 
473  template <typename Function, typename AsyncReadStream, typename Allocator,
474  typename ReadHandler>
475  inline void asio_handler_invoke(Function& function,
476  read_until_delim_op<AsyncReadStream,
477  Allocator, ReadHandler>* this_handler)
478  {
480  function, this_handler->handler_);
481  }
482 
483  template <typename Function, typename AsyncReadStream, typename Allocator,
484  typename ReadHandler>
485  inline void asio_handler_invoke(const Function& function,
486  read_until_delim_op<AsyncReadStream,
487  Allocator, ReadHandler>* this_handler)
488  {
490  function, this_handler->handler_);
491  }
492 } // namespace detail
493 
494 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
495 ASIO_INITFN_RESULT_TYPE(ReadHandler,
496  void (asio::error_code, std::size_t))
497 async_read_until(AsyncReadStream& s,
499  ASIO_MOVE_ARG(ReadHandler) handler)
500 {
501  // If you get an error on the following line it means that your handler does
502  // not meet the documented type requirements for a ReadHandler.
503  ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
504 
506  ReadHandler, void (asio::error_code, std::size_t)> init(
507  ASIO_MOVE_CAST(ReadHandler)(handler));
508 
509  detail::read_until_delim_op<AsyncReadStream,
510  Allocator, ASIO_HANDLER_TYPE(ReadHandler,
511  void (asio::error_code, std::size_t))>(
512  s, b, delim, init.handler)(
513  asio::error_code(), 0, 1);
514 
515  return init.result.get();
516 }
517 
518 namespace detail
519 {
520  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
522  {
523  public:
524  read_until_delim_string_op(AsyncReadStream& stream,
526  const std::string& delim, ReadHandler& handler)
527  : stream_(stream),
528  streambuf_(streambuf),
529  delim_(delim),
530  start_(0),
531  search_position_(0),
532  handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
533  {
534  }
535 
536 #if defined(ASIO_HAS_MOVE)
538  : stream_(other.stream_),
539  streambuf_(other.streambuf_),
540  delim_(other.delim_),
541  start_(other.start_),
542  search_position_(other.search_position_),
543  handler_(other.handler_)
544  {
545  }
546 
548  : stream_(other.stream_),
549  streambuf_(other.streambuf_),
550  delim_(ASIO_MOVE_CAST(std::string)(other.delim_)),
551  start_(other.start_),
552  search_position_(other.search_position_),
553  handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
554  {
555  }
556 #endif // defined(ASIO_HAS_MOVE)
557 
558  void operator()(const asio::error_code& ec,
559  std::size_t bytes_transferred, int start = 0)
560  {
561  const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
562  std::size_t bytes_to_read;
563  switch (start_ = start)
564  {
565  case 1:
566  for (;;)
567  {
568  {
569  // Determine the range of the data to be searched.
570  typedef typename asio::basic_streambuf<
571  Allocator>::const_buffers_type const_buffers_type;
573  const_buffers_type buffers = streambuf_.data();
574  iterator begin = iterator::begin(buffers);
575  iterator start_pos = begin + search_position_;
576  iterator end = iterator::end(buffers);
577 
578  // Look for a match.
579  std::pair<iterator, bool> result = detail::partial_search(
580  start_pos, end, delim_.begin(), delim_.end());
581  if (result.first != end && result.second)
582  {
583  // Full match. We're done.
584  search_position_ = result.first - begin + delim_.length();
585  bytes_to_read = 0;
586  }
587 
588  // No match yet. Check if buffer is full.
589  else if (streambuf_.size() == streambuf_.max_size())
590  {
591  search_position_ = not_found;
592  bytes_to_read = 0;
593  }
594 
595  // Need to read some more data.
596  else
597  {
598  if (result.first != end)
599  {
600  // Partial match. Next search needs to start from beginning of
601  // match.
602  search_position_ = result.first - begin;
603  }
604  else
605  {
606  // Next search can start with the new data.
607  search_position_ = end - begin;
608  }
609 
610  bytes_to_read = read_size_helper(streambuf_, 65536);
611  }
612  }
613 
614  // Check if we're done.
615  if (!start && bytes_to_read == 0)
616  break;
617 
618  // Start a new asynchronous read operation to obtain more data.
619  stream_.async_read_some(streambuf_.prepare(bytes_to_read),
621  return; default:
622  streambuf_.commit(bytes_transferred);
623  if (ec || bytes_transferred == 0)
624  break;
625  }
626 
627  const asio::error_code result_ec =
628  (search_position_ == not_found)
629  ? error::not_found : ec;
630 
631  const std::size_t result_n =
632  (ec || search_position_ == not_found)
633  ? 0 : search_position_;
634 
635  handler_(result_ec, result_n);
636  }
637  }
638 
639  //private:
640  AsyncReadStream& stream_;
642  std::string delim_;
643  int start_;
644  std::size_t search_position_;
645  ReadHandler handler_;
646  };
647 
648  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
649  inline void* asio_handler_allocate(std::size_t size,
650  read_until_delim_string_op<AsyncReadStream,
651  Allocator, ReadHandler>* this_handler)
652  {
654  size, this_handler->handler_);
655  }
656 
657  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
658  inline void asio_handler_deallocate(void* pointer, std::size_t size,
659  read_until_delim_string_op<AsyncReadStream,
660  Allocator, ReadHandler>* this_handler)
661  {
663  pointer, size, this_handler->handler_);
664  }
665 
666  template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
668  read_until_delim_string_op<AsyncReadStream,
669  Allocator, ReadHandler>* this_handler)
670  {
671  return this_handler->start_ == 0 ? true
673  this_handler->handler_);
674  }
675 
676  template <typename Function, typename AsyncReadStream,
677  typename Allocator, typename ReadHandler>
678  inline void asio_handler_invoke(Function& function,
679  read_until_delim_string_op<AsyncReadStream,
680  Allocator, ReadHandler>* this_handler)
681  {
683  function, this_handler->handler_);
684  }
685 
686  template <typename Function, typename AsyncReadStream,
687  typename Allocator, typename ReadHandler>
688  inline void asio_handler_invoke(const Function& function,
689  read_until_delim_string_op<AsyncReadStream,
690  Allocator, ReadHandler>* this_handler)
691  {
693  function, this_handler->handler_);
694  }
695 } // namespace detail
696 
697 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
698 ASIO_INITFN_RESULT_TYPE(ReadHandler,
699  void (asio::error_code, std::size_t))
700 async_read_until(AsyncReadStream& s,
701  asio::basic_streambuf<Allocator>& b, const std::string& delim,
702  ASIO_MOVE_ARG(ReadHandler) handler)
703 {
704  // If you get an error on the following line it means that your handler does
705  // not meet the documented type requirements for a ReadHandler.
706  ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
707 
709  ReadHandler, void (asio::error_code, std::size_t)> init(
710  ASIO_MOVE_CAST(ReadHandler)(handler));
711 
712  detail::read_until_delim_string_op<AsyncReadStream,
713  Allocator, ASIO_HANDLER_TYPE(ReadHandler,
714  void (asio::error_code, std::size_t))>(
715  s, b, delim, init.handler)(
716  asio::error_code(), 0, 1);
717 
718  return init.result.get();
719 }
720 
721 #if defined(ASIO_HAS_BOOST_REGEX)
722 
723 namespace detail
724 {
725  template <typename AsyncReadStream, typename Allocator,
726  typename RegEx, typename ReadHandler>
727  class read_until_expr_op
728  {
729  public:
730  read_until_expr_op(AsyncReadStream& stream,
732  const boost::regex& expr, ReadHandler& handler)
733  : stream_(stream),
734  streambuf_(streambuf),
735  expr_(expr),
736  start_(0),
737  search_position_(0),
738  handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
739  {
740  }
741 
742 #if defined(ASIO_HAS_MOVE)
743  read_until_expr_op(const read_until_expr_op& other)
744  : stream_(other.stream_),
745  streambuf_(other.streambuf_),
746  expr_(other.expr_),
747  start_(other.start_),
748  search_position_(other.search_position_),
749  handler_(other.handler_)
750  {
751  }
752 
753  read_until_expr_op(read_until_expr_op&& other)
754  : stream_(other.stream_),
755  streambuf_(other.streambuf_),
756  expr_(other.expr_),
757  start_(other.start_),
758  search_position_(other.search_position_),
759  handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
760  {
761  }
762 #endif // defined(ASIO_HAS_MOVE)
763 
764  void operator()(const asio::error_code& ec,
765  std::size_t bytes_transferred, int start = 0)
766  {
767  const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
768  std::size_t bytes_to_read;
769  switch (start_ = start)
770  {
771  case 1:
772  for (;;)
773  {
774  {
775  // Determine the range of the data to be searched.
776  typedef typename asio::basic_streambuf<
777  Allocator>::const_buffers_type const_buffers_type;
779  const_buffers_type buffers = streambuf_.data();
780  iterator begin = iterator::begin(buffers);
781  iterator start_pos = begin + search_position_;
782  iterator end = iterator::end(buffers);
783 
784  // Look for a match.
785  boost::match_results<iterator,
786  typename std::vector<boost::sub_match<iterator> >::allocator_type>
787  match_results;
788  bool match = regex_search(start_pos, end, match_results, expr_,
789  boost::match_default | boost::match_partial);
790  if (match && match_results[0].matched)
791  {
792  // Full match. We're done.
793  search_position_ = match_results[0].second - begin;
794  bytes_to_read = 0;
795  }
796 
797  // No match yet. Check if buffer is full.
798  else if (streambuf_.size() == streambuf_.max_size())
799  {
800  search_position_ = not_found;
801  bytes_to_read = 0;
802  }
803 
804  // Need to read some more data.
805  else
806  {
807  if (match)
808  {
809  // Partial match. Next search needs to start from beginning of
810  // match.
811  search_position_ = match_results[0].first - begin;
812  }
813  else
814  {
815  // Next search can start with the new data.
816  search_position_ = end - begin;
817  }
818 
819  bytes_to_read = read_size_helper(streambuf_, 65536);
820  }
821  }
822 
823  // Check if we're done.
824  if (!start && bytes_to_read == 0)
825  break;
826 
827  // Start a new asynchronous read operation to obtain more data.
828  stream_.async_read_some(streambuf_.prepare(bytes_to_read),
829  ASIO_MOVE_CAST(read_until_expr_op)(*this));
830  return; default:
831  streambuf_.commit(bytes_transferred);
832  if (ec || bytes_transferred == 0)
833  break;
834  }
835 
836  const asio::error_code result_ec =
837  (search_position_ == not_found)
838  ? error::not_found : ec;
839 
840  const std::size_t result_n =
841  (ec || search_position_ == not_found)
842  ? 0 : search_position_;
843 
844  handler_(result_ec, result_n);
845  }
846  }
847 
848  //private:
849  AsyncReadStream& stream_;
851  RegEx expr_;
852  int start_;
853  std::size_t search_position_;
854  ReadHandler handler_;
855  };
856 
857  template <typename AsyncReadStream, typename Allocator,
858  typename RegEx, typename ReadHandler>
859  inline void* asio_handler_allocate(std::size_t size,
860  read_until_expr_op<AsyncReadStream,
861  Allocator, RegEx, ReadHandler>* this_handler)
862  {
864  size, this_handler->handler_);
865  }
866 
867  template <typename AsyncReadStream, typename Allocator,
868  typename RegEx, typename ReadHandler>
869  inline void asio_handler_deallocate(void* pointer, std::size_t size,
870  read_until_expr_op<AsyncReadStream,
871  Allocator, RegEx, ReadHandler>* this_handler)
872  {
874  pointer, size, this_handler->handler_);
875  }
876 
877  template <typename AsyncReadStream, typename Allocator,
878  typename RegEx, typename ReadHandler>
879  inline bool asio_handler_is_continuation(
880  read_until_expr_op<AsyncReadStream,
881  Allocator, RegEx, ReadHandler>* this_handler)
882  {
883  return this_handler->start_ == 0 ? true
885  this_handler->handler_);
886  }
887 
888  template <typename Function, typename AsyncReadStream, typename Allocator,
889  typename RegEx, typename ReadHandler>
890  inline void asio_handler_invoke(Function& function,
891  read_until_expr_op<AsyncReadStream,
892  Allocator, RegEx, ReadHandler>* this_handler)
893  {
895  function, this_handler->handler_);
896  }
897 
898  template <typename Function, typename AsyncReadStream, typename Allocator,
899  typename RegEx, typename ReadHandler>
900  inline void asio_handler_invoke(const Function& function,
901  read_until_expr_op<AsyncReadStream,
902  Allocator, RegEx, ReadHandler>* this_handler)
903  {
905  function, this_handler->handler_);
906  }
907 } // namespace detail
908 
909 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
910 ASIO_INITFN_RESULT_TYPE(ReadHandler,
911  void (asio::error_code, std::size_t))
912 async_read_until(AsyncReadStream& s,
913  asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
914  ASIO_MOVE_ARG(ReadHandler) handler)
915 {
916  // If you get an error on the following line it means that your handler does
917  // not meet the documented type requirements for a ReadHandler.
918  ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
919 
921  ReadHandler, void (asio::error_code, std::size_t)> init(
922  ASIO_MOVE_CAST(ReadHandler)(handler));
923 
924  detail::read_until_expr_op<AsyncReadStream, Allocator,
925  boost::regex, ASIO_HANDLER_TYPE(ReadHandler,
926  void (asio::error_code, std::size_t))>(
927  s, b, expr, init.handler)(
928  asio::error_code(), 0, 1);
929 
930  return init.result.get();
931 }
932 
933 #endif // defined(ASIO_HAS_BOOST_REGEX)
934 
935 namespace detail
936 {
937  template <typename AsyncReadStream, typename Allocator,
938  typename MatchCondition, typename ReadHandler>
940  {
941  public:
942  read_until_match_op(AsyncReadStream& stream,
944  MatchCondition match_condition, ReadHandler& handler)
945  : stream_(stream),
946  streambuf_(streambuf),
947  match_condition_(match_condition),
948  start_(0),
949  search_position_(0),
950  handler_(ASIO_MOVE_CAST(ReadHandler)(handler))
951  {
952  }
953 
954 #if defined(ASIO_HAS_MOVE)
956  : stream_(other.stream_),
957  streambuf_(other.streambuf_),
958  match_condition_(other.match_condition_),
959  start_(other.start_),
960  search_position_(other.search_position_),
961  handler_(other.handler_)
962  {
963  }
964 
966  : stream_(other.stream_),
967  streambuf_(other.streambuf_),
968  match_condition_(other.match_condition_),
969  start_(other.start_),
970  search_position_(other.search_position_),
971  handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))
972  {
973  }
974 #endif // defined(ASIO_HAS_MOVE)
975 
976  void operator()(const asio::error_code& ec,
977  std::size_t bytes_transferred, int start = 0)
978  {
979  const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
980  std::size_t bytes_to_read;
981  switch (start_ = start)
982  {
983  case 1:
984  for (;;)
985  {
986  {
987  // Determine the range of the data to be searched.
988  typedef typename asio::basic_streambuf<
989  Allocator>::const_buffers_type const_buffers_type;
991  const_buffers_type buffers = streambuf_.data();
992  iterator begin = iterator::begin(buffers);
993  iterator start_pos = begin + search_position_;
994  iterator end = iterator::end(buffers);
995 
996  // Look for a match.
997  std::pair<iterator, bool> result = match_condition_(start_pos, end);
998  if (result.second)
999  {
1000  // Full match. We're done.
1001  search_position_ = result.first - begin;
1002  bytes_to_read = 0;
1003  }
1004 
1005  // No match yet. Check if buffer is full.
1006  else if (streambuf_.size() == streambuf_.max_size())
1007  {
1008  search_position_ = not_found;
1009  bytes_to_read = 0;
1010  }
1011 
1012  // Need to read some more data.
1013  else
1014  {
1015  if (result.first != end)
1016  {
1017  // Partial match. Next search needs to start from beginning of
1018  // match.
1019  search_position_ = result.first - begin;
1020  }
1021  else
1022  {
1023  // Next search can start with the new data.
1024  search_position_ = end - begin;
1025  }
1026 
1027  bytes_to_read = read_size_helper(streambuf_, 65536);
1028  }
1029  }
1030 
1031  // Check if we're done.
1032  if (!start && bytes_to_read == 0)
1033  break;
1034 
1035  // Start a new asynchronous read operation to obtain more data.
1036  stream_.async_read_some(streambuf_.prepare(bytes_to_read),
1038  return; default:
1039  streambuf_.commit(bytes_transferred);
1040  if (ec || bytes_transferred == 0)
1041  break;
1042  }
1043 
1044  const asio::error_code result_ec =
1045  (search_position_ == not_found)
1046  ? error::not_found : ec;
1047 
1048  const std::size_t result_n =
1049  (ec || search_position_ == not_found)
1050  ? 0 : search_position_;
1051 
1052  handler_(result_ec, result_n);
1053  }
1054  }
1055 
1056  //private:
1057  AsyncReadStream& stream_;
1059  MatchCondition match_condition_;
1060  int start_;
1061  std::size_t search_position_;
1062  ReadHandler handler_;
1063  };
1064 
1065  template <typename AsyncReadStream, typename Allocator,
1066  typename MatchCondition, typename ReadHandler>
1067  inline void* asio_handler_allocate(std::size_t size,
1068  read_until_match_op<AsyncReadStream,
1069  Allocator, MatchCondition, ReadHandler>* this_handler)
1070  {
1072  size, this_handler->handler_);
1073  }
1074 
1075  template <typename AsyncReadStream, typename Allocator,
1076  typename MatchCondition, typename ReadHandler>
1077  inline void asio_handler_deallocate(void* pointer, std::size_t size,
1078  read_until_match_op<AsyncReadStream,
1079  Allocator, MatchCondition, ReadHandler>* this_handler)
1080  {
1082  pointer, size, this_handler->handler_);
1083  }
1084 
1085  template <typename AsyncReadStream, typename Allocator,
1086  typename MatchCondition, typename ReadHandler>
1088  read_until_match_op<AsyncReadStream,
1089  Allocator, MatchCondition, ReadHandler>* this_handler)
1090  {
1091  return this_handler->start_ == 0 ? true
1093  this_handler->handler_);
1094  }
1095 
1096  template <typename Function, typename AsyncReadStream, typename Allocator,
1097  typename MatchCondition, typename ReadHandler>
1098  inline void asio_handler_invoke(Function& function,
1099  read_until_match_op<AsyncReadStream,
1100  Allocator, MatchCondition, ReadHandler>* this_handler)
1101  {
1103  function, this_handler->handler_);
1104  }
1105 
1106  template <typename Function, typename AsyncReadStream, typename Allocator,
1107  typename MatchCondition, typename ReadHandler>
1108  inline void asio_handler_invoke(const Function& function,
1109  read_until_match_op<AsyncReadStream,
1110  Allocator, MatchCondition, ReadHandler>* this_handler)
1111  {
1113  function, this_handler->handler_);
1114  }
1115 } // namespace detail
1116 
1117 template <typename AsyncReadStream, typename Allocator,
1118  typename MatchCondition, typename ReadHandler>
1119 ASIO_INITFN_RESULT_TYPE(ReadHandler,
1120  void (asio::error_code, std::size_t))
1121 async_read_until(AsyncReadStream& s,
1123  MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler,
1125 {
1126  // If you get an error on the following line it means that your handler does
1127  // not meet the documented type requirements for a ReadHandler.
1128  ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1129 
1131  ReadHandler, void (asio::error_code, std::size_t)> init(
1132  ASIO_MOVE_CAST(ReadHandler)(handler));
1133 
1134  detail::read_until_match_op<AsyncReadStream, Allocator,
1135  MatchCondition, ASIO_HANDLER_TYPE(ReadHandler,
1136  void (asio::error_code, std::size_t))>(
1137  s, b, match_condition, init.handler)(
1138  asio::error_code(), 0, 1);
1139 
1140  return init.result.get();
1141 }
1142 
1143 } // namespace asio
1144 
1145 #include "asio/detail/pop_options.hpp"
1146 
1147 #endif // ASIO_IMPL_READ_UNTIL_HPP
void asio_handler_deallocate(void *pointer, std::size_t size, binder1< Handler, Arg1 > *this_handler)
asio::basic_streambuf< Allocator > & streambuf_
void throw_error(const asio::error_code &err)
Definition: throw_error.hpp:31
SocketService & s
Definition: connect.hpp:521
SocketService Iterator begin
Definition: connect.hpp:521
void * asio_handler_allocate(std::size_t size, binder1< Handler, Arg1 > *this_handler)
std::size_t max_size() const
Get the maximum size of the basic_streambuf.
read_until_match_op(AsyncReadStream &stream, asio::basic_streambuf< Allocator > &streambuf, MatchCondition match_condition, ReadHandler &handler)
Definition: read_until.hpp:942
asio::basic_streambuf< Allocator > MatchCondition enable_if< is_match_condition< MatchCondition >::value >::type *detail::async_result_init< ReadHandler, void(asio::error_code, std::size_t)> init(ASIO_MOVE_CAST(ReadHandler)(handler))
void operator()(const asio::error_code &ec, std::size_t bytes_transferred, int start=0)
Definition: read_until.hpp:558
#define ASIO_HANDLER_TYPE(h, sig)
mutable_buffers_type prepare(std::size_t n)
A random access iterator over the bytes in a buffer sequence.
asio::basic_streambuf< Allocator > & b
Definition: read.hpp:702
ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, void(asio::error_code, Iterator)) async_connect(basic_socket< Protocol
void invoke(Function &function, Context &context)
asio::basic_streambuf< Allocator > & streambuf_
Definition: read_until.hpp:641
void operator()(const asio::error_code &ec, std::size_t bytes_transferred, int start=0)
Definition: read_until.hpp:366
const MutableBufferSequence & buffers
Definition: read.hpp:521
void commit(std::size_t n)
Move characters from the output sequence to the input sequence.
std::size_t read_until(SyncReadStream &s, asio::basic_streambuf< Allocator > &b, char delim)
Read data into a streambuf until it contains a specified delimiter.
Definition: read_until.hpp:37
#define ASIO_READ_HANDLER_CHECK(handler_type, handler)
Element not found.
Definition: error.hpp:220
void operator()(const asio::error_code &ec, std::size_t bytes_transferred, int start=0)
Definition: read_until.hpp:976
std::size_t size() const
Get the size of the input sequence.
void asio_handler_invoke(Function &function, binder1< Handler, Arg1 > *this_handler)
asio::basic_streambuf< Allocator > CompletionCondition ASIO_MOVE_ARG(ReadHandler) handler)
Definition: read.hpp:704
bool is_continuation(Context &context)
read_until_delim_op(AsyncReadStream &stream, asio::basic_streambuf< Allocator > &streambuf, char delim, ReadHandler &handler)
Definition: read_until.hpp:332
Class to represent an error code value.
Definition: error_code.hpp:80
asio::basic_streambuf< Allocator > & streambuf_
Definition: read_until.hpp:438
void deallocate(void *p, std::size_t s, Handler &h)
asio::basic_streambuf< Allocator > MatchCondition match_condition
std::size_t read_size_helper(basic_streambuf< Allocator > &sb, std::size_t max_size)
read_until_delim_string_op(AsyncReadStream &stream, asio::basic_streambuf< Allocator > &streambuf, const std::string &delim, ReadHandler &handler)
Definition: read_until.hpp:524
std::pair< Iterator1, bool > partial_search(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
Definition: read_until.hpp:111
Automatically resizable buffer class based on std::streambuf.
void * allocate(std::size_t s, Handler &h)
handler_type< Handler, Signature >::type handler
SocketService Iterator Iterator end
Definition: connect.hpp:592
#define ASIO_MOVE_CAST(type)
Definition: config.hpp:138
async_result< typename handler_type< Handler, Signature >::type > result
asio::basic_streambuf< Allocator > char delim
Definition: read_until.hpp:498
const_buffers_type data() const
Get a list of buffers that represents the input sequence.
bool asio_handler_is_continuation(binder1< Handler, Arg1 > *this_handler)