5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
12 #define BOOST_ASIO_IMPL_READ_UNTIL_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
22 #include <boost/asio/associated_allocator.hpp>
23 #include <boost/asio/associated_executor.hpp>
24 #include <boost/asio/buffer.hpp>
25 #include <boost/asio/buffers_iterator.hpp>
26 #include <boost/asio/detail/bind_handler.hpp>
27 #include <boost/asio/detail/handler_alloc_helpers.hpp>
28 #include <boost/asio/detail/handler_cont_helpers.hpp>
29 #include <boost/asio/detail/handler_invoke_helpers.hpp>
30 #include <boost/asio/detail/handler_type_requirements.hpp>
31 #include <boost/asio/detail/limits.hpp>
32 #include <boost/asio/detail/throw_error.hpp>
34 #include <boost/asio/detail/push_options.hpp>
39 template <typename SyncReadStream, typename DynamicBuffer>
40 inline std::size_t read_until(SyncReadStream& s,
41 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim)
43 boost::system::error_code ec;
44 std::size_t bytes_transferred = read_until(s,
45 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec);
46 boost::asio::detail::throw_error(ec, "read_until");
47 return bytes_transferred;
50 template <typename SyncReadStream, typename DynamicBuffer>
51 std::size_t read_until(SyncReadStream& s,
52 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
53 char delim, boost::system::error_code& ec)
55 typename decay<DynamicBuffer>::type b(
56 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
58 std::size_t search_position = 0;
61 // Determine the range of the data to be searched.
62 typedef typename DynamicBuffer::const_buffers_type buffers_type;
63 typedef buffers_iterator<buffers_type> iterator;
64 buffers_type data_buffers = b.data();
65 iterator begin = iterator::begin(data_buffers);
66 iterator start_pos = begin + search_position;
67 iterator end = iterator::end(data_buffers);
70 iterator iter = std::find(start_pos, end, delim);
73 // Found a match. We're done.
74 ec = boost::system::error_code();
75 return iter - begin + 1;
79 // No match. Next search can start with the new data.
80 search_position = end - begin;
83 // Check if buffer is full.
84 if (b.size() == b.max_size())
86 ec = error::not_found;
91 std::size_t bytes_to_read = std::min<std::size_t>(
92 std::max<std::size_t>(512, b.capacity() - b.size()),
93 std::min<std::size_t>(65536, b.max_size() - b.size()));
94 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
100 template <typename SyncReadStream, typename DynamicBuffer>
101 inline std::size_t read_until(SyncReadStream& s,
102 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
103 BOOST_ASIO_STRING_VIEW_PARAM delim)
105 boost::system::error_code ec;
106 std::size_t bytes_transferred = read_until(s,
107 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec);
108 boost::asio::detail::throw_error(ec, "read_until");
109 return bytes_transferred;
114 // Algorithm that finds a subsequence of equal values in a sequence. Returns
115 // (iterator,true) if a full match was found, in which case the iterator
116 // points to the beginning of the match. Returns (iterator,false) if a
117 // partial match was found at the end of the first sequence, in which case
118 // the iterator points to the beginning of the partial match. Returns
119 // (last1,false) if no full or partial match was found.
120 template <typename Iterator1, typename Iterator2>
121 std::pair<Iterator1, bool> partial_search(
122 Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
124 for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
126 Iterator1 test_iter1 = iter1;
127 Iterator2 test_iter2 = first2;
128 for (;; ++test_iter1, ++test_iter2)
130 if (test_iter2 == last2)
131 return std::make_pair(iter1, true);
132 if (test_iter1 == last1)
134 if (test_iter2 != first2)
135 return std::make_pair(iter1, false);
139 if (*test_iter1 != *test_iter2)
143 return std::make_pair(last1, false);
145 } // namespace detail
147 template <typename SyncReadStream, typename DynamicBuffer>
148 std::size_t read_until(SyncReadStream& s,
149 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
150 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec)
152 typename decay<DynamicBuffer>::type b(
153 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
155 std::size_t search_position = 0;
158 // Determine the range of the data to be searched.
159 typedef typename DynamicBuffer::const_buffers_type buffers_type;
160 typedef buffers_iterator<buffers_type> iterator;
161 buffers_type data_buffers = b.data();
162 iterator begin = iterator::begin(data_buffers);
163 iterator start_pos = begin + search_position;
164 iterator end = iterator::end(data_buffers);
167 std::pair<iterator, bool> result = detail::partial_search(
168 start_pos, end, delim.begin(), delim.end());
169 if (result.first != end)
173 // Full match. We're done.
174 ec = boost::system::error_code();
175 return result.first - begin + delim.length();
179 // Partial match. Next search needs to start from beginning of match.
180 search_position = result.first - begin;
185 // No match. Next search can start with the new data.
186 search_position = end - begin;
189 // Check if buffer is full.
190 if (b.size() == b.max_size())
192 ec = error::not_found;
197 std::size_t bytes_to_read = std::min<std::size_t>(
198 std::max<std::size_t>(512, b.capacity() - b.size()),
199 std::min<std::size_t>(65536, b.max_size() - b.size()));
200 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
206 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
207 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
209 template <typename SyncReadStream, typename DynamicBuffer>
210 inline std::size_t read_until(SyncReadStream& s,
211 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
212 const boost::regex& expr)
214 boost::system::error_code ec;
215 std::size_t bytes_transferred = read_until(s,
216 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), expr, ec);
217 boost::asio::detail::throw_error(ec, "read_until");
218 return bytes_transferred;
221 template <typename SyncReadStream, typename DynamicBuffer>
222 std::size_t read_until(SyncReadStream& s,
223 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
224 const boost::regex& expr, boost::system::error_code& ec)
226 typename decay<DynamicBuffer>::type b(
227 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
229 std::size_t search_position = 0;
232 // Determine the range of the data to be searched.
233 typedef typename DynamicBuffer::const_buffers_type buffers_type;
234 typedef buffers_iterator<buffers_type> iterator;
235 buffers_type data_buffers = b.data();
236 iterator begin = iterator::begin(data_buffers);
237 iterator start_pos = begin + search_position;
238 iterator end = iterator::end(data_buffers);
241 boost::match_results<iterator,
242 typename std::vector<boost::sub_match<iterator> >::allocator_type>
244 if (regex_search(start_pos, end, match_results, expr,
245 boost::match_default | boost::match_partial))
247 if (match_results[0].matched)
249 // Full match. We're done.
250 ec = boost::system::error_code();
251 return match_results[0].second - begin;
255 // Partial match. Next search needs to start from beginning of match.
256 search_position = match_results[0].first - begin;
261 // No match. Next search can start with the new data.
262 search_position = end - begin;
265 // Check if buffer is full.
266 if (b.size() == b.max_size())
268 ec = error::not_found;
273 std::size_t bytes_to_read = read_size_helper(b, 65536);
274 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
280 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
282 template <typename SyncReadStream,
283 typename DynamicBuffer, typename MatchCondition>
284 inline std::size_t read_until(SyncReadStream& s,
285 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
286 MatchCondition match_condition,
287 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
289 boost::system::error_code ec;
290 std::size_t bytes_transferred = read_until(s,
291 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
292 match_condition, ec);
293 boost::asio::detail::throw_error(ec, "read_until");
294 return bytes_transferred;
297 template <typename SyncReadStream,
298 typename DynamicBuffer, typename MatchCondition>
299 std::size_t read_until(SyncReadStream& s,
300 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
301 MatchCondition match_condition, boost::system::error_code& ec,
302 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
304 typename decay<DynamicBuffer>::type b(
305 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
307 std::size_t search_position = 0;
310 // Determine the range of the data to be searched.
311 typedef typename DynamicBuffer::const_buffers_type buffers_type;
312 typedef buffers_iterator<buffers_type> iterator;
313 buffers_type data_buffers = b.data();
314 iterator begin = iterator::begin(data_buffers);
315 iterator start_pos = begin + search_position;
316 iterator end = iterator::end(data_buffers);
319 std::pair<iterator, bool> result = match_condition(start_pos, end);
322 // Full match. We're done.
323 ec = boost::system::error_code();
324 return result.first - begin;
326 else if (result.first != end)
328 // Partial match. Next search needs to start from beginning of match.
329 search_position = result.first - begin;
333 // No match. Next search can start with the new data.
334 search_position = end - begin;
337 // Check if buffer is full.
338 if (b.size() == b.max_size())
340 ec = error::not_found;
345 std::size_t bytes_to_read = std::min<std::size_t>(
346 std::max<std::size_t>(512, b.capacity() - b.size()),
347 std::min<std::size_t>(65536, b.max_size() - b.size()));
348 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
354 #if !defined(BOOST_ASIO_NO_IOSTREAM)
356 template <typename SyncReadStream, typename Allocator>
357 inline std::size_t read_until(SyncReadStream& s,
358 boost::asio::basic_streambuf<Allocator>& b, char delim)
360 return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
363 template <typename SyncReadStream, typename Allocator>
364 inline std::size_t read_until(SyncReadStream& s,
365 boost::asio::basic_streambuf<Allocator>& b, char delim,
366 boost::system::error_code& ec)
368 return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
371 template <typename SyncReadStream, typename Allocator>
372 inline std::size_t read_until(SyncReadStream& s,
373 boost::asio::basic_streambuf<Allocator>& b,
374 BOOST_ASIO_STRING_VIEW_PARAM delim)
376 return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
379 template <typename SyncReadStream, typename Allocator>
380 inline std::size_t read_until(SyncReadStream& s,
381 boost::asio::basic_streambuf<Allocator>& b,
382 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec)
384 return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
387 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
389 template <typename SyncReadStream, typename Allocator>
390 inline std::size_t read_until(SyncReadStream& s,
391 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
393 return read_until(s, basic_streambuf_ref<Allocator>(b), expr);
396 template <typename SyncReadStream, typename Allocator>
397 inline std::size_t read_until(SyncReadStream& s,
398 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
399 boost::system::error_code& ec)
401 return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec);
404 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
406 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
407 inline std::size_t read_until(SyncReadStream& s,
408 boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
409 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
411 return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition);
414 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
415 inline std::size_t read_until(SyncReadStream& s,
416 boost::asio::basic_streambuf<Allocator>& b,
417 MatchCondition match_condition, boost::system::error_code& ec,
418 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
420 return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec);
423 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
424 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
428 template <typename AsyncReadStream,
429 typename DynamicBuffer, typename ReadHandler>
430 class read_until_delim_op
433 template <typename BufferSequence>
434 read_until_delim_op(AsyncReadStream& stream,
435 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
436 char delim, ReadHandler& handler)
438 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
442 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
446 #if defined(BOOST_ASIO_HAS_MOVE)
447 read_until_delim_op(const read_until_delim_op& other)
448 : stream_(other.stream_),
449 buffers_(other.buffers_),
450 delim_(other.delim_),
451 start_(other.start_),
452 search_position_(other.search_position_),
453 handler_(other.handler_)
457 read_until_delim_op(read_until_delim_op&& other)
458 : stream_(other.stream_),
459 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
460 delim_(other.delim_),
461 start_(other.start_),
462 search_position_(other.search_position_),
463 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
466 #endif // defined(BOOST_ASIO_HAS_MOVE)
468 void operator()(const boost::system::error_code& ec,
469 std::size_t bytes_transferred, int start = 0)
471 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
472 std::size_t bytes_to_read;
473 switch (start_ = start)
479 // Determine the range of the data to be searched.
480 typedef typename DynamicBuffer::const_buffers_type
482 typedef buffers_iterator<buffers_type> iterator;
483 buffers_type data_buffers = buffers_.data();
484 iterator begin = iterator::begin(data_buffers);
485 iterator start_pos = begin + search_position_;
486 iterator end = iterator::end(data_buffers);
489 iterator iter = std::find(start_pos, end, delim_);
492 // Found a match. We're done.
493 search_position_ = iter - begin + 1;
497 // No match yet. Check if buffer is full.
498 else if (buffers_.size() == buffers_.max_size())
500 search_position_ = not_found;
504 // Need to read some more data.
507 // Next search can start with the new data.
508 search_position_ = end - begin;
509 bytes_to_read = std::min<std::size_t>(
510 std::max<std::size_t>(512,
511 buffers_.capacity() - buffers_.size()),
512 std::min<std::size_t>(65536,
513 buffers_.max_size() - buffers_.size()));
517 // Check if we're done.
518 if (!start && bytes_to_read == 0)
521 // Start a new asynchronous read operation to obtain more data.
522 stream_.async_read_some(buffers_.prepare(bytes_to_read),
523 BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this));
525 buffers_.commit(bytes_transferred);
526 if (ec || bytes_transferred == 0)
530 const boost::system::error_code result_ec =
531 (search_position_ == not_found)
532 ? error::not_found : ec;
534 const std::size_t result_n =
535 (ec || search_position_ == not_found)
536 ? 0 : search_position_;
538 handler_(result_ec, result_n);
543 AsyncReadStream& stream_;
544 DynamicBuffer buffers_;
547 std::size_t search_position_;
548 ReadHandler handler_;
551 template <typename AsyncReadStream,
552 typename DynamicBuffer, typename ReadHandler>
553 inline void* asio_handler_allocate(std::size_t size,
554 read_until_delim_op<AsyncReadStream,
555 DynamicBuffer, ReadHandler>* this_handler)
557 return boost_asio_handler_alloc_helpers::allocate(
558 size, this_handler->handler_);
561 template <typename AsyncReadStream,
562 typename DynamicBuffer, typename ReadHandler>
563 inline void asio_handler_deallocate(void* pointer, std::size_t size,
564 read_until_delim_op<AsyncReadStream,
565 DynamicBuffer, ReadHandler>* this_handler)
567 boost_asio_handler_alloc_helpers::deallocate(
568 pointer, size, this_handler->handler_);
571 template <typename AsyncReadStream,
572 typename DynamicBuffer, typename ReadHandler>
573 inline bool asio_handler_is_continuation(
574 read_until_delim_op<AsyncReadStream,
575 DynamicBuffer, ReadHandler>* this_handler)
577 return this_handler->start_ == 0 ? true
578 : boost_asio_handler_cont_helpers::is_continuation(
579 this_handler->handler_);
582 template <typename Function, typename AsyncReadStream,
583 typename DynamicBuffer, typename ReadHandler>
584 inline void asio_handler_invoke(Function& function,
585 read_until_delim_op<AsyncReadStream,
586 DynamicBuffer, ReadHandler>* this_handler)
588 boost_asio_handler_invoke_helpers::invoke(
589 function, this_handler->handler_);
592 template <typename Function, typename AsyncReadStream,
593 typename DynamicBuffer, typename ReadHandler>
594 inline void asio_handler_invoke(const Function& function,
595 read_until_delim_op<AsyncReadStream,
596 DynamicBuffer, ReadHandler>* this_handler)
598 boost_asio_handler_invoke_helpers::invoke(
599 function, this_handler->handler_);
601 } // namespace detail
603 #if !defined(GENERATING_DOCUMENTATION)
605 template <typename AsyncReadStream, typename DynamicBuffer,
606 typename ReadHandler, typename Allocator>
607 struct associated_allocator<
608 detail::read_until_delim_op<AsyncReadStream,
609 DynamicBuffer, ReadHandler>,
612 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
615 const detail::read_until_delim_op<AsyncReadStream,
616 DynamicBuffer, ReadHandler>& h,
617 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
619 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
623 template <typename AsyncReadStream, typename DynamicBuffer,
624 typename ReadHandler, typename Executor>
625 struct associated_executor<
626 detail::read_until_delim_op<AsyncReadStream,
627 DynamicBuffer, ReadHandler>,
630 typedef typename associated_executor<ReadHandler, Executor>::type type;
633 const detail::read_until_delim_op<AsyncReadStream,
634 DynamicBuffer, ReadHandler>& h,
635 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
637 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
641 #endif // !defined(GENERATING_DOCUMENTATION)
643 template <typename AsyncReadStream,
644 typename DynamicBuffer, typename ReadHandler>
645 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
646 void (boost::system::error_code, std::size_t))
647 async_read_until(AsyncReadStream& s,
648 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
649 char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
651 // If you get an error on the following line it means that your handler does
652 // not meet the documented type requirements for a ReadHandler.
653 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
655 async_completion<ReadHandler,
656 void (boost::system::error_code, std::size_t)> init(handler);
658 detail::read_until_delim_op<AsyncReadStream,
659 typename decay<DynamicBuffer>::type,
660 BOOST_ASIO_HANDLER_TYPE(ReadHandler,
661 void (boost::system::error_code, std::size_t))>(
662 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
663 delim, init.completion_handler)(boost::system::error_code(), 0, 1);
665 return init.result.get();
670 template <typename AsyncReadStream,
671 typename DynamicBuffer, typename ReadHandler>
672 class read_until_delim_string_op
675 template <typename BufferSequence>
676 read_until_delim_string_op(AsyncReadStream& stream,
677 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
678 const std::string& delim, ReadHandler& handler)
680 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
684 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
688 #if defined(BOOST_ASIO_HAS_MOVE)
689 read_until_delim_string_op(const read_until_delim_string_op& other)
690 : stream_(other.stream_),
691 buffers_(other.buffers_),
692 delim_(other.delim_),
693 start_(other.start_),
694 search_position_(other.search_position_),
695 handler_(other.handler_)
699 read_until_delim_string_op(read_until_delim_string_op&& other)
700 : stream_(other.stream_),
701 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
702 delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
703 start_(other.start_),
704 search_position_(other.search_position_),
705 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
708 #endif // defined(BOOST_ASIO_HAS_MOVE)
710 void operator()(const boost::system::error_code& ec,
711 std::size_t bytes_transferred, int start = 0)
713 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
714 std::size_t bytes_to_read;
715 switch (start_ = start)
721 // Determine the range of the data to be searched.
722 typedef typename DynamicBuffer::const_buffers_type
724 typedef buffers_iterator<buffers_type> iterator;
725 buffers_type data_buffers = buffers_.data();
726 iterator begin = iterator::begin(data_buffers);
727 iterator start_pos = begin + search_position_;
728 iterator end = iterator::end(data_buffers);
731 std::pair<iterator, bool> result = detail::partial_search(
732 start_pos, end, delim_.begin(), delim_.end());
733 if (result.first != end && result.second)
735 // Full match. We're done.
736 search_position_ = result.first - begin + delim_.length();
740 // No match yet. Check if buffer is full.
741 else if (buffers_.size() == buffers_.max_size())
743 search_position_ = not_found;
747 // Need to read some more data.
750 if (result.first != end)
752 // Partial match. Next search needs to start from beginning of
754 search_position_ = result.first - begin;
758 // Next search can start with the new data.
759 search_position_ = end - begin;
762 bytes_to_read = std::min<std::size_t>(
763 std::max<std::size_t>(512,
764 buffers_.capacity() - buffers_.size()),
765 std::min<std::size_t>(65536,
766 buffers_.max_size() - buffers_.size()));
770 // Check if we're done.
771 if (!start && bytes_to_read == 0)
774 // Start a new asynchronous read operation to obtain more data.
775 stream_.async_read_some(buffers_.prepare(bytes_to_read),
776 BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this));
778 buffers_.commit(bytes_transferred);
779 if (ec || bytes_transferred == 0)
783 const boost::system::error_code result_ec =
784 (search_position_ == not_found)
785 ? error::not_found : ec;
787 const std::size_t result_n =
788 (ec || search_position_ == not_found)
789 ? 0 : search_position_;
791 handler_(result_ec, result_n);
796 AsyncReadStream& stream_;
797 DynamicBuffer buffers_;
800 std::size_t search_position_;
801 ReadHandler handler_;
804 template <typename AsyncReadStream,
805 typename DynamicBuffer, typename ReadHandler>
806 inline void* asio_handler_allocate(std::size_t size,
807 read_until_delim_string_op<AsyncReadStream,
808 DynamicBuffer, ReadHandler>* this_handler)
810 return boost_asio_handler_alloc_helpers::allocate(
811 size, this_handler->handler_);
814 template <typename AsyncReadStream,
815 typename DynamicBuffer, typename ReadHandler>
816 inline void asio_handler_deallocate(void* pointer, std::size_t size,
817 read_until_delim_string_op<AsyncReadStream,
818 DynamicBuffer, ReadHandler>* this_handler)
820 boost_asio_handler_alloc_helpers::deallocate(
821 pointer, size, this_handler->handler_);
824 template <typename AsyncReadStream,
825 typename DynamicBuffer, typename ReadHandler>
826 inline bool asio_handler_is_continuation(
827 read_until_delim_string_op<AsyncReadStream,
828 DynamicBuffer, ReadHandler>* this_handler)
830 return this_handler->start_ == 0 ? true
831 : boost_asio_handler_cont_helpers::is_continuation(
832 this_handler->handler_);
835 template <typename Function, typename AsyncReadStream,
836 typename DynamicBuffer, typename ReadHandler>
837 inline void asio_handler_invoke(Function& function,
838 read_until_delim_string_op<AsyncReadStream,
839 DynamicBuffer, ReadHandler>* this_handler)
841 boost_asio_handler_invoke_helpers::invoke(
842 function, this_handler->handler_);
845 template <typename Function, typename AsyncReadStream,
846 typename DynamicBuffer, typename ReadHandler>
847 inline void asio_handler_invoke(const Function& function,
848 read_until_delim_string_op<AsyncReadStream,
849 DynamicBuffer, ReadHandler>* this_handler)
851 boost_asio_handler_invoke_helpers::invoke(
852 function, this_handler->handler_);
854 } // namespace detail
856 #if !defined(GENERATING_DOCUMENTATION)
858 template <typename AsyncReadStream, typename DynamicBuffer,
859 typename ReadHandler, typename Allocator>
860 struct associated_allocator<
861 detail::read_until_delim_string_op<AsyncReadStream,
862 DynamicBuffer, ReadHandler>,
865 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
868 const detail::read_until_delim_string_op<AsyncReadStream,
869 DynamicBuffer, ReadHandler>& h,
870 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
872 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
876 template <typename AsyncReadStream, typename DynamicBuffer,
877 typename ReadHandler, typename Executor>
878 struct associated_executor<
879 detail::read_until_delim_string_op<AsyncReadStream,
880 DynamicBuffer, ReadHandler>,
883 typedef typename associated_executor<ReadHandler, Executor>::type type;
886 const detail::read_until_delim_string_op<AsyncReadStream,
887 DynamicBuffer, ReadHandler>& h,
888 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
890 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
894 #endif // !defined(GENERATING_DOCUMENTATION)
896 template <typename AsyncReadStream,
897 typename DynamicBuffer, typename ReadHandler>
898 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
899 void (boost::system::error_code, std::size_t))
900 async_read_until(AsyncReadStream& s,
901 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
902 BOOST_ASIO_STRING_VIEW_PARAM delim,
903 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
905 // If you get an error on the following line it means that your handler does
906 // not meet the documented type requirements for a ReadHandler.
907 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
909 async_completion<ReadHandler,
910 void (boost::system::error_code, std::size_t)> init(handler);
912 detail::read_until_delim_string_op<AsyncReadStream,
913 typename decay<DynamicBuffer>::type,
914 BOOST_ASIO_HANDLER_TYPE(ReadHandler,
915 void (boost::system::error_code, std::size_t))>(
916 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
917 static_cast<std::string>(delim),
918 init.completion_handler)(boost::system::error_code(), 0, 1);
920 return init.result.get();
923 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
924 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
928 template <typename AsyncReadStream, typename DynamicBuffer,
929 typename RegEx, typename ReadHandler>
930 class read_until_expr_op
933 template <typename BufferSequence>
934 read_until_expr_op(AsyncReadStream& stream,
935 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
936 const boost::regex& expr, ReadHandler& handler)
938 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
942 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
946 #if defined(BOOST_ASIO_HAS_MOVE)
947 read_until_expr_op(const read_until_expr_op& other)
948 : stream_(other.stream_),
949 buffers_(other.buffers_),
951 start_(other.start_),
952 search_position_(other.search_position_),
953 handler_(other.handler_)
957 read_until_expr_op(read_until_expr_op&& other)
958 : stream_(other.stream_),
959 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
961 start_(other.start_),
962 search_position_(other.search_position_),
963 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
966 #endif // defined(BOOST_ASIO_HAS_MOVE)
968 void operator()(const boost::system::error_code& ec,
969 std::size_t bytes_transferred, int start = 0)
971 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
972 std::size_t bytes_to_read;
973 switch (start_ = start)
979 // Determine the range of the data to be searched.
980 typedef typename DynamicBuffer::const_buffers_type
982 typedef buffers_iterator<buffers_type> iterator;
983 buffers_type data_buffers = buffers_.data();
984 iterator begin = iterator::begin(data_buffers);
985 iterator start_pos = begin + search_position_;
986 iterator end = iterator::end(data_buffers);
989 boost::match_results<iterator,
990 typename std::vector<boost::sub_match<iterator> >::allocator_type>
992 bool match = regex_search(start_pos, end, match_results, expr_,
993 boost::match_default | boost::match_partial);
994 if (match && match_results[0].matched)
996 // Full match. We're done.
997 search_position_ = match_results[0].second - begin;
1001 // No match yet. Check if buffer is full.
1002 else if (buffers_.size() == buffers_.max_size())
1004 search_position_ = not_found;
1008 // Need to read some more data.
1013 // Partial match. Next search needs to start from beginning of
1015 search_position_ = match_results[0].first - begin;
1019 // Next search can start with the new data.
1020 search_position_ = end - begin;
1023 bytes_to_read = std::min<std::size_t>(
1024 std::max<std::size_t>(512,
1025 buffers_.capacity() - buffers_.size()),
1026 std::min<std::size_t>(65536,
1027 buffers_.max_size() - buffers_.size()));
1031 // Check if we're done.
1032 if (!start && bytes_to_read == 0)
1035 // Start a new asynchronous read operation to obtain more data.
1036 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1037 BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this));
1039 buffers_.commit(bytes_transferred);
1040 if (ec || bytes_transferred == 0)
1044 const boost::system::error_code result_ec =
1045 (search_position_ == not_found)
1046 ? error::not_found : ec;
1048 const std::size_t result_n =
1049 (ec || search_position_ == not_found)
1050 ? 0 : search_position_;
1052 handler_(result_ec, result_n);
1057 AsyncReadStream& stream_;
1058 DynamicBuffer buffers_;
1061 std::size_t search_position_;
1062 ReadHandler handler_;
1065 template <typename AsyncReadStream, typename DynamicBuffer,
1066 typename RegEx, typename ReadHandler>
1067 inline void* asio_handler_allocate(std::size_t size,
1068 read_until_expr_op<AsyncReadStream,
1069 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1071 return boost_asio_handler_alloc_helpers::allocate(
1072 size, this_handler->handler_);
1075 template <typename AsyncReadStream, typename DynamicBuffer,
1076 typename RegEx, typename ReadHandler>
1077 inline void asio_handler_deallocate(void* pointer, std::size_t size,
1078 read_until_expr_op<AsyncReadStream,
1079 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1081 boost_asio_handler_alloc_helpers::deallocate(
1082 pointer, size, this_handler->handler_);
1085 template <typename AsyncReadStream, typename DynamicBuffer,
1086 typename RegEx, typename ReadHandler>
1087 inline bool asio_handler_is_continuation(
1088 read_until_expr_op<AsyncReadStream,
1089 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1091 return this_handler->start_ == 0 ? true
1092 : boost_asio_handler_cont_helpers::is_continuation(
1093 this_handler->handler_);
1096 template <typename Function, typename AsyncReadStream,
1097 typename DynamicBuffer, typename RegEx, typename ReadHandler>
1098 inline void asio_handler_invoke(Function& function,
1099 read_until_expr_op<AsyncReadStream,
1100 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1102 boost_asio_handler_invoke_helpers::invoke(
1103 function, this_handler->handler_);
1106 template <typename Function, typename AsyncReadStream,
1107 typename DynamicBuffer, typename RegEx, typename ReadHandler>
1108 inline void asio_handler_invoke(const Function& function,
1109 read_until_expr_op<AsyncReadStream,
1110 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1112 boost_asio_handler_invoke_helpers::invoke(
1113 function, this_handler->handler_);
1115 } // namespace detail
1117 #if !defined(GENERATING_DOCUMENTATION)
1119 template <typename AsyncReadStream, typename DynamicBuffer,
1120 typename RegEx, typename ReadHandler, typename Allocator>
1121 struct associated_allocator<
1122 detail::read_until_expr_op<AsyncReadStream,
1123 DynamicBuffer, RegEx, ReadHandler>,
1126 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
1129 const detail::read_until_expr_op<AsyncReadStream,
1130 DynamicBuffer, RegEx, ReadHandler>& h,
1131 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
1133 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
1137 template <typename AsyncReadStream, typename DynamicBuffer,
1138 typename RegEx, typename ReadHandler, typename Executor>
1139 struct associated_executor<
1140 detail::read_until_expr_op<AsyncReadStream,
1141 DynamicBuffer, RegEx, ReadHandler>,
1144 typedef typename associated_executor<ReadHandler, Executor>::type type;
1147 const detail::read_until_expr_op<AsyncReadStream,
1148 DynamicBuffer, RegEx, ReadHandler>& h,
1149 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
1151 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
1155 #endif // !defined(GENERATING_DOCUMENTATION)
1157 template <typename AsyncReadStream,
1158 typename DynamicBuffer, typename ReadHandler>
1159 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1160 void (boost::system::error_code, std::size_t))
1161 async_read_until(AsyncReadStream& s,
1162 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
1163 const boost::regex& expr,
1164 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1166 // If you get an error on the following line it means that your handler does
1167 // not meet the documented type requirements for a ReadHandler.
1168 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1170 async_completion<ReadHandler,
1171 void (boost::system::error_code, std::size_t)> init(handler);
1173 detail::read_until_expr_op<AsyncReadStream,
1174 typename decay<DynamicBuffer>::type,
1175 boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
1176 void (boost::system::error_code, std::size_t))>(
1177 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
1178 expr, init.completion_handler)(boost::system::error_code(), 0, 1);
1180 return init.result.get();
1183 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1187 template <typename AsyncReadStream, typename DynamicBuffer,
1188 typename MatchCondition, typename ReadHandler>
1189 class read_until_match_op
1192 template <typename BufferSequence>
1193 read_until_match_op(AsyncReadStream& stream,
1194 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
1195 MatchCondition match_condition, ReadHandler& handler)
1197 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
1198 match_condition_(match_condition),
1200 search_position_(0),
1201 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
1205 #if defined(BOOST_ASIO_HAS_MOVE)
1206 read_until_match_op(const read_until_match_op& other)
1207 : stream_(other.stream_),
1208 buffers_(other.buffers_),
1209 match_condition_(other.match_condition_),
1210 start_(other.start_),
1211 search_position_(other.search_position_),
1212 handler_(other.handler_)
1216 read_until_match_op(read_until_match_op&& other)
1217 : stream_(other.stream_),
1218 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
1219 match_condition_(other.match_condition_),
1220 start_(other.start_),
1221 search_position_(other.search_position_),
1222 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
1225 #endif // defined(BOOST_ASIO_HAS_MOVE)
1227 void operator()(const boost::system::error_code& ec,
1228 std::size_t bytes_transferred, int start = 0)
1230 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1231 std::size_t bytes_to_read;
1232 switch (start_ = start)
1238 // Determine the range of the data to be searched.
1239 typedef typename DynamicBuffer::const_buffers_type
1241 typedef buffers_iterator<buffers_type> iterator;
1242 buffers_type data_buffers = buffers_.data();
1243 iterator begin = iterator::begin(data_buffers);
1244 iterator start_pos = begin + search_position_;
1245 iterator end = iterator::end(data_buffers);
1247 // Look for a match.
1248 std::pair<iterator, bool> result = match_condition_(start_pos, end);
1251 // Full match. We're done.
1252 search_position_ = result.first - begin;
1256 // No match yet. Check if buffer is full.
1257 else if (buffers_.size() == buffers_.max_size())
1259 search_position_ = not_found;
1263 // Need to read some more data.
1266 if (result.first != end)
1268 // Partial match. Next search needs to start from beginning of
1270 search_position_ = result.first - begin;
1274 // Next search can start with the new data.
1275 search_position_ = end - begin;
1278 bytes_to_read = std::min<std::size_t>(
1279 std::max<std::size_t>(512,
1280 buffers_.capacity() - buffers_.size()),
1281 std::min<std::size_t>(65536,
1282 buffers_.max_size() - buffers_.size()));
1286 // Check if we're done.
1287 if (!start && bytes_to_read == 0)
1290 // Start a new asynchronous read operation to obtain more data.
1291 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1292 BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this));
1294 buffers_.commit(bytes_transferred);
1295 if (ec || bytes_transferred == 0)
1299 const boost::system::error_code result_ec =
1300 (search_position_ == not_found)
1301 ? error::not_found : ec;
1303 const std::size_t result_n =
1304 (ec || search_position_ == not_found)
1305 ? 0 : search_position_;
1307 handler_(result_ec, result_n);
1312 AsyncReadStream& stream_;
1313 DynamicBuffer buffers_;
1314 MatchCondition match_condition_;
1316 std::size_t search_position_;
1317 ReadHandler handler_;
1320 template <typename AsyncReadStream, typename DynamicBuffer,
1321 typename MatchCondition, typename ReadHandler>
1322 inline void* asio_handler_allocate(std::size_t size,
1323 read_until_match_op<AsyncReadStream, DynamicBuffer,
1324 MatchCondition, ReadHandler>* this_handler)
1326 return boost_asio_handler_alloc_helpers::allocate(
1327 size, this_handler->handler_);
1330 template <typename AsyncReadStream, typename DynamicBuffer,
1331 typename MatchCondition, typename ReadHandler>
1332 inline void asio_handler_deallocate(void* pointer, std::size_t size,
1333 read_until_match_op<AsyncReadStream, DynamicBuffer,
1334 MatchCondition, ReadHandler>* this_handler)
1336 boost_asio_handler_alloc_helpers::deallocate(
1337 pointer, size, this_handler->handler_);
1340 template <typename AsyncReadStream, typename DynamicBuffer,
1341 typename MatchCondition, typename ReadHandler>
1342 inline bool asio_handler_is_continuation(
1343 read_until_match_op<AsyncReadStream, DynamicBuffer,
1344 MatchCondition, ReadHandler>* this_handler)
1346 return this_handler->start_ == 0 ? true
1347 : boost_asio_handler_cont_helpers::is_continuation(
1348 this_handler->handler_);
1351 template <typename Function, typename AsyncReadStream,
1352 typename DynamicBuffer, typename MatchCondition,
1353 typename ReadHandler>
1354 inline void asio_handler_invoke(Function& function,
1355 read_until_match_op<AsyncReadStream, DynamicBuffer,
1356 MatchCondition, ReadHandler>* this_handler)
1358 boost_asio_handler_invoke_helpers::invoke(
1359 function, this_handler->handler_);
1362 template <typename Function, typename AsyncReadStream,
1363 typename DynamicBuffer, typename MatchCondition,
1364 typename ReadHandler>
1365 inline void asio_handler_invoke(const Function& function,
1366 read_until_match_op<AsyncReadStream, DynamicBuffer,
1367 MatchCondition, ReadHandler>* this_handler)
1369 boost_asio_handler_invoke_helpers::invoke(
1370 function, this_handler->handler_);
1372 } // namespace detail
1374 #if !defined(GENERATING_DOCUMENTATION)
1376 template <typename AsyncReadStream, typename DynamicBuffer,
1377 typename MatchCondition, typename ReadHandler, typename Allocator>
1378 struct associated_allocator<
1379 detail::read_until_match_op<AsyncReadStream,
1380 DynamicBuffer, MatchCondition, ReadHandler>,
1383 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
1386 const detail::read_until_match_op<AsyncReadStream,
1387 DynamicBuffer, MatchCondition, ReadHandler>& h,
1388 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
1390 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
1394 template <typename AsyncReadStream, typename DynamicBuffer,
1395 typename MatchCondition, typename ReadHandler, typename Executor>
1396 struct associated_executor<
1397 detail::read_until_match_op<AsyncReadStream,
1398 DynamicBuffer, MatchCondition, ReadHandler>,
1401 typedef typename associated_executor<ReadHandler, Executor>::type type;
1404 const detail::read_until_match_op<AsyncReadStream,
1405 DynamicBuffer, MatchCondition, ReadHandler>& h,
1406 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
1408 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
1412 #endif // !defined(GENERATING_DOCUMENTATION)
1414 template <typename AsyncReadStream, typename DynamicBuffer,
1415 typename MatchCondition, typename ReadHandler>
1416 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1417 void (boost::system::error_code, std::size_t))
1418 async_read_until(AsyncReadStream& s,
1419 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
1420 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1421 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
1423 // If you get an error on the following line it means that your handler does
1424 // not meet the documented type requirements for a ReadHandler.
1425 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1427 async_completion<ReadHandler,
1428 void (boost::system::error_code, std::size_t)> init(handler);
1430 detail::read_until_match_op<AsyncReadStream,
1431 typename decay<DynamicBuffer>::type,
1432 MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
1433 void (boost::system::error_code, std::size_t))>(
1434 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
1435 match_condition, init.completion_handler)(
1436 boost::system::error_code(), 0, 1);
1438 return init.result.get();
1441 #if !defined(BOOST_ASIO_NO_IOSTREAM)
1443 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1444 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1445 void (boost::system::error_code, std::size_t))
1446 async_read_until(AsyncReadStream& s,
1447 boost::asio::basic_streambuf<Allocator>& b,
1448 char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1450 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1451 delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1454 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1455 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1456 void (boost::system::error_code, std::size_t))
1457 async_read_until(AsyncReadStream& s,
1458 boost::asio::basic_streambuf<Allocator>& b,
1459 BOOST_ASIO_STRING_VIEW_PARAM delim,
1460 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1462 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1463 delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1466 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
1468 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1469 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1470 void (boost::system::error_code, std::size_t))
1471 async_read_until(AsyncReadStream& s,
1472 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
1473 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1475 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1476 expr, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1479 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1481 template <typename AsyncReadStream, typename Allocator,
1482 typename MatchCondition, typename ReadHandler>
1483 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1484 void (boost::system::error_code, std::size_t))
1485 async_read_until(AsyncReadStream& s,
1486 boost::asio::basic_streambuf<Allocator>& b,
1487 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1488 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
1490 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1491 match_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1494 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
1495 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
1498 } // namespace boost
1500 #include <boost/asio/detail/pop_options.hpp>
1502 #endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP