Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:57

0001 //
0002 // impl/read_until.hpp
0003 // ~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
0012 #define BOOST_ASIO_IMPL_READ_UNTIL_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <algorithm>
0019 #include <string>
0020 #include <vector>
0021 #include <utility>
0022 #include <boost/asio/associator.hpp>
0023 #include <boost/asio/buffer.hpp>
0024 #include <boost/asio/buffers_iterator.hpp>
0025 #include <boost/asio/detail/base_from_cancellation_state.hpp>
0026 #include <boost/asio/detail/bind_handler.hpp>
0027 #include <boost/asio/detail/handler_cont_helpers.hpp>
0028 #include <boost/asio/detail/handler_tracking.hpp>
0029 #include <boost/asio/detail/handler_type_requirements.hpp>
0030 #include <boost/asio/detail/limits.hpp>
0031 #include <boost/asio/detail/non_const_lvalue.hpp>
0032 #include <boost/asio/detail/throw_error.hpp>
0033 
0034 #include <boost/asio/detail/push_options.hpp>
0035 
0036 namespace boost {
0037 namespace asio {
0038 
0039 namespace detail
0040 {
0041   // Algorithm that finds a subsequence of equal values in a sequence. Returns
0042   // (iterator,true) if a full match was found, in which case the iterator
0043   // points to the beginning of the match. Returns (iterator,false) if a
0044   // partial match was found at the end of the first sequence, in which case
0045   // the iterator points to the beginning of the partial match. Returns
0046   // (last1,false) if no full or partial match was found.
0047   template <typename Iterator1, typename Iterator2>
0048   std::pair<Iterator1, bool> partial_search(
0049       Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
0050   {
0051     for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
0052     {
0053       Iterator1 test_iter1 = iter1;
0054       Iterator2 test_iter2 = first2;
0055       for (;; ++test_iter1, ++test_iter2)
0056       {
0057         if (test_iter2 == last2)
0058           return std::make_pair(iter1, true);
0059         if (test_iter1 == last1)
0060         {
0061           if (test_iter2 != first2)
0062             return std::make_pair(iter1, false);
0063           else
0064             break;
0065         }
0066         if (*test_iter1 != *test_iter2)
0067           break;
0068       }
0069     }
0070     return std::make_pair(last1, false);
0071   }
0072 } // namespace detail
0073 
0074 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
0075 
0076 template <typename SyncReadStream, typename DynamicBuffer_v1>
0077 inline std::size_t read_until(SyncReadStream& s,
0078     DynamicBuffer_v1&& buffers, char delim,
0079     constraint_t<
0080       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0081     >,
0082     constraint_t<
0083       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0084     >)
0085 {
0086   boost::system::error_code ec;
0087   std::size_t bytes_transferred = read_until(s,
0088       static_cast<DynamicBuffer_v1&&>(buffers), delim, ec);
0089   boost::asio::detail::throw_error(ec, "read_until");
0090   return bytes_transferred;
0091 }
0092 
0093 template <typename SyncReadStream, typename DynamicBuffer_v1>
0094 std::size_t read_until(SyncReadStream& s,
0095     DynamicBuffer_v1&& buffers,
0096     char delim, boost::system::error_code& ec,
0097     constraint_t<
0098       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0099     >,
0100     constraint_t<
0101       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0102     >)
0103 {
0104   decay_t<DynamicBuffer_v1> b(
0105       static_cast<DynamicBuffer_v1&&>(buffers));
0106 
0107   std::size_t search_position = 0;
0108   for (;;)
0109   {
0110     // Determine the range of the data to be searched.
0111     typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
0112     typedef buffers_iterator<buffers_type> iterator;
0113     buffers_type data_buffers = b.data();
0114     iterator begin = iterator::begin(data_buffers);
0115     iterator start_pos = begin + search_position;
0116     iterator end = iterator::end(data_buffers);
0117 
0118     // Look for a match.
0119     iterator iter = std::find(start_pos, end, delim);
0120     if (iter != end)
0121     {
0122       // Found a match. We're done.
0123       ec = boost::system::error_code();
0124       return iter - begin + 1;
0125     }
0126     else
0127     {
0128       // No match. Next search can start with the new data.
0129       search_position = end - begin;
0130     }
0131 
0132     // Check if buffer is full.
0133     if (b.size() == b.max_size())
0134     {
0135       ec = error::not_found;
0136       return 0;
0137     }
0138 
0139     // Need more data.
0140     std::size_t bytes_to_read = std::min<std::size_t>(
0141           std::max<std::size_t>(512, b.capacity() - b.size()),
0142           std::min<std::size_t>(65536, b.max_size() - b.size()));
0143     b.commit(s.read_some(b.prepare(bytes_to_read), ec));
0144     if (ec)
0145       return 0;
0146   }
0147 }
0148 
0149 template <typename SyncReadStream, typename DynamicBuffer_v1>
0150 inline std::size_t read_until(SyncReadStream& s,
0151     DynamicBuffer_v1&& buffers,
0152     BOOST_ASIO_STRING_VIEW_PARAM delim,
0153     constraint_t<
0154       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0155     >,
0156     constraint_t<
0157       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0158     >)
0159 {
0160   boost::system::error_code ec;
0161   std::size_t bytes_transferred = read_until(s,
0162       static_cast<DynamicBuffer_v1&&>(buffers), delim, ec);
0163   boost::asio::detail::throw_error(ec, "read_until");
0164   return bytes_transferred;
0165 }
0166 
0167 template <typename SyncReadStream, typename DynamicBuffer_v1>
0168 std::size_t read_until(SyncReadStream& s,
0169     DynamicBuffer_v1&& buffers,
0170     BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec,
0171     constraint_t<
0172       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0173     >,
0174     constraint_t<
0175       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0176     >)
0177 {
0178   decay_t<DynamicBuffer_v1> b(
0179       static_cast<DynamicBuffer_v1&&>(buffers));
0180 
0181   std::size_t search_position = 0;
0182   for (;;)
0183   {
0184     // Determine the range of the data to be searched.
0185     typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
0186     typedef buffers_iterator<buffers_type> iterator;
0187     buffers_type data_buffers = b.data();
0188     iterator begin = iterator::begin(data_buffers);
0189     iterator start_pos = begin + search_position;
0190     iterator end = iterator::end(data_buffers);
0191 
0192     // Look for a match.
0193     std::pair<iterator, bool> result = detail::partial_search(
0194         start_pos, end, delim.begin(), delim.end());
0195     if (result.first != end)
0196     {
0197       if (result.second)
0198       {
0199         // Full match. We're done.
0200         ec = boost::system::error_code();
0201         return result.first - begin + delim.length();
0202       }
0203       else
0204       {
0205         // Partial match. Next search needs to start from beginning of match.
0206         search_position = result.first - begin;
0207       }
0208     }
0209     else
0210     {
0211       // No match. Next search can start with the new data.
0212       search_position = end - begin;
0213     }
0214 
0215     // Check if buffer is full.
0216     if (b.size() == b.max_size())
0217     {
0218       ec = error::not_found;
0219       return 0;
0220     }
0221 
0222     // Need more data.
0223     std::size_t bytes_to_read = std::min<std::size_t>(
0224           std::max<std::size_t>(512, b.capacity() - b.size()),
0225           std::min<std::size_t>(65536, b.max_size() - b.size()));
0226     b.commit(s.read_some(b.prepare(bytes_to_read), ec));
0227     if (ec)
0228       return 0;
0229   }
0230 }
0231 
0232 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0233 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
0234 
0235 namespace detail {
0236 
0237 struct regex_match_flags
0238 {
0239   template <typename T>
0240   operator T() const
0241   {
0242     return T::match_default | T::match_partial;
0243   }
0244 };
0245 
0246 } // namespace detail
0247 
0248 template <typename SyncReadStream, typename DynamicBuffer_v1, typename Traits>
0249 inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v1&& buffers,
0250     const boost::basic_regex<char, Traits>& expr,
0251     constraint_t<
0252       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0253     >,
0254     constraint_t<
0255       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0256     >)
0257 {
0258   boost::system::error_code ec;
0259   std::size_t bytes_transferred = read_until(s,
0260       static_cast<DynamicBuffer_v1&&>(buffers), expr, ec);
0261   boost::asio::detail::throw_error(ec, "read_until");
0262   return bytes_transferred;
0263 }
0264 
0265 template <typename SyncReadStream, typename DynamicBuffer_v1, typename Traits>
0266 std::size_t read_until(SyncReadStream& s, DynamicBuffer_v1&& buffers,
0267     const boost::basic_regex<char, Traits>& expr, boost::system::error_code& ec,
0268     constraint_t<
0269       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0270     >,
0271     constraint_t<
0272       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0273     >)
0274 {
0275   decay_t<DynamicBuffer_v1> b(
0276       static_cast<DynamicBuffer_v1&&>(buffers));
0277 
0278   std::size_t search_position = 0;
0279   for (;;)
0280   {
0281     // Determine the range of the data to be searched.
0282     typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
0283     typedef buffers_iterator<buffers_type> iterator;
0284     buffers_type data_buffers = b.data();
0285     iterator begin = iterator::begin(data_buffers);
0286     iterator start_pos = begin + search_position;
0287     iterator end = iterator::end(data_buffers);
0288 
0289     // Look for a match.
0290     boost::match_results<iterator,
0291       typename std::vector<boost::sub_match<iterator>>::allocator_type>
0292         match_results;
0293     if (regex_search(start_pos, end, match_results,
0294           expr, detail::regex_match_flags()))
0295     {
0296       if (match_results[0].matched)
0297       {
0298         // Full match. We're done.
0299         ec = boost::system::error_code();
0300         return match_results[0].second - begin;
0301       }
0302       else
0303       {
0304         // Partial match. Next search needs to start from beginning of match.
0305         search_position = match_results[0].first - begin;
0306       }
0307     }
0308     else
0309     {
0310       // No match. Next search can start with the new data.
0311       search_position = end - begin;
0312     }
0313 
0314     // Check if buffer is full.
0315     if (b.size() == b.max_size())
0316     {
0317       ec = error::not_found;
0318       return 0;
0319     }
0320 
0321     // Need more data.
0322     std::size_t bytes_to_read = std::min<std::size_t>(
0323           std::max<std::size_t>(512, b.capacity() - b.size()),
0324           std::min<std::size_t>(65536, b.max_size() - b.size()));
0325     b.commit(s.read_some(b.prepare(bytes_to_read), ec));
0326     if (ec)
0327       return 0;
0328   }
0329 }
0330 
0331 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
0332 
0333 template <typename SyncReadStream,
0334     typename DynamicBuffer_v1, typename MatchCondition>
0335 inline std::size_t read_until(SyncReadStream& s,
0336     DynamicBuffer_v1&& buffers,
0337     MatchCondition match_condition,
0338     constraint_t<
0339       is_match_condition<MatchCondition>::value
0340     >,
0341     constraint_t<
0342       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0343     >,
0344     constraint_t<
0345       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0346     >)
0347 {
0348   boost::system::error_code ec;
0349   std::size_t bytes_transferred = read_until(s,
0350       static_cast<DynamicBuffer_v1&&>(buffers),
0351       match_condition, ec);
0352   boost::asio::detail::throw_error(ec, "read_until");
0353   return bytes_transferred;
0354 }
0355 
0356 template <typename SyncReadStream,
0357     typename DynamicBuffer_v1, typename MatchCondition>
0358 std::size_t read_until(SyncReadStream& s,
0359     DynamicBuffer_v1&& buffers,
0360     MatchCondition match_condition, boost::system::error_code& ec,
0361     constraint_t<
0362       is_match_condition<MatchCondition>::value
0363     >,
0364     constraint_t<
0365       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0366     >,
0367     constraint_t<
0368       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0369     >)
0370 {
0371   decay_t<DynamicBuffer_v1> b(
0372       static_cast<DynamicBuffer_v1&&>(buffers));
0373 
0374   std::size_t search_position = 0;
0375   for (;;)
0376   {
0377     // Determine the range of the data to be searched.
0378     typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
0379     typedef buffers_iterator<buffers_type> iterator;
0380     buffers_type data_buffers = b.data();
0381     iterator begin = iterator::begin(data_buffers);
0382     iterator start_pos = begin + search_position;
0383     iterator end = iterator::end(data_buffers);
0384 
0385     // Look for a match.
0386     std::pair<iterator, bool> result = match_condition(start_pos, end);
0387     if (result.second)
0388     {
0389       // Full match. We're done.
0390       ec = boost::system::error_code();
0391       return result.first - begin;
0392     }
0393     else if (result.first != end)
0394     {
0395       // Partial match. Next search needs to start from beginning of match.
0396       search_position = result.first - begin;
0397     }
0398     else
0399     {
0400       // No match. Next search can start with the new data.
0401       search_position = end - begin;
0402     }
0403 
0404     // Check if buffer is full.
0405     if (b.size() == b.max_size())
0406     {
0407       ec = error::not_found;
0408       return 0;
0409     }
0410 
0411     // Need more data.
0412     std::size_t bytes_to_read = std::min<std::size_t>(
0413           std::max<std::size_t>(512, b.capacity() - b.size()),
0414           std::min<std::size_t>(65536, b.max_size() - b.size()));
0415     b.commit(s.read_some(b.prepare(bytes_to_read), ec));
0416     if (ec)
0417       return 0;
0418   }
0419 }
0420 
0421 #if !defined(BOOST_ASIO_NO_IOSTREAM)
0422 
0423 template <typename SyncReadStream, typename Allocator>
0424 inline std::size_t read_until(SyncReadStream& s,
0425     boost::asio::basic_streambuf<Allocator>& b, char delim)
0426 {
0427   return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
0428 }
0429 
0430 template <typename SyncReadStream, typename Allocator>
0431 inline std::size_t read_until(SyncReadStream& s,
0432     boost::asio::basic_streambuf<Allocator>& b, char delim,
0433     boost::system::error_code& ec)
0434 {
0435   return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
0436 }
0437 
0438 template <typename SyncReadStream, typename Allocator>
0439 inline std::size_t read_until(SyncReadStream& s,
0440     boost::asio::basic_streambuf<Allocator>& b,
0441     BOOST_ASIO_STRING_VIEW_PARAM delim)
0442 {
0443   return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
0444 }
0445 
0446 template <typename SyncReadStream, typename Allocator>
0447 inline std::size_t read_until(SyncReadStream& s,
0448     boost::asio::basic_streambuf<Allocator>& b,
0449     BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec)
0450 {
0451   return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
0452 }
0453 
0454 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
0455 
0456 template <typename SyncReadStream, typename Allocator, typename Traits>
0457 inline std::size_t read_until(SyncReadStream& s,
0458     boost::asio::basic_streambuf<Allocator>& b,
0459     const boost::basic_regex<char, Traits>& expr)
0460 {
0461   return read_until(s, basic_streambuf_ref<Allocator>(b), expr);
0462 }
0463 
0464 template <typename SyncReadStream, typename Allocator, typename Traits>
0465 inline std::size_t read_until(SyncReadStream& s,
0466     boost::asio::basic_streambuf<Allocator>& b,
0467     const boost::basic_regex<char, Traits>& expr,
0468     boost::system::error_code& ec)
0469 {
0470   return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec);
0471 }
0472 
0473 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
0474 
0475 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
0476 inline std::size_t read_until(SyncReadStream& s,
0477     boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
0478     constraint_t<is_match_condition<MatchCondition>::value>)
0479 {
0480   return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition);
0481 }
0482 
0483 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
0484 inline std::size_t read_until(SyncReadStream& s,
0485     boost::asio::basic_streambuf<Allocator>& b,
0486     MatchCondition match_condition, boost::system::error_code& ec,
0487     constraint_t<is_match_condition<MatchCondition>::value>)
0488 {
0489   return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec);
0490 }
0491 
0492 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
0493 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
0494 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
0495 
0496 template <typename SyncReadStream, typename DynamicBuffer_v2>
0497 inline std::size_t read_until(SyncReadStream& s,
0498     DynamicBuffer_v2 buffers, char delim,
0499     constraint_t<
0500       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0501     >)
0502 {
0503   boost::system::error_code ec;
0504   std::size_t bytes_transferred = read_until(s,
0505       static_cast<DynamicBuffer_v2&&>(buffers), delim, ec);
0506   boost::asio::detail::throw_error(ec, "read_until");
0507   return bytes_transferred;
0508 }
0509 
0510 template <typename SyncReadStream, typename DynamicBuffer_v2>
0511 std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
0512     char delim, boost::system::error_code& ec,
0513     constraint_t<
0514       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0515     >)
0516 {
0517   DynamicBuffer_v2& b = buffers;
0518 
0519   std::size_t search_position = 0;
0520   for (;;)
0521   {
0522     // Determine the range of the data to be searched.
0523     typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
0524     typedef buffers_iterator<buffers_type> iterator;
0525     buffers_type data_buffers =
0526       const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
0527     iterator begin = iterator::begin(data_buffers);
0528     iterator start_pos = begin + search_position;
0529     iterator end = iterator::end(data_buffers);
0530 
0531     // Look for a match.
0532     iterator iter = std::find(start_pos, end, delim);
0533     if (iter != end)
0534     {
0535       // Found a match. We're done.
0536       ec = boost::system::error_code();
0537       return iter - begin + 1;
0538     }
0539     else
0540     {
0541       // No match. Next search can start with the new data.
0542       search_position = end - begin;
0543     }
0544 
0545     // Check if buffer is full.
0546     if (b.size() == b.max_size())
0547     {
0548       ec = error::not_found;
0549       return 0;
0550     }
0551 
0552     // Need more data.
0553     std::size_t bytes_to_read = std::min<std::size_t>(
0554           std::max<std::size_t>(512, b.capacity() - b.size()),
0555           std::min<std::size_t>(65536, b.max_size() - b.size()));
0556     std::size_t pos = b.size();
0557     b.grow(bytes_to_read);
0558     std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
0559     b.shrink(bytes_to_read - bytes_transferred);
0560     if (ec)
0561       return 0;
0562   }
0563 }
0564 
0565 template <typename SyncReadStream, typename DynamicBuffer_v2>
0566 inline std::size_t read_until(SyncReadStream& s,
0567     DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim,
0568     constraint_t<
0569       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0570     >)
0571 {
0572   boost::system::error_code ec;
0573   std::size_t bytes_transferred = read_until(s,
0574       static_cast<DynamicBuffer_v2&&>(buffers), delim, ec);
0575   boost::asio::detail::throw_error(ec, "read_until");
0576   return bytes_transferred;
0577 }
0578 
0579 template <typename SyncReadStream, typename DynamicBuffer_v2>
0580 std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
0581     BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec,
0582     constraint_t<
0583       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0584     >)
0585 {
0586   DynamicBuffer_v2& b = buffers;
0587 
0588   std::size_t search_position = 0;
0589   for (;;)
0590   {
0591     // Determine the range of the data to be searched.
0592     typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
0593     typedef buffers_iterator<buffers_type> iterator;
0594     buffers_type data_buffers =
0595       const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
0596     iterator begin = iterator::begin(data_buffers);
0597     iterator start_pos = begin + search_position;
0598     iterator end = iterator::end(data_buffers);
0599 
0600     // Look for a match.
0601     std::pair<iterator, bool> result = detail::partial_search(
0602         start_pos, end, delim.begin(), delim.end());
0603     if (result.first != end)
0604     {
0605       if (result.second)
0606       {
0607         // Full match. We're done.
0608         ec = boost::system::error_code();
0609         return result.first - begin + delim.length();
0610       }
0611       else
0612       {
0613         // Partial match. Next search needs to start from beginning of match.
0614         search_position = result.first - begin;
0615       }
0616     }
0617     else
0618     {
0619       // No match. Next search can start with the new data.
0620       search_position = end - begin;
0621     }
0622 
0623     // Check if buffer is full.
0624     if (b.size() == b.max_size())
0625     {
0626       ec = error::not_found;
0627       return 0;
0628     }
0629 
0630     // Need more data.
0631     std::size_t bytes_to_read = std::min<std::size_t>(
0632           std::max<std::size_t>(512, b.capacity() - b.size()),
0633           std::min<std::size_t>(65536, b.max_size() - b.size()));
0634     std::size_t pos = b.size();
0635     b.grow(bytes_to_read);
0636     std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
0637     b.shrink(bytes_to_read - bytes_transferred);
0638     if (ec)
0639       return 0;
0640   }
0641 }
0642 
0643 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0644 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
0645 
0646 template <typename SyncReadStream, typename DynamicBuffer_v2, typename Traits>
0647 inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
0648     const boost::basic_regex<char, Traits>& expr,
0649     constraint_t<
0650       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0651     >)
0652 {
0653   boost::system::error_code ec;
0654   std::size_t bytes_transferred = read_until(s,
0655       static_cast<DynamicBuffer_v2&&>(buffers), expr, ec);
0656   boost::asio::detail::throw_error(ec, "read_until");
0657   return bytes_transferred;
0658 }
0659 
0660 template <typename SyncReadStream, typename DynamicBuffer_v2, typename Traits>
0661 std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
0662     const boost::basic_regex<char, Traits>& expr, boost::system::error_code& ec,
0663     constraint_t<
0664       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0665     >)
0666 {
0667   DynamicBuffer_v2& b = buffers;
0668 
0669   std::size_t search_position = 0;
0670   for (;;)
0671   {
0672     // Determine the range of the data to be searched.
0673     typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
0674     typedef buffers_iterator<buffers_type> iterator;
0675     buffers_type data_buffers =
0676       const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
0677     iterator begin = iterator::begin(data_buffers);
0678     iterator start_pos = begin + search_position;
0679     iterator end = iterator::end(data_buffers);
0680 
0681     // Look for a match.
0682     boost::match_results<iterator,
0683       typename std::vector<boost::sub_match<iterator>>::allocator_type>
0684         match_results;
0685     if (regex_search(start_pos, end, match_results,
0686           expr, detail::regex_match_flags()))
0687     {
0688       if (match_results[0].matched)
0689       {
0690         // Full match. We're done.
0691         ec = boost::system::error_code();
0692         return match_results[0].second - begin;
0693       }
0694       else
0695       {
0696         // Partial match. Next search needs to start from beginning of match.
0697         search_position = match_results[0].first - begin;
0698       }
0699     }
0700     else
0701     {
0702       // No match. Next search can start with the new data.
0703       search_position = end - begin;
0704     }
0705 
0706     // Check if buffer is full.
0707     if (b.size() == b.max_size())
0708     {
0709       ec = error::not_found;
0710       return 0;
0711     }
0712 
0713     // Need more data.
0714     std::size_t bytes_to_read = std::min<std::size_t>(
0715           std::max<std::size_t>(512, b.capacity() - b.size()),
0716           std::min<std::size_t>(65536, b.max_size() - b.size()));
0717     std::size_t pos = b.size();
0718     b.grow(bytes_to_read);
0719     std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
0720     b.shrink(bytes_to_read - bytes_transferred);
0721     if (ec)
0722       return 0;
0723   }
0724 }
0725 
0726 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
0727 
0728 template <typename SyncReadStream,
0729     typename DynamicBuffer_v2, typename MatchCondition>
0730 inline std::size_t read_until(SyncReadStream& s,
0731     DynamicBuffer_v2 buffers, MatchCondition match_condition,
0732     constraint_t<
0733       is_match_condition<MatchCondition>::value
0734     >,
0735     constraint_t<
0736       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0737     >)
0738 {
0739   boost::system::error_code ec;
0740   std::size_t bytes_transferred = read_until(s,
0741       static_cast<DynamicBuffer_v2&&>(buffers),
0742       match_condition, ec);
0743   boost::asio::detail::throw_error(ec, "read_until");
0744   return bytes_transferred;
0745 }
0746 
0747 template <typename SyncReadStream,
0748     typename DynamicBuffer_v2, typename MatchCondition>
0749 std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
0750     MatchCondition match_condition, boost::system::error_code& ec,
0751     constraint_t<
0752       is_match_condition<MatchCondition>::value
0753     >,
0754     constraint_t<
0755       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
0756     >)
0757 {
0758   DynamicBuffer_v2& b = buffers;
0759 
0760   std::size_t search_position = 0;
0761   for (;;)
0762   {
0763     // Determine the range of the data to be searched.
0764     typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
0765     typedef buffers_iterator<buffers_type> iterator;
0766     buffers_type data_buffers =
0767       const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
0768     iterator begin = iterator::begin(data_buffers);
0769     iterator start_pos = begin + search_position;
0770     iterator end = iterator::end(data_buffers);
0771 
0772     // Look for a match.
0773     std::pair<iterator, bool> result = match_condition(start_pos, end);
0774     if (result.second)
0775     {
0776       // Full match. We're done.
0777       ec = boost::system::error_code();
0778       return result.first - begin;
0779     }
0780     else if (result.first != end)
0781     {
0782       // Partial match. Next search needs to start from beginning of match.
0783       search_position = result.first - begin;
0784     }
0785     else
0786     {
0787       // No match. Next search can start with the new data.
0788       search_position = end - begin;
0789     }
0790 
0791     // Check if buffer is full.
0792     if (b.size() == b.max_size())
0793     {
0794       ec = error::not_found;
0795       return 0;
0796     }
0797 
0798     // Need more data.
0799     std::size_t bytes_to_read = std::min<std::size_t>(
0800           std::max<std::size_t>(512, b.capacity() - b.size()),
0801           std::min<std::size_t>(65536, b.max_size() - b.size()));
0802     std::size_t pos = b.size();
0803     b.grow(bytes_to_read);
0804     std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
0805     b.shrink(bytes_to_read - bytes_transferred);
0806     if (ec)
0807       return 0;
0808   }
0809 }
0810 
0811 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
0812 
0813 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
0814 
0815 namespace detail
0816 {
0817   template <typename AsyncReadStream,
0818       typename DynamicBuffer_v1, typename ReadHandler>
0819   class read_until_delim_op_v1
0820     : public base_from_cancellation_state<ReadHandler>
0821   {
0822   public:
0823     template <typename BufferSequence>
0824     read_until_delim_op_v1(AsyncReadStream& stream,
0825         BufferSequence&& buffers,
0826         char delim, ReadHandler& handler)
0827       : base_from_cancellation_state<ReadHandler>(
0828           handler, enable_partial_cancellation()),
0829         stream_(stream),
0830         buffers_(static_cast<BufferSequence&&>(buffers)),
0831         delim_(delim),
0832         start_(0),
0833         search_position_(0),
0834         handler_(static_cast<ReadHandler&&>(handler))
0835     {
0836     }
0837 
0838     read_until_delim_op_v1(const read_until_delim_op_v1& other)
0839       : base_from_cancellation_state<ReadHandler>(other),
0840         stream_(other.stream_),
0841         buffers_(other.buffers_),
0842         delim_(other.delim_),
0843         start_(other.start_),
0844         search_position_(other.search_position_),
0845         handler_(other.handler_)
0846     {
0847     }
0848 
0849     read_until_delim_op_v1(read_until_delim_op_v1&& other)
0850       : base_from_cancellation_state<ReadHandler>(
0851           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
0852         stream_(other.stream_),
0853         buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
0854         delim_(other.delim_),
0855         start_(other.start_),
0856         search_position_(other.search_position_),
0857         handler_(static_cast<ReadHandler&&>(other.handler_))
0858     {
0859     }
0860 
0861     void operator()(boost::system::error_code ec,
0862         std::size_t bytes_transferred, int start = 0)
0863     {
0864       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
0865       std::size_t bytes_to_read;
0866       switch (start_ = start)
0867       {
0868       case 1:
0869         for (;;)
0870         {
0871           {
0872             // Determine the range of the data to be searched.
0873             typedef typename DynamicBuffer_v1::const_buffers_type
0874               buffers_type;
0875             typedef buffers_iterator<buffers_type> iterator;
0876             buffers_type data_buffers = buffers_.data();
0877             iterator begin = iterator::begin(data_buffers);
0878             iterator start_pos = begin + search_position_;
0879             iterator end = iterator::end(data_buffers);
0880 
0881             // Look for a match.
0882             iterator iter = std::find(start_pos, end, delim_);
0883             if (iter != end)
0884             {
0885               // Found a match. We're done.
0886               search_position_ = iter - begin + 1;
0887               bytes_to_read = 0;
0888             }
0889 
0890             // No match yet. Check if buffer is full.
0891             else if (buffers_.size() == buffers_.max_size())
0892             {
0893               search_position_ = not_found;
0894               bytes_to_read = 0;
0895             }
0896 
0897             // Need to read some more data.
0898             else
0899             {
0900               // Next search can start with the new data.
0901               search_position_ = end - begin;
0902               bytes_to_read = std::min<std::size_t>(
0903                     std::max<std::size_t>(512,
0904                       buffers_.capacity() - buffers_.size()),
0905                     std::min<std::size_t>(65536,
0906                       buffers_.max_size() - buffers_.size()));
0907             }
0908           }
0909 
0910           // Check if we're done.
0911           if (!start && bytes_to_read == 0)
0912             break;
0913 
0914           // Start a new asynchronous read operation to obtain more data.
0915           {
0916             BOOST_ASIO_HANDLER_LOCATION((
0917                   __FILE__, __LINE__, "async_read_until"));
0918             stream_.async_read_some(buffers_.prepare(bytes_to_read),
0919                 static_cast<read_until_delim_op_v1&&>(*this));
0920           }
0921           return; default:
0922           buffers_.commit(bytes_transferred);
0923           if (ec || bytes_transferred == 0)
0924             break;
0925           if (this->cancelled() != cancellation_type::none)
0926           {
0927             ec = error::operation_aborted;
0928             break;
0929           }
0930         }
0931 
0932         const boost::system::error_code result_ec =
0933           (search_position_ == not_found)
0934           ? error::not_found : ec;
0935 
0936         const std::size_t result_n =
0937           (ec || search_position_ == not_found)
0938           ? 0 : search_position_;
0939 
0940         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
0941       }
0942     }
0943 
0944   //private:
0945     AsyncReadStream& stream_;
0946     DynamicBuffer_v1 buffers_;
0947     char delim_;
0948     int start_;
0949     std::size_t search_position_;
0950     ReadHandler handler_;
0951   };
0952 
0953   template <typename AsyncReadStream,
0954       typename DynamicBuffer_v1, typename ReadHandler>
0955   inline bool asio_handler_is_continuation(
0956       read_until_delim_op_v1<AsyncReadStream,
0957         DynamicBuffer_v1, ReadHandler>* this_handler)
0958   {
0959     return this_handler->start_ == 0 ? true
0960       : boost_asio_handler_cont_helpers::is_continuation(
0961           this_handler->handler_);
0962   }
0963 
0964   template <typename AsyncReadStream>
0965   class initiate_async_read_until_delim_v1
0966   {
0967   public:
0968     typedef typename AsyncReadStream::executor_type executor_type;
0969 
0970     explicit initiate_async_read_until_delim_v1(AsyncReadStream& stream)
0971       : stream_(stream)
0972     {
0973     }
0974 
0975     executor_type get_executor() const noexcept
0976     {
0977       return stream_.get_executor();
0978     }
0979 
0980     template <typename ReadHandler, typename DynamicBuffer_v1>
0981     void operator()(ReadHandler&& handler,
0982         DynamicBuffer_v1&& buffers,
0983         char delim) const
0984     {
0985       // If you get an error on the following line it means that your handler
0986       // does not meet the documented type requirements for a ReadHandler.
0987       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
0988 
0989       non_const_lvalue<ReadHandler> handler2(handler);
0990       read_until_delim_op_v1<AsyncReadStream,
0991         decay_t<DynamicBuffer_v1>,
0992           decay_t<ReadHandler>>(
0993             stream_, static_cast<DynamicBuffer_v1&&>(buffers),
0994             delim, handler2.value)(boost::system::error_code(), 0, 1);
0995     }
0996 
0997   private:
0998     AsyncReadStream& stream_;
0999   };
1000 } // namespace detail
1001 
1002 #if !defined(GENERATING_DOCUMENTATION)
1003 
1004 template <template <typename, typename> class Associator,
1005     typename AsyncReadStream, typename DynamicBuffer_v1,
1006     typename ReadHandler, typename DefaultCandidate>
1007 struct associator<Associator,
1008     detail::read_until_delim_op_v1<AsyncReadStream,
1009       DynamicBuffer_v1, ReadHandler>,
1010     DefaultCandidate>
1011   : Associator<ReadHandler, DefaultCandidate>
1012 {
1013   static typename Associator<ReadHandler, DefaultCandidate>::type get(
1014       const detail::read_until_delim_op_v1<AsyncReadStream,
1015         DynamicBuffer_v1, ReadHandler>& h) noexcept
1016   {
1017     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1018   }
1019 
1020   static auto get(
1021       const detail::read_until_delim_op_v1<AsyncReadStream,
1022         DynamicBuffer_v1, ReadHandler>& h,
1023       const DefaultCandidate& c) noexcept
1024     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1025   {
1026     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1027   }
1028 };
1029 
1030 #endif // !defined(GENERATING_DOCUMENTATION)
1031 
1032 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1033     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1034       std::size_t)) ReadToken>
1035 inline auto async_read_until(AsyncReadStream& s,
1036     DynamicBuffer_v1&& buffers, char delim, ReadToken&& token,
1037     constraint_t<
1038       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
1039     >,
1040     constraint_t<
1041       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
1042     >)
1043   -> decltype(
1044     async_initiate<ReadToken,
1045       void (boost::system::error_code, std::size_t)>(
1046         declval<detail::initiate_async_read_until_delim_v1<AsyncReadStream>>(),
1047         token, static_cast<DynamicBuffer_v1&&>(buffers), delim))
1048 {
1049   return async_initiate<ReadToken,
1050     void (boost::system::error_code, std::size_t)>(
1051       detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s),
1052       token, static_cast<DynamicBuffer_v1&&>(buffers), delim);
1053 }
1054 
1055 namespace detail
1056 {
1057   template <typename AsyncReadStream,
1058       typename DynamicBuffer_v1, typename ReadHandler>
1059   class read_until_delim_string_op_v1
1060     : public base_from_cancellation_state<ReadHandler>
1061   {
1062   public:
1063     template <typename BufferSequence>
1064     read_until_delim_string_op_v1(AsyncReadStream& stream,
1065         BufferSequence&& buffers,
1066         const std::string& delim, ReadHandler& handler)
1067       : base_from_cancellation_state<ReadHandler>(
1068           handler, enable_partial_cancellation()),
1069         stream_(stream),
1070         buffers_(static_cast<BufferSequence&&>(buffers)),
1071         delim_(delim),
1072         start_(0),
1073         search_position_(0),
1074         handler_(static_cast<ReadHandler&&>(handler))
1075     {
1076     }
1077 
1078     read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other)
1079       : base_from_cancellation_state<ReadHandler>(other),
1080         stream_(other.stream_),
1081         buffers_(other.buffers_),
1082         delim_(other.delim_),
1083         start_(other.start_),
1084         search_position_(other.search_position_),
1085         handler_(other.handler_)
1086     {
1087     }
1088 
1089     read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other)
1090       : base_from_cancellation_state<ReadHandler>(
1091           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1092         stream_(other.stream_),
1093         buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
1094         delim_(static_cast<std::string&&>(other.delim_)),
1095         start_(other.start_),
1096         search_position_(other.search_position_),
1097         handler_(static_cast<ReadHandler&&>(other.handler_))
1098     {
1099     }
1100 
1101     void operator()(boost::system::error_code ec,
1102         std::size_t bytes_transferred, int start = 0)
1103     {
1104       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1105       std::size_t bytes_to_read;
1106       switch (start_ = start)
1107       {
1108       case 1:
1109         for (;;)
1110         {
1111           {
1112             // Determine the range of the data to be searched.
1113             typedef typename DynamicBuffer_v1::const_buffers_type
1114               buffers_type;
1115             typedef buffers_iterator<buffers_type> iterator;
1116             buffers_type data_buffers = buffers_.data();
1117             iterator begin = iterator::begin(data_buffers);
1118             iterator start_pos = begin + search_position_;
1119             iterator end = iterator::end(data_buffers);
1120 
1121             // Look for a match.
1122             std::pair<iterator, bool> result = detail::partial_search(
1123                 start_pos, end, delim_.begin(), delim_.end());
1124             if (result.first != end && result.second)
1125             {
1126               // Full match. We're done.
1127               search_position_ = result.first - begin + delim_.length();
1128               bytes_to_read = 0;
1129             }
1130 
1131             // No match yet. Check if buffer is full.
1132             else if (buffers_.size() == buffers_.max_size())
1133             {
1134               search_position_ = not_found;
1135               bytes_to_read = 0;
1136             }
1137 
1138             // Need to read some more data.
1139             else
1140             {
1141               if (result.first != end)
1142               {
1143                 // Partial match. Next search needs to start from beginning of
1144                 // match.
1145                 search_position_ = result.first - begin;
1146               }
1147               else
1148               {
1149                 // Next search can start with the new data.
1150                 search_position_ = end - begin;
1151               }
1152 
1153               bytes_to_read = std::min<std::size_t>(
1154                     std::max<std::size_t>(512,
1155                       buffers_.capacity() - buffers_.size()),
1156                     std::min<std::size_t>(65536,
1157                       buffers_.max_size() - buffers_.size()));
1158             }
1159           }
1160 
1161           // Check if we're done.
1162           if (!start && bytes_to_read == 0)
1163             break;
1164 
1165           // Start a new asynchronous read operation to obtain more data.
1166           {
1167             BOOST_ASIO_HANDLER_LOCATION((
1168                   __FILE__, __LINE__, "async_read_until"));
1169             stream_.async_read_some(buffers_.prepare(bytes_to_read),
1170                 static_cast<read_until_delim_string_op_v1&&>(*this));
1171           }
1172           return; default:
1173           buffers_.commit(bytes_transferred);
1174           if (ec || bytes_transferred == 0)
1175             break;
1176           if (this->cancelled() != cancellation_type::none)
1177           {
1178             ec = error::operation_aborted;
1179             break;
1180           }
1181         }
1182 
1183         const boost::system::error_code result_ec =
1184           (search_position_ == not_found)
1185           ? error::not_found : ec;
1186 
1187         const std::size_t result_n =
1188           (ec || search_position_ == not_found)
1189           ? 0 : search_position_;
1190 
1191         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
1192       }
1193     }
1194 
1195   //private:
1196     AsyncReadStream& stream_;
1197     DynamicBuffer_v1 buffers_;
1198     std::string delim_;
1199     int start_;
1200     std::size_t search_position_;
1201     ReadHandler handler_;
1202   };
1203 
1204   template <typename AsyncReadStream,
1205       typename DynamicBuffer_v1, typename ReadHandler>
1206   inline bool asio_handler_is_continuation(
1207       read_until_delim_string_op_v1<AsyncReadStream,
1208         DynamicBuffer_v1, ReadHandler>* this_handler)
1209   {
1210     return this_handler->start_ == 0 ? true
1211       : boost_asio_handler_cont_helpers::is_continuation(
1212           this_handler->handler_);
1213   }
1214 
1215   template <typename AsyncReadStream>
1216   class initiate_async_read_until_delim_string_v1
1217   {
1218   public:
1219     typedef typename AsyncReadStream::executor_type executor_type;
1220 
1221     explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream)
1222       : stream_(stream)
1223     {
1224     }
1225 
1226     executor_type get_executor() const noexcept
1227     {
1228       return stream_.get_executor();
1229     }
1230 
1231     template <typename ReadHandler, typename DynamicBuffer_v1>
1232     void operator()(ReadHandler&& handler,
1233         DynamicBuffer_v1&& buffers,
1234         const std::string& delim) const
1235     {
1236       // If you get an error on the following line it means that your handler
1237       // does not meet the documented type requirements for a ReadHandler.
1238       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1239 
1240       non_const_lvalue<ReadHandler> handler2(handler);
1241       read_until_delim_string_op_v1<AsyncReadStream,
1242         decay_t<DynamicBuffer_v1>,
1243           decay_t<ReadHandler>>(
1244             stream_, static_cast<DynamicBuffer_v1&&>(buffers),
1245             delim, handler2.value)(boost::system::error_code(), 0, 1);
1246     }
1247 
1248   private:
1249     AsyncReadStream& stream_;
1250   };
1251 } // namespace detail
1252 
1253 #if !defined(GENERATING_DOCUMENTATION)
1254 
1255 template <template <typename, typename> class Associator,
1256     typename AsyncReadStream, typename DynamicBuffer_v1,
1257     typename ReadHandler, typename DefaultCandidate>
1258 struct associator<Associator,
1259     detail::read_until_delim_string_op_v1<AsyncReadStream,
1260       DynamicBuffer_v1, ReadHandler>,
1261     DefaultCandidate>
1262   : Associator<ReadHandler, DefaultCandidate>
1263 {
1264   static typename Associator<ReadHandler, DefaultCandidate>::type get(
1265       const detail::read_until_delim_string_op_v1<
1266         AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h) noexcept
1267   {
1268     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1269   }
1270 
1271   static auto get(
1272       const detail::read_until_delim_string_op_v1<
1273         AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h,
1274       const DefaultCandidate& c) noexcept
1275     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1276   {
1277     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1278   }
1279 };
1280 
1281 #endif // !defined(GENERATING_DOCUMENTATION)
1282 
1283 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1284     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1285       std::size_t)) ReadToken>
1286 inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v1&& buffers,
1287     BOOST_ASIO_STRING_VIEW_PARAM delim, ReadToken&& token,
1288     constraint_t<
1289       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
1290     >,
1291     constraint_t<
1292       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
1293     >)
1294   -> decltype(
1295     async_initiate<ReadToken,
1296       void (boost::system::error_code, std::size_t)>(
1297         declval<detail::initiate_async_read_until_delim_string_v1<
1298           AsyncReadStream>>(),
1299         token, static_cast<DynamicBuffer_v1&&>(buffers),
1300         static_cast<std::string>(delim)))
1301 {
1302   return async_initiate<ReadToken,
1303     void (boost::system::error_code, std::size_t)>(
1304       detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s),
1305       token, static_cast<DynamicBuffer_v1&&>(buffers),
1306       static_cast<std::string>(delim));
1307 }
1308 
1309 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
1310 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
1311 
1312 namespace detail
1313 {
1314   template <typename AsyncReadStream, typename DynamicBuffer_v1,
1315       typename RegEx, typename ReadHandler>
1316   class read_until_expr_op_v1
1317     : public base_from_cancellation_state<ReadHandler>
1318   {
1319   public:
1320     template <typename BufferSequence, typename Traits>
1321     read_until_expr_op_v1(AsyncReadStream& stream, BufferSequence&& buffers,
1322         const boost::basic_regex<char, Traits>& expr, ReadHandler& handler)
1323       : base_from_cancellation_state<ReadHandler>(
1324           handler, enable_partial_cancellation()),
1325         stream_(stream),
1326         buffers_(static_cast<BufferSequence&&>(buffers)),
1327         expr_(expr),
1328         start_(0),
1329         search_position_(0),
1330         handler_(static_cast<ReadHandler&&>(handler))
1331     {
1332     }
1333 
1334     read_until_expr_op_v1(const read_until_expr_op_v1& other)
1335       : base_from_cancellation_state<ReadHandler>(other),
1336         stream_(other.stream_),
1337         buffers_(other.buffers_),
1338         expr_(other.expr_),
1339         start_(other.start_),
1340         search_position_(other.search_position_),
1341         handler_(other.handler_)
1342     {
1343     }
1344 
1345     read_until_expr_op_v1(read_until_expr_op_v1&& other)
1346       : base_from_cancellation_state<ReadHandler>(
1347           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1348         stream_(other.stream_),
1349         buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
1350         expr_(other.expr_),
1351         start_(other.start_),
1352         search_position_(other.search_position_),
1353         handler_(static_cast<ReadHandler&&>(other.handler_))
1354     {
1355     }
1356 
1357     void operator()(boost::system::error_code ec,
1358         std::size_t bytes_transferred, int start = 0)
1359     {
1360       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1361       std::size_t bytes_to_read;
1362       switch (start_ = start)
1363       {
1364       case 1:
1365         for (;;)
1366         {
1367           {
1368             // Determine the range of the data to be searched.
1369             typedef typename DynamicBuffer_v1::const_buffers_type
1370               buffers_type;
1371             typedef buffers_iterator<buffers_type> iterator;
1372             buffers_type data_buffers = buffers_.data();
1373             iterator begin = iterator::begin(data_buffers);
1374             iterator start_pos = begin + search_position_;
1375             iterator end = iterator::end(data_buffers);
1376 
1377             // Look for a match.
1378             boost::match_results<iterator,
1379               typename std::vector<boost::sub_match<iterator>>::allocator_type>
1380                 match_results;
1381             bool match = regex_search(start_pos, end,
1382                 match_results, expr_, regex_match_flags());
1383             if (match && match_results[0].matched)
1384             {
1385               // Full match. We're done.
1386               search_position_ = match_results[0].second - begin;
1387               bytes_to_read = 0;
1388             }
1389 
1390             // No match yet. Check if buffer is full.
1391             else if (buffers_.size() == buffers_.max_size())
1392             {
1393               search_position_ = not_found;
1394               bytes_to_read = 0;
1395             }
1396 
1397             // Need to read some more data.
1398             else
1399             {
1400               if (match)
1401               {
1402                 // Partial match. Next search needs to start from beginning of
1403                 // match.
1404                 search_position_ = match_results[0].first - begin;
1405               }
1406               else
1407               {
1408                 // Next search can start with the new data.
1409                 search_position_ = end - begin;
1410               }
1411 
1412               bytes_to_read = std::min<std::size_t>(
1413                     std::max<std::size_t>(512,
1414                       buffers_.capacity() - buffers_.size()),
1415                     std::min<std::size_t>(65536,
1416                       buffers_.max_size() - buffers_.size()));
1417             }
1418           }
1419 
1420           // Check if we're done.
1421           if (!start && bytes_to_read == 0)
1422             break;
1423 
1424           // Start a new asynchronous read operation to obtain more data.
1425           {
1426             BOOST_ASIO_HANDLER_LOCATION((
1427                   __FILE__, __LINE__, "async_read_until"));
1428             stream_.async_read_some(buffers_.prepare(bytes_to_read),
1429                 static_cast<read_until_expr_op_v1&&>(*this));
1430           }
1431           return; default:
1432           buffers_.commit(bytes_transferred);
1433           if (ec || bytes_transferred == 0)
1434             break;
1435           if (this->cancelled() != cancellation_type::none)
1436           {
1437             ec = error::operation_aborted;
1438             break;
1439           }
1440         }
1441 
1442         const boost::system::error_code result_ec =
1443           (search_position_ == not_found)
1444           ? error::not_found : ec;
1445 
1446         const std::size_t result_n =
1447           (ec || search_position_ == not_found)
1448           ? 0 : search_position_;
1449 
1450         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
1451       }
1452     }
1453 
1454   //private:
1455     AsyncReadStream& stream_;
1456     DynamicBuffer_v1 buffers_;
1457     RegEx expr_;
1458     int start_;
1459     std::size_t search_position_;
1460     ReadHandler handler_;
1461   };
1462 
1463   template <typename AsyncReadStream, typename DynamicBuffer_v1,
1464       typename RegEx, typename ReadHandler>
1465   inline bool asio_handler_is_continuation(
1466       read_until_expr_op_v1<AsyncReadStream,
1467         DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
1468   {
1469     return this_handler->start_ == 0 ? true
1470       : boost_asio_handler_cont_helpers::is_continuation(
1471           this_handler->handler_);
1472   }
1473 
1474   template <typename AsyncReadStream>
1475   class initiate_async_read_until_expr_v1
1476   {
1477   public:
1478     typedef typename AsyncReadStream::executor_type executor_type;
1479 
1480     explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream)
1481       : stream_(stream)
1482     {
1483     }
1484 
1485     executor_type get_executor() const noexcept
1486     {
1487       return stream_.get_executor();
1488     }
1489 
1490     template <typename ReadHandler, typename DynamicBuffer_v1, typename RegEx>
1491     void operator()(ReadHandler&& handler,
1492         DynamicBuffer_v1&& buffers, const RegEx& expr) const
1493     {
1494       // If you get an error on the following line it means that your handler
1495       // does not meet the documented type requirements for a ReadHandler.
1496       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1497 
1498       non_const_lvalue<ReadHandler> handler2(handler);
1499       read_until_expr_op_v1<AsyncReadStream,
1500         decay_t<DynamicBuffer_v1>,
1501           RegEx, decay_t<ReadHandler>>(
1502             stream_, static_cast<DynamicBuffer_v1&&>(buffers),
1503             expr, handler2.value)(boost::system::error_code(), 0, 1);
1504     }
1505 
1506   private:
1507     AsyncReadStream& stream_;
1508   };
1509 } // namespace detail
1510 
1511 #if !defined(GENERATING_DOCUMENTATION)
1512 
1513 template <template <typename, typename> class Associator,
1514     typename AsyncReadStream, typename DynamicBuffer_v1,
1515     typename RegEx, typename ReadHandler, typename DefaultCandidate>
1516 struct associator<Associator,
1517     detail::read_until_expr_op_v1<AsyncReadStream,
1518       DynamicBuffer_v1, RegEx, ReadHandler>,
1519     DefaultCandidate>
1520   : Associator<ReadHandler, DefaultCandidate>
1521 {
1522   static typename Associator<ReadHandler, DefaultCandidate>::type get(
1523       const detail::read_until_expr_op_v1<AsyncReadStream,
1524         DynamicBuffer_v1, RegEx, ReadHandler>& h) noexcept
1525   {
1526     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1527   }
1528 
1529   static auto get(
1530       const detail::read_until_expr_op_v1<AsyncReadStream,
1531         DynamicBuffer_v1, RegEx, ReadHandler>& h,
1532       const DefaultCandidate& c) noexcept
1533     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1534   {
1535     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1536   }
1537 };
1538 
1539 #endif // !defined(GENERATING_DOCUMENTATION)
1540 
1541 template <typename AsyncReadStream, typename DynamicBuffer_v1, typename Traits,
1542     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1543       std::size_t)) ReadToken>
1544 inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v1&& buffers,
1545     const boost::basic_regex<char, Traits>& expr, ReadToken&& token,
1546     constraint_t<
1547       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
1548     >,
1549     constraint_t<
1550       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
1551     >)
1552   -> decltype(
1553     async_initiate<ReadToken,
1554       void (boost::system::error_code, std::size_t)>(
1555         declval<detail::initiate_async_read_until_expr_v1<AsyncReadStream>>(),
1556         token, static_cast<DynamicBuffer_v1&&>(buffers), expr))
1557 {
1558   return async_initiate<ReadToken,
1559     void (boost::system::error_code, std::size_t)>(
1560       detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s),
1561       token, static_cast<DynamicBuffer_v1&&>(buffers), expr);
1562 }
1563 
1564 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1565 
1566 namespace detail
1567 {
1568   template <typename AsyncReadStream, typename DynamicBuffer_v1,
1569       typename MatchCondition, typename ReadHandler>
1570   class read_until_match_op_v1
1571     : public base_from_cancellation_state<ReadHandler>
1572   {
1573   public:
1574     template <typename BufferSequence>
1575     read_until_match_op_v1(AsyncReadStream& stream,
1576         BufferSequence&& buffers,
1577         MatchCondition match_condition, ReadHandler& handler)
1578       : base_from_cancellation_state<ReadHandler>(
1579           handler, enable_partial_cancellation()),
1580         stream_(stream),
1581         buffers_(static_cast<BufferSequence&&>(buffers)),
1582         match_condition_(match_condition),
1583         start_(0),
1584         search_position_(0),
1585         handler_(static_cast<ReadHandler&&>(handler))
1586     {
1587     }
1588 
1589     read_until_match_op_v1(const read_until_match_op_v1& other)
1590       : base_from_cancellation_state<ReadHandler>(other),
1591         stream_(other.stream_),
1592         buffers_(other.buffers_),
1593         match_condition_(other.match_condition_),
1594         start_(other.start_),
1595         search_position_(other.search_position_),
1596         handler_(other.handler_)
1597     {
1598     }
1599 
1600     read_until_match_op_v1(read_until_match_op_v1&& other)
1601       : base_from_cancellation_state<ReadHandler>(
1602           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1603         stream_(other.stream_),
1604         buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
1605         match_condition_(other.match_condition_),
1606         start_(other.start_),
1607         search_position_(other.search_position_),
1608         handler_(static_cast<ReadHandler&&>(other.handler_))
1609     {
1610     }
1611 
1612     void operator()(boost::system::error_code ec,
1613         std::size_t bytes_transferred, int start = 0)
1614     {
1615       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1616       std::size_t bytes_to_read;
1617       switch (start_ = start)
1618       {
1619       case 1:
1620         for (;;)
1621         {
1622           {
1623             // Determine the range of the data to be searched.
1624             typedef typename DynamicBuffer_v1::const_buffers_type
1625               buffers_type;
1626             typedef buffers_iterator<buffers_type> iterator;
1627             buffers_type data_buffers = buffers_.data();
1628             iterator begin = iterator::begin(data_buffers);
1629             iterator start_pos = begin + search_position_;
1630             iterator end = iterator::end(data_buffers);
1631 
1632             // Look for a match.
1633             std::pair<iterator, bool> result = match_condition_(start_pos, end);
1634             if (result.second)
1635             {
1636               // Full match. We're done.
1637               search_position_ = result.first - begin;
1638               bytes_to_read = 0;
1639             }
1640 
1641             // No match yet. Check if buffer is full.
1642             else if (buffers_.size() == buffers_.max_size())
1643             {
1644               search_position_ = not_found;
1645               bytes_to_read = 0;
1646             }
1647 
1648             // Need to read some more data.
1649             else
1650             {
1651               if (result.first != end)
1652               {
1653                 // Partial match. Next search needs to start from beginning of
1654                 // match.
1655                 search_position_ = result.first - begin;
1656               }
1657               else
1658               {
1659                 // Next search can start with the new data.
1660                 search_position_ = end - begin;
1661               }
1662 
1663               bytes_to_read = std::min<std::size_t>(
1664                     std::max<std::size_t>(512,
1665                       buffers_.capacity() - buffers_.size()),
1666                     std::min<std::size_t>(65536,
1667                       buffers_.max_size() - buffers_.size()));
1668             }
1669           }
1670 
1671           // Check if we're done.
1672           if (!start && bytes_to_read == 0)
1673             break;
1674 
1675           // Start a new asynchronous read operation to obtain more data.
1676           {
1677             BOOST_ASIO_HANDLER_LOCATION((
1678                   __FILE__, __LINE__, "async_read_until"));
1679             stream_.async_read_some(buffers_.prepare(bytes_to_read),
1680                 static_cast<read_until_match_op_v1&&>(*this));
1681           }
1682           return; default:
1683           buffers_.commit(bytes_transferred);
1684           if (ec || bytes_transferred == 0)
1685             break;
1686           if (this->cancelled() != cancellation_type::none)
1687           {
1688             ec = error::operation_aborted;
1689             break;
1690           }
1691         }
1692 
1693         const boost::system::error_code result_ec =
1694           (search_position_ == not_found)
1695           ? error::not_found : ec;
1696 
1697         const std::size_t result_n =
1698           (ec || search_position_ == not_found)
1699           ? 0 : search_position_;
1700 
1701         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
1702       }
1703     }
1704 
1705   //private:
1706     AsyncReadStream& stream_;
1707     DynamicBuffer_v1 buffers_;
1708     MatchCondition match_condition_;
1709     int start_;
1710     std::size_t search_position_;
1711     ReadHandler handler_;
1712   };
1713 
1714   template <typename AsyncReadStream, typename DynamicBuffer_v1,
1715       typename MatchCondition, typename ReadHandler>
1716   inline bool asio_handler_is_continuation(
1717       read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
1718         MatchCondition, ReadHandler>* this_handler)
1719   {
1720     return this_handler->start_ == 0 ? true
1721       : boost_asio_handler_cont_helpers::is_continuation(
1722           this_handler->handler_);
1723   }
1724 
1725   template <typename AsyncReadStream>
1726   class initiate_async_read_until_match_v1
1727   {
1728   public:
1729     typedef typename AsyncReadStream::executor_type executor_type;
1730 
1731     explicit initiate_async_read_until_match_v1(AsyncReadStream& stream)
1732       : stream_(stream)
1733     {
1734     }
1735 
1736     executor_type get_executor() const noexcept
1737     {
1738       return stream_.get_executor();
1739     }
1740 
1741     template <typename ReadHandler,
1742         typename DynamicBuffer_v1, typename MatchCondition>
1743     void operator()(ReadHandler&& handler,
1744         DynamicBuffer_v1&& buffers,
1745         MatchCondition match_condition) const
1746     {
1747       // If you get an error on the following line it means that your handler
1748       // does not meet the documented type requirements for a ReadHandler.
1749       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1750 
1751       non_const_lvalue<ReadHandler> handler2(handler);
1752       read_until_match_op_v1<AsyncReadStream,
1753         decay_t<DynamicBuffer_v1>,
1754           MatchCondition, decay_t<ReadHandler>>(
1755             stream_, static_cast<DynamicBuffer_v1&&>(buffers),
1756             match_condition, handler2.value)(boost::system::error_code(), 0, 1);
1757     }
1758 
1759   private:
1760     AsyncReadStream& stream_;
1761   };
1762 } // namespace detail
1763 
1764 #if !defined(GENERATING_DOCUMENTATION)
1765 
1766 template <template <typename, typename> class Associator,
1767     typename AsyncReadStream, typename DynamicBuffer_v1,
1768     typename MatchCondition, typename ReadHandler, typename DefaultCandidate>
1769 struct associator<Associator,
1770     detail::read_until_match_op_v1<AsyncReadStream,
1771       DynamicBuffer_v1, MatchCondition, ReadHandler>,
1772     DefaultCandidate>
1773   : Associator<ReadHandler, DefaultCandidate>
1774 {
1775   static typename Associator<ReadHandler, DefaultCandidate>::type get(
1776       const detail::read_until_match_op_v1<AsyncReadStream,
1777         DynamicBuffer_v1, MatchCondition, ReadHandler>& h) noexcept
1778   {
1779     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1780   }
1781 
1782   static auto get(
1783       const detail::read_until_match_op_v1<AsyncReadStream,
1784         DynamicBuffer_v1, MatchCondition, ReadHandler>& h,
1785       const DefaultCandidate& c) noexcept
1786     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1787   {
1788     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1789   }
1790 };
1791 
1792 #endif // !defined(GENERATING_DOCUMENTATION)
1793 
1794 template <typename AsyncReadStream,
1795     typename DynamicBuffer_v1, typename MatchCondition,
1796     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1797       std::size_t)) ReadToken>
1798 inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v1&& buffers,
1799     MatchCondition match_condition, ReadToken&& token,
1800     constraint_t<
1801       is_match_condition<MatchCondition>::value
1802     >,
1803     constraint_t<
1804       is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
1805     >,
1806     constraint_t<
1807       !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
1808     >)
1809   -> decltype(
1810     async_initiate<ReadToken,
1811       void (boost::system::error_code, std::size_t)>(
1812         declval<detail::initiate_async_read_until_match_v1<AsyncReadStream>>(),
1813         token, static_cast<DynamicBuffer_v1&&>(buffers),
1814         match_condition))
1815 {
1816   return async_initiate<ReadToken,
1817     void (boost::system::error_code, std::size_t)>(
1818       detail::initiate_async_read_until_match_v1<AsyncReadStream>(s),
1819       token, static_cast<DynamicBuffer_v1&&>(buffers),
1820       match_condition);
1821 }
1822 
1823 #if !defined(BOOST_ASIO_NO_IOSTREAM)
1824 
1825 template <typename AsyncReadStream, typename Allocator,
1826     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1827       std::size_t)) ReadToken>
1828 inline auto async_read_until(AsyncReadStream& s,
1829     boost::asio::basic_streambuf<Allocator>& b, char delim, ReadToken&& token)
1830   -> decltype(
1831     async_initiate<ReadToken,
1832       void (boost::system::error_code, std::size_t)>(
1833         declval<detail::initiate_async_read_until_delim_v1<AsyncReadStream>>(),
1834         token, basic_streambuf_ref<Allocator>(b), delim))
1835 {
1836   return async_initiate<ReadToken,
1837     void (boost::system::error_code, std::size_t)>(
1838       detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s),
1839       token, basic_streambuf_ref<Allocator>(b), delim);
1840 }
1841 
1842 template <typename AsyncReadStream, typename Allocator,
1843     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1844       std::size_t)) ReadToken>
1845 inline auto async_read_until(AsyncReadStream& s,
1846     boost::asio::basic_streambuf<Allocator>& b,
1847     BOOST_ASIO_STRING_VIEW_PARAM delim, ReadToken&& token)
1848   -> decltype(
1849     async_initiate<ReadToken,
1850       void (boost::system::error_code, std::size_t)>(
1851         declval<detail::initiate_async_read_until_delim_string_v1<
1852           AsyncReadStream>>(),
1853         token, basic_streambuf_ref<Allocator>(b),
1854         static_cast<std::string>(delim)))
1855 {
1856   return async_initiate<ReadToken,
1857     void (boost::system::error_code, std::size_t)>(
1858       detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s),
1859       token, basic_streambuf_ref<Allocator>(b),
1860       static_cast<std::string>(delim));
1861 }
1862 
1863 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
1864 
1865 template <typename AsyncReadStream, typename Allocator, typename Traits,
1866     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1867       std::size_t)) ReadToken>
1868 inline auto async_read_until(AsyncReadStream& s,
1869     boost::asio::basic_streambuf<Allocator>& b,
1870     const boost::basic_regex<char, Traits>& expr, ReadToken&& token)
1871   -> decltype(
1872     async_initiate<ReadToken,
1873       void (boost::system::error_code, std::size_t)>(
1874         declval<detail::initiate_async_read_until_expr_v1<AsyncReadStream>>(),
1875         token, basic_streambuf_ref<Allocator>(b), expr))
1876 {
1877   return async_initiate<ReadToken,
1878     void (boost::system::error_code, std::size_t)>(
1879       detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s),
1880       token, basic_streambuf_ref<Allocator>(b), expr);
1881 }
1882 
1883 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1884 
1885 template <typename AsyncReadStream, typename Allocator, typename MatchCondition,
1886     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1887       std::size_t)) ReadToken>
1888 inline auto async_read_until(AsyncReadStream& s,
1889     boost::asio::basic_streambuf<Allocator>& b,
1890     MatchCondition match_condition, ReadToken&& token,
1891     constraint_t<is_match_condition<MatchCondition>::value>)
1892   -> decltype(
1893     async_initiate<ReadToken,
1894       void (boost::system::error_code, std::size_t)>(
1895         declval<detail::initiate_async_read_until_match_v1<AsyncReadStream>>(),
1896         token, basic_streambuf_ref<Allocator>(b), match_condition))
1897 {
1898   return async_initiate<ReadToken,
1899     void (boost::system::error_code, std::size_t)>(
1900       detail::initiate_async_read_until_match_v1<AsyncReadStream>(s),
1901       token, basic_streambuf_ref<Allocator>(b), match_condition);
1902 }
1903 
1904 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
1905 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
1906 #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
1907 
1908 namespace detail
1909 {
1910   template <typename AsyncReadStream,
1911       typename DynamicBuffer_v2, typename ReadHandler>
1912   class read_until_delim_op_v2
1913     : public base_from_cancellation_state<ReadHandler>
1914   {
1915   public:
1916     template <typename BufferSequence>
1917     read_until_delim_op_v2(AsyncReadStream& stream,
1918         BufferSequence&& buffers,
1919         char delim, ReadHandler& handler)
1920       : base_from_cancellation_state<ReadHandler>(
1921           handler, enable_partial_cancellation()),
1922         stream_(stream),
1923         buffers_(static_cast<BufferSequence&&>(buffers)),
1924         delim_(delim),
1925         start_(0),
1926         search_position_(0),
1927         bytes_to_read_(0),
1928         handler_(static_cast<ReadHandler&&>(handler))
1929     {
1930     }
1931 
1932     read_until_delim_op_v2(const read_until_delim_op_v2& other)
1933       : base_from_cancellation_state<ReadHandler>(other),
1934         stream_(other.stream_),
1935         buffers_(other.buffers_),
1936         delim_(other.delim_),
1937         start_(other.start_),
1938         search_position_(other.search_position_),
1939         bytes_to_read_(other.bytes_to_read_),
1940         handler_(other.handler_)
1941     {
1942     }
1943 
1944     read_until_delim_op_v2(read_until_delim_op_v2&& other)
1945       : base_from_cancellation_state<ReadHandler>(
1946           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1947         stream_(other.stream_),
1948         buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
1949         delim_(other.delim_),
1950         start_(other.start_),
1951         search_position_(other.search_position_),
1952         bytes_to_read_(other.bytes_to_read_),
1953         handler_(static_cast<ReadHandler&&>(other.handler_))
1954     {
1955     }
1956 
1957     void operator()(boost::system::error_code ec,
1958         std::size_t bytes_transferred, int start = 0)
1959     {
1960       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1961       std::size_t pos;
1962       switch (start_ = start)
1963       {
1964       case 1:
1965         for (;;)
1966         {
1967           {
1968             // Determine the range of the data to be searched.
1969             typedef typename DynamicBuffer_v2::const_buffers_type
1970               buffers_type;
1971             typedef buffers_iterator<buffers_type> iterator;
1972             buffers_type data_buffers =
1973               const_cast<const DynamicBuffer_v2&>(buffers_).data(
1974                   0, buffers_.size());
1975             iterator begin = iterator::begin(data_buffers);
1976             iterator start_pos = begin + search_position_;
1977             iterator end = iterator::end(data_buffers);
1978 
1979             // Look for a match.
1980             iterator iter = std::find(start_pos, end, delim_);
1981             if (iter != end)
1982             {
1983               // Found a match. We're done.
1984               search_position_ = iter - begin + 1;
1985               bytes_to_read_ = 0;
1986             }
1987 
1988             // No match yet. Check if buffer is full.
1989             else if (buffers_.size() == buffers_.max_size())
1990             {
1991               search_position_ = not_found;
1992               bytes_to_read_ = 0;
1993             }
1994 
1995             // Need to read some more data.
1996             else
1997             {
1998               // Next search can start with the new data.
1999               search_position_ = end - begin;
2000               bytes_to_read_ = std::min<std::size_t>(
2001                     std::max<std::size_t>(512,
2002                       buffers_.capacity() - buffers_.size()),
2003                     std::min<std::size_t>(65536,
2004                       buffers_.max_size() - buffers_.size()));
2005             }
2006           }
2007 
2008           // Check if we're done.
2009           if (!start && bytes_to_read_ == 0)
2010             break;
2011 
2012           // Start a new asynchronous read operation to obtain more data.
2013           pos = buffers_.size();
2014           buffers_.grow(bytes_to_read_);
2015           {
2016             BOOST_ASIO_HANDLER_LOCATION((
2017                   __FILE__, __LINE__, "async_read_until"));
2018             stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2019                 static_cast<read_until_delim_op_v2&&>(*this));
2020           }
2021           return; default:
2022           buffers_.shrink(bytes_to_read_ - bytes_transferred);
2023           if (ec || bytes_transferred == 0)
2024             break;
2025           if (this->cancelled() != cancellation_type::none)
2026           {
2027             ec = error::operation_aborted;
2028             break;
2029           }
2030         }
2031 
2032         const boost::system::error_code result_ec =
2033           (search_position_ == not_found)
2034           ? error::not_found : ec;
2035 
2036         const std::size_t result_n =
2037           (ec || search_position_ == not_found)
2038           ? 0 : search_position_;
2039 
2040         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
2041       }
2042     }
2043 
2044   //private:
2045     AsyncReadStream& stream_;
2046     DynamicBuffer_v2 buffers_;
2047     char delim_;
2048     int start_;
2049     std::size_t search_position_;
2050     std::size_t bytes_to_read_;
2051     ReadHandler handler_;
2052   };
2053 
2054   template <typename AsyncReadStream,
2055       typename DynamicBuffer_v2, typename ReadHandler>
2056   inline bool asio_handler_is_continuation(
2057       read_until_delim_op_v2<AsyncReadStream,
2058         DynamicBuffer_v2, ReadHandler>* this_handler)
2059   {
2060     return this_handler->start_ == 0 ? true
2061       : boost_asio_handler_cont_helpers::is_continuation(
2062           this_handler->handler_);
2063   }
2064 
2065   template <typename AsyncReadStream>
2066   class initiate_async_read_until_delim_v2
2067   {
2068   public:
2069     typedef typename AsyncReadStream::executor_type executor_type;
2070 
2071     explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream)
2072       : stream_(stream)
2073     {
2074     }
2075 
2076     executor_type get_executor() const noexcept
2077     {
2078       return stream_.get_executor();
2079     }
2080 
2081     template <typename ReadHandler, typename DynamicBuffer_v2>
2082     void operator()(ReadHandler&& handler,
2083         DynamicBuffer_v2&& buffers, char delim) const
2084     {
2085       // If you get an error on the following line it means that your handler
2086       // does not meet the documented type requirements for a ReadHandler.
2087       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2088 
2089       non_const_lvalue<ReadHandler> handler2(handler);
2090       read_until_delim_op_v2<AsyncReadStream,
2091         decay_t<DynamicBuffer_v2>,
2092           decay_t<ReadHandler>>(
2093             stream_, static_cast<DynamicBuffer_v2&&>(buffers),
2094             delim, handler2.value)(boost::system::error_code(), 0, 1);
2095     }
2096 
2097   private:
2098     AsyncReadStream& stream_;
2099   };
2100 } // namespace detail
2101 
2102 #if !defined(GENERATING_DOCUMENTATION)
2103 
2104 template <template <typename, typename> class Associator,
2105     typename AsyncReadStream, typename DynamicBuffer_v2,
2106     typename ReadHandler, typename DefaultCandidate>
2107 struct associator<Associator,
2108     detail::read_until_delim_op_v2<AsyncReadStream,
2109       DynamicBuffer_v2, ReadHandler>,
2110     DefaultCandidate>
2111   : Associator<ReadHandler, DefaultCandidate>
2112 {
2113   static typename Associator<ReadHandler, DefaultCandidate>::type get(
2114       const detail::read_until_delim_op_v2<AsyncReadStream,
2115         DynamicBuffer_v2, ReadHandler>& h) noexcept
2116   {
2117     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
2118   }
2119 
2120   static auto get(
2121       const detail::read_until_delim_op_v2<AsyncReadStream,
2122         DynamicBuffer_v2, ReadHandler>& h,
2123       const DefaultCandidate& c) noexcept
2124     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
2125   {
2126     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
2127   }
2128 };
2129 
2130 #endif // !defined(GENERATING_DOCUMENTATION)
2131 
2132 template <typename AsyncReadStream, typename DynamicBuffer_v2,
2133     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
2134       std::size_t)) ReadToken>
2135 inline auto async_read_until(AsyncReadStream& s,
2136     DynamicBuffer_v2 buffers, char delim, ReadToken&& token,
2137     constraint_t<
2138       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
2139     >)
2140   -> decltype(
2141     async_initiate<ReadToken,
2142       void (boost::system::error_code, std::size_t)>(
2143         declval<detail::initiate_async_read_until_delim_v2<AsyncReadStream>>(),
2144         token, static_cast<DynamicBuffer_v2&&>(buffers), delim))
2145 {
2146   return async_initiate<ReadToken,
2147     void (boost::system::error_code, std::size_t)>(
2148       detail::initiate_async_read_until_delim_v2<AsyncReadStream>(s),
2149       token, static_cast<DynamicBuffer_v2&&>(buffers), delim);
2150 }
2151 
2152 namespace detail
2153 {
2154   template <typename AsyncReadStream,
2155       typename DynamicBuffer_v2, typename ReadHandler>
2156   class read_until_delim_string_op_v2
2157     : public base_from_cancellation_state<ReadHandler>
2158   {
2159   public:
2160     template <typename BufferSequence>
2161     read_until_delim_string_op_v2(AsyncReadStream& stream,
2162         BufferSequence&& buffers,
2163         const std::string& delim, ReadHandler& handler)
2164       : base_from_cancellation_state<ReadHandler>(
2165           handler, enable_partial_cancellation()),
2166         stream_(stream),
2167         buffers_(static_cast<BufferSequence&&>(buffers)),
2168         delim_(delim),
2169         start_(0),
2170         search_position_(0),
2171         bytes_to_read_(0),
2172         handler_(static_cast<ReadHandler&&>(handler))
2173     {
2174     }
2175 
2176     read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other)
2177       : base_from_cancellation_state<ReadHandler>(other),
2178         stream_(other.stream_),
2179         buffers_(other.buffers_),
2180         delim_(other.delim_),
2181         start_(other.start_),
2182         search_position_(other.search_position_),
2183         bytes_to_read_(other.bytes_to_read_),
2184         handler_(other.handler_)
2185     {
2186     }
2187 
2188     read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other)
2189       : base_from_cancellation_state<ReadHandler>(
2190           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
2191         stream_(other.stream_),
2192         buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
2193         delim_(static_cast<std::string&&>(other.delim_)),
2194         start_(other.start_),
2195         search_position_(other.search_position_),
2196         bytes_to_read_(other.bytes_to_read_),
2197         handler_(static_cast<ReadHandler&&>(other.handler_))
2198     {
2199     }
2200 
2201     void operator()(boost::system::error_code ec,
2202         std::size_t bytes_transferred, int start = 0)
2203     {
2204       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
2205       std::size_t pos;
2206       switch (start_ = start)
2207       {
2208       case 1:
2209         for (;;)
2210         {
2211           {
2212             // Determine the range of the data to be searched.
2213             typedef typename DynamicBuffer_v2::const_buffers_type
2214               buffers_type;
2215             typedef buffers_iterator<buffers_type> iterator;
2216             buffers_type data_buffers =
2217               const_cast<const DynamicBuffer_v2&>(buffers_).data(
2218                   0, buffers_.size());
2219             iterator begin = iterator::begin(data_buffers);
2220             iterator start_pos = begin + search_position_;
2221             iterator end = iterator::end(data_buffers);
2222 
2223             // Look for a match.
2224             std::pair<iterator, bool> result = detail::partial_search(
2225                 start_pos, end, delim_.begin(), delim_.end());
2226             if (result.first != end && result.second)
2227             {
2228               // Full match. We're done.
2229               search_position_ = result.first - begin + delim_.length();
2230               bytes_to_read_ = 0;
2231             }
2232 
2233             // No match yet. Check if buffer is full.
2234             else if (buffers_.size() == buffers_.max_size())
2235             {
2236               search_position_ = not_found;
2237               bytes_to_read_ = 0;
2238             }
2239 
2240             // Need to read some more data.
2241             else
2242             {
2243               if (result.first != end)
2244               {
2245                 // Partial match. Next search needs to start from beginning of
2246                 // match.
2247                 search_position_ = result.first - begin;
2248               }
2249               else
2250               {
2251                 // Next search can start with the new data.
2252                 search_position_ = end - begin;
2253               }
2254 
2255               bytes_to_read_ = std::min<std::size_t>(
2256                     std::max<std::size_t>(512,
2257                       buffers_.capacity() - buffers_.size()),
2258                     std::min<std::size_t>(65536,
2259                       buffers_.max_size() - buffers_.size()));
2260             }
2261           }
2262 
2263           // Check if we're done.
2264           if (!start && bytes_to_read_ == 0)
2265             break;
2266 
2267           // Start a new asynchronous read operation to obtain more data.
2268           pos = buffers_.size();
2269           buffers_.grow(bytes_to_read_);
2270           {
2271             BOOST_ASIO_HANDLER_LOCATION((
2272                   __FILE__, __LINE__, "async_read_until"));
2273             stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2274                 static_cast<read_until_delim_string_op_v2&&>(*this));
2275           }
2276           return; default:
2277           buffers_.shrink(bytes_to_read_ - bytes_transferred);
2278           if (ec || bytes_transferred == 0)
2279             break;
2280           if (this->cancelled() != cancellation_type::none)
2281           {
2282             ec = error::operation_aborted;
2283             break;
2284           }
2285         }
2286 
2287         const boost::system::error_code result_ec =
2288           (search_position_ == not_found)
2289           ? error::not_found : ec;
2290 
2291         const std::size_t result_n =
2292           (ec || search_position_ == not_found)
2293           ? 0 : search_position_;
2294 
2295         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
2296       }
2297     }
2298 
2299   //private:
2300     AsyncReadStream& stream_;
2301     DynamicBuffer_v2 buffers_;
2302     std::string delim_;
2303     int start_;
2304     std::size_t search_position_;
2305     std::size_t bytes_to_read_;
2306     ReadHandler handler_;
2307   };
2308 
2309   template <typename AsyncReadStream,
2310       typename DynamicBuffer_v2, typename ReadHandler>
2311   inline bool asio_handler_is_continuation(
2312       read_until_delim_string_op_v2<AsyncReadStream,
2313         DynamicBuffer_v2, ReadHandler>* this_handler)
2314   {
2315     return this_handler->start_ == 0 ? true
2316       : boost_asio_handler_cont_helpers::is_continuation(
2317           this_handler->handler_);
2318   }
2319 
2320   template <typename AsyncReadStream>
2321   class initiate_async_read_until_delim_string_v2
2322   {
2323   public:
2324     typedef typename AsyncReadStream::executor_type executor_type;
2325 
2326     explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream)
2327       : stream_(stream)
2328     {
2329     }
2330 
2331     executor_type get_executor() const noexcept
2332     {
2333       return stream_.get_executor();
2334     }
2335 
2336     template <typename ReadHandler, typename DynamicBuffer_v2>
2337     void operator()(ReadHandler&& handler,
2338         DynamicBuffer_v2&& buffers,
2339         const std::string& delim) const
2340     {
2341       // If you get an error on the following line it means that your handler
2342       // does not meet the documented type requirements for a ReadHandler.
2343       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2344 
2345       non_const_lvalue<ReadHandler> handler2(handler);
2346       read_until_delim_string_op_v2<AsyncReadStream,
2347         decay_t<DynamicBuffer_v2>,
2348           decay_t<ReadHandler>>(
2349             stream_, static_cast<DynamicBuffer_v2&&>(buffers),
2350             delim, handler2.value)(boost::system::error_code(), 0, 1);
2351     }
2352 
2353   private:
2354     AsyncReadStream& stream_;
2355   };
2356 } // namespace detail
2357 
2358 #if !defined(GENERATING_DOCUMENTATION)
2359 
2360 template <template <typename, typename> class Associator,
2361     typename AsyncReadStream, typename DynamicBuffer_v2,
2362     typename ReadHandler, typename DefaultCandidate>
2363 struct associator<Associator,
2364     detail::read_until_delim_string_op_v2<AsyncReadStream,
2365       DynamicBuffer_v2, ReadHandler>,
2366     DefaultCandidate>
2367   : Associator<ReadHandler, DefaultCandidate>
2368 {
2369   static typename Associator<ReadHandler, DefaultCandidate>::type get(
2370       const detail::read_until_delim_string_op_v2<
2371         AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h) noexcept
2372   {
2373     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
2374   }
2375 
2376   static auto get(
2377       const detail::read_until_delim_string_op_v2<
2378         AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h,
2379       const DefaultCandidate& c) noexcept
2380     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
2381   {
2382     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
2383   }
2384 };
2385 
2386 #endif // !defined(GENERATING_DOCUMENTATION)
2387 
2388 template <typename AsyncReadStream,
2389     typename DynamicBuffer_v2,
2390     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
2391       std::size_t)) ReadToken>
2392 inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
2393     BOOST_ASIO_STRING_VIEW_PARAM delim, ReadToken&& token,
2394     constraint_t<
2395       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
2396     >)
2397   -> decltype(
2398     async_initiate<ReadToken,
2399       void (boost::system::error_code, std::size_t)>(
2400         declval<detail::initiate_async_read_until_delim_string_v2<
2401           AsyncReadStream>>(),
2402         token, static_cast<DynamicBuffer_v2&&>(buffers),
2403         static_cast<std::string>(delim)))
2404 {
2405   return async_initiate<ReadToken,
2406     void (boost::system::error_code, std::size_t)>(
2407       detail::initiate_async_read_until_delim_string_v2<AsyncReadStream>(s),
2408       token, static_cast<DynamicBuffer_v2&&>(buffers),
2409       static_cast<std::string>(delim));
2410 }
2411 
2412 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
2413 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
2414 
2415 namespace detail
2416 {
2417   template <typename AsyncReadStream, typename DynamicBuffer_v2,
2418       typename RegEx, typename ReadHandler>
2419   class read_until_expr_op_v2
2420     : public base_from_cancellation_state<ReadHandler>
2421   {
2422   public:
2423     template <typename BufferSequence, typename Traits>
2424     read_until_expr_op_v2(AsyncReadStream& stream, BufferSequence&& buffers,
2425         const boost::basic_regex<char, Traits>& expr, ReadHandler& handler)
2426       : base_from_cancellation_state<ReadHandler>(
2427           handler, enable_partial_cancellation()),
2428         stream_(stream),
2429         buffers_(static_cast<BufferSequence&&>(buffers)),
2430         expr_(expr),
2431         start_(0),
2432         search_position_(0),
2433         bytes_to_read_(0),
2434         handler_(static_cast<ReadHandler&&>(handler))
2435     {
2436     }
2437 
2438     read_until_expr_op_v2(const read_until_expr_op_v2& other)
2439       : base_from_cancellation_state<ReadHandler>(other),
2440         stream_(other.stream_),
2441         buffers_(other.buffers_),
2442         expr_(other.expr_),
2443         start_(other.start_),
2444         search_position_(other.search_position_),
2445         bytes_to_read_(other.bytes_to_read_),
2446         handler_(other.handler_)
2447     {
2448     }
2449 
2450     read_until_expr_op_v2(read_until_expr_op_v2&& other)
2451       : base_from_cancellation_state<ReadHandler>(
2452           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
2453         stream_(other.stream_),
2454         buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
2455         expr_(other.expr_),
2456         start_(other.start_),
2457         search_position_(other.search_position_),
2458         bytes_to_read_(other.bytes_to_read_),
2459         handler_(static_cast<ReadHandler&&>(other.handler_))
2460     {
2461     }
2462 
2463     void operator()(boost::system::error_code ec,
2464         std::size_t bytes_transferred, int start = 0)
2465     {
2466       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
2467       std::size_t pos;
2468       switch (start_ = start)
2469       {
2470       case 1:
2471         for (;;)
2472         {
2473           {
2474             // Determine the range of the data to be searched.
2475             typedef typename DynamicBuffer_v2::const_buffers_type
2476               buffers_type;
2477             typedef buffers_iterator<buffers_type> iterator;
2478             buffers_type data_buffers =
2479               const_cast<const DynamicBuffer_v2&>(buffers_).data(
2480                   0, buffers_.size());
2481             iterator begin = iterator::begin(data_buffers);
2482             iterator start_pos = begin + search_position_;
2483             iterator end = iterator::end(data_buffers);
2484 
2485             // Look for a match.
2486             boost::match_results<iterator,
2487               typename std::vector<boost::sub_match<iterator>>::allocator_type>
2488                 match_results;
2489             bool match = regex_search(start_pos, end,
2490                 match_results, expr_, regex_match_flags());
2491             if (match && match_results[0].matched)
2492             {
2493               // Full match. We're done.
2494               search_position_ = match_results[0].second - begin;
2495               bytes_to_read_ = 0;
2496             }
2497 
2498             // No match yet. Check if buffer is full.
2499             else if (buffers_.size() == buffers_.max_size())
2500             {
2501               search_position_ = not_found;
2502               bytes_to_read_ = 0;
2503             }
2504 
2505             // Need to read some more data.
2506             else
2507             {
2508               if (match)
2509               {
2510                 // Partial match. Next search needs to start from beginning of
2511                 // match.
2512                 search_position_ = match_results[0].first - begin;
2513               }
2514               else
2515               {
2516                 // Next search can start with the new data.
2517                 search_position_ = end - begin;
2518               }
2519 
2520               bytes_to_read_ = std::min<std::size_t>(
2521                     std::max<std::size_t>(512,
2522                       buffers_.capacity() - buffers_.size()),
2523                     std::min<std::size_t>(65536,
2524                       buffers_.max_size() - buffers_.size()));
2525             }
2526           }
2527 
2528           // Check if we're done.
2529           if (!start && bytes_to_read_ == 0)
2530             break;
2531 
2532           // Start a new asynchronous read operation to obtain more data.
2533           pos = buffers_.size();
2534           buffers_.grow(bytes_to_read_);
2535           {
2536             BOOST_ASIO_HANDLER_LOCATION((
2537                   __FILE__, __LINE__, "async_read_until"));
2538             stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2539                 static_cast<read_until_expr_op_v2&&>(*this));
2540           }
2541           return; default:
2542           buffers_.shrink(bytes_to_read_ - bytes_transferred);
2543           if (ec || bytes_transferred == 0)
2544             break;
2545           if (this->cancelled() != cancellation_type::none)
2546           {
2547             ec = error::operation_aborted;
2548             break;
2549           }
2550         }
2551 
2552         const boost::system::error_code result_ec =
2553           (search_position_ == not_found)
2554           ? error::not_found : ec;
2555 
2556         const std::size_t result_n =
2557           (ec || search_position_ == not_found)
2558           ? 0 : search_position_;
2559 
2560         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
2561       }
2562     }
2563 
2564   //private:
2565     AsyncReadStream& stream_;
2566     DynamicBuffer_v2 buffers_;
2567     RegEx expr_;
2568     int start_;
2569     std::size_t search_position_;
2570     std::size_t bytes_to_read_;
2571     ReadHandler handler_;
2572   };
2573 
2574   template <typename AsyncReadStream, typename DynamicBuffer_v2,
2575       typename RegEx, typename ReadHandler>
2576   inline bool asio_handler_is_continuation(
2577       read_until_expr_op_v2<AsyncReadStream,
2578         DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
2579   {
2580     return this_handler->start_ == 0 ? true
2581       : boost_asio_handler_cont_helpers::is_continuation(
2582           this_handler->handler_);
2583   }
2584 
2585   template <typename AsyncReadStream>
2586   class initiate_async_read_until_expr_v2
2587   {
2588   public:
2589     typedef typename AsyncReadStream::executor_type executor_type;
2590 
2591     explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream)
2592       : stream_(stream)
2593     {
2594     }
2595 
2596     executor_type get_executor() const noexcept
2597     {
2598       return stream_.get_executor();
2599     }
2600 
2601     template <typename ReadHandler, typename DynamicBuffer_v2, typename RegEx>
2602     void operator()(ReadHandler&& handler,
2603         DynamicBuffer_v2&& buffers,
2604         const RegEx& expr) const
2605     {
2606       // If you get an error on the following line it means that your handler
2607       // does not meet the documented type requirements for a ReadHandler.
2608       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2609 
2610       non_const_lvalue<ReadHandler> handler2(handler);
2611       read_until_expr_op_v2<AsyncReadStream,
2612         decay_t<DynamicBuffer_v2>,
2613           RegEx, decay_t<ReadHandler>>(
2614             stream_, static_cast<DynamicBuffer_v2&&>(buffers),
2615             expr, handler2.value)(boost::system::error_code(), 0, 1);
2616     }
2617 
2618   private:
2619     AsyncReadStream& stream_;
2620   };
2621 } // namespace detail
2622 
2623 #if !defined(GENERATING_DOCUMENTATION)
2624 
2625 template <template <typename, typename> class Associator,
2626     typename AsyncReadStream, typename DynamicBuffer_v2,
2627     typename RegEx, typename ReadHandler, typename DefaultCandidate>
2628 struct associator<Associator,
2629     detail::read_until_expr_op_v2<AsyncReadStream,
2630       DynamicBuffer_v2, RegEx, ReadHandler>,
2631     DefaultCandidate>
2632   : Associator<ReadHandler, DefaultCandidate>
2633 {
2634   static typename Associator<ReadHandler, DefaultCandidate>::type get(
2635       const detail::read_until_expr_op_v2<AsyncReadStream,
2636         DynamicBuffer_v2, RegEx, ReadHandler>& h) noexcept
2637   {
2638     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
2639   }
2640 
2641   static auto get(
2642       const detail::read_until_expr_op_v2<AsyncReadStream,
2643         DynamicBuffer_v2, RegEx, ReadHandler>& h,
2644       const DefaultCandidate& c) noexcept
2645     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
2646   {
2647     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
2648   }
2649 };
2650 
2651 #endif // !defined(GENERATING_DOCUMENTATION)
2652 
2653 template <typename AsyncReadStream, typename DynamicBuffer_v2, typename Traits,
2654     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
2655       std::size_t)) ReadToken>
2656 inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
2657     const boost::basic_regex<char, Traits>& expr, ReadToken&& token,
2658     constraint_t<
2659       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
2660     >)
2661   -> decltype(
2662     async_initiate<ReadToken,
2663       void (boost::system::error_code, std::size_t)>(
2664         declval<detail::initiate_async_read_until_expr_v2<AsyncReadStream>>(),
2665         token, static_cast<DynamicBuffer_v2&&>(buffers), expr))
2666 {
2667   return async_initiate<ReadToken,
2668     void (boost::system::error_code, std::size_t)>(
2669       detail::initiate_async_read_until_expr_v2<AsyncReadStream>(s),
2670       token, static_cast<DynamicBuffer_v2&&>(buffers), expr);
2671 }
2672 
2673 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
2674 
2675 namespace detail
2676 {
2677   template <typename AsyncReadStream, typename DynamicBuffer_v2,
2678       typename MatchCondition, typename ReadHandler>
2679   class read_until_match_op_v2
2680     : public base_from_cancellation_state<ReadHandler>
2681   {
2682   public:
2683     template <typename BufferSequence>
2684     read_until_match_op_v2(AsyncReadStream& stream,
2685         BufferSequence&& buffers,
2686         MatchCondition match_condition, ReadHandler& handler)
2687       : base_from_cancellation_state<ReadHandler>(
2688           handler, enable_partial_cancellation()),
2689         stream_(stream),
2690         buffers_(static_cast<BufferSequence&&>(buffers)),
2691         match_condition_(match_condition),
2692         start_(0),
2693         search_position_(0),
2694         bytes_to_read_(0),
2695         handler_(static_cast<ReadHandler&&>(handler))
2696     {
2697     }
2698 
2699     read_until_match_op_v2(const read_until_match_op_v2& other)
2700       : base_from_cancellation_state<ReadHandler>(other),
2701         stream_(other.stream_),
2702         buffers_(other.buffers_),
2703         match_condition_(other.match_condition_),
2704         start_(other.start_),
2705         search_position_(other.search_position_),
2706         bytes_to_read_(other.bytes_to_read_),
2707         handler_(other.handler_)
2708     {
2709     }
2710 
2711     read_until_match_op_v2(read_until_match_op_v2&& other)
2712       : base_from_cancellation_state<ReadHandler>(
2713           static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
2714         stream_(other.stream_),
2715         buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
2716         match_condition_(other.match_condition_),
2717         start_(other.start_),
2718         search_position_(other.search_position_),
2719         bytes_to_read_(other.bytes_to_read_),
2720         handler_(static_cast<ReadHandler&&>(other.handler_))
2721     {
2722     }
2723 
2724     void operator()(boost::system::error_code ec,
2725         std::size_t bytes_transferred, int start = 0)
2726     {
2727       const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
2728       std::size_t pos;
2729       switch (start_ = start)
2730       {
2731       case 1:
2732         for (;;)
2733         {
2734           {
2735             // Determine the range of the data to be searched.
2736             typedef typename DynamicBuffer_v2::const_buffers_type
2737               buffers_type;
2738             typedef buffers_iterator<buffers_type> iterator;
2739             buffers_type data_buffers =
2740               const_cast<const DynamicBuffer_v2&>(buffers_).data(
2741                   0, buffers_.size());
2742             iterator begin = iterator::begin(data_buffers);
2743             iterator start_pos = begin + search_position_;
2744             iterator end = iterator::end(data_buffers);
2745 
2746             // Look for a match.
2747             std::pair<iterator, bool> result = match_condition_(start_pos, end);
2748             if (result.second)
2749             {
2750               // Full match. We're done.
2751               search_position_ = result.first - begin;
2752               bytes_to_read_ = 0;
2753             }
2754 
2755             // No match yet. Check if buffer is full.
2756             else if (buffers_.size() == buffers_.max_size())
2757             {
2758               search_position_ = not_found;
2759               bytes_to_read_ = 0;
2760             }
2761 
2762             // Need to read some more data.
2763             else
2764             {
2765               if (result.first != end)
2766               {
2767                 // Partial match. Next search needs to start from beginning of
2768                 // match.
2769                 search_position_ = result.first - begin;
2770               }
2771               else
2772               {
2773                 // Next search can start with the new data.
2774                 search_position_ = end - begin;
2775               }
2776 
2777               bytes_to_read_ = std::min<std::size_t>(
2778                     std::max<std::size_t>(512,
2779                       buffers_.capacity() - buffers_.size()),
2780                     std::min<std::size_t>(65536,
2781                       buffers_.max_size() - buffers_.size()));
2782             }
2783           }
2784 
2785           // Check if we're done.
2786           if (!start && bytes_to_read_ == 0)
2787             break;
2788 
2789           // Start a new asynchronous read operation to obtain more data.
2790           pos = buffers_.size();
2791           buffers_.grow(bytes_to_read_);
2792           {
2793             BOOST_ASIO_HANDLER_LOCATION((
2794                   __FILE__, __LINE__, "async_read_until"));
2795             stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2796                 static_cast<read_until_match_op_v2&&>(*this));
2797           }
2798           return; default:
2799           buffers_.shrink(bytes_to_read_ - bytes_transferred);
2800           if (ec || bytes_transferred == 0)
2801             break;
2802           if (this->cancelled() != cancellation_type::none)
2803           {
2804             ec = error::operation_aborted;
2805             break;
2806           }
2807         }
2808 
2809         const boost::system::error_code result_ec =
2810           (search_position_ == not_found)
2811           ? error::not_found : ec;
2812 
2813         const std::size_t result_n =
2814           (ec || search_position_ == not_found)
2815           ? 0 : search_position_;
2816 
2817         static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
2818       }
2819     }
2820 
2821   //private:
2822     AsyncReadStream& stream_;
2823     DynamicBuffer_v2 buffers_;
2824     MatchCondition match_condition_;
2825     int start_;
2826     std::size_t search_position_;
2827     std::size_t bytes_to_read_;
2828     ReadHandler handler_;
2829   };
2830 
2831   template <typename AsyncReadStream, typename DynamicBuffer_v2,
2832       typename MatchCondition, typename ReadHandler>
2833   inline bool asio_handler_is_continuation(
2834       read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
2835         MatchCondition, ReadHandler>* this_handler)
2836   {
2837     return this_handler->start_ == 0 ? true
2838       : boost_asio_handler_cont_helpers::is_continuation(
2839           this_handler->handler_);
2840   }
2841 
2842   template <typename AsyncReadStream>
2843   class initiate_async_read_until_match_v2
2844   {
2845   public:
2846     typedef typename AsyncReadStream::executor_type executor_type;
2847 
2848     explicit initiate_async_read_until_match_v2(AsyncReadStream& stream)
2849       : stream_(stream)
2850     {
2851     }
2852 
2853     executor_type get_executor() const noexcept
2854     {
2855       return stream_.get_executor();
2856     }
2857 
2858     template <typename ReadHandler,
2859         typename DynamicBuffer_v2, typename MatchCondition>
2860     void operator()(ReadHandler&& handler,
2861         DynamicBuffer_v2&& buffers,
2862         MatchCondition match_condition) const
2863     {
2864       // If you get an error on the following line it means that your handler
2865       // does not meet the documented type requirements for a ReadHandler.
2866       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2867 
2868       non_const_lvalue<ReadHandler> handler2(handler);
2869       read_until_match_op_v2<AsyncReadStream, decay_t<DynamicBuffer_v2>,
2870         MatchCondition, decay_t<ReadHandler>>(
2871           stream_, static_cast<DynamicBuffer_v2&&>(buffers),
2872           match_condition, handler2.value)(boost::system::error_code(), 0, 1);
2873     }
2874 
2875   private:
2876     AsyncReadStream& stream_;
2877   };
2878 } // namespace detail
2879 
2880 #if !defined(GENERATING_DOCUMENTATION)
2881 
2882 template <template <typename, typename> class Associator,
2883     typename AsyncReadStream, typename DynamicBuffer_v2,
2884     typename MatchCondition, typename ReadHandler, typename DefaultCandidate>
2885 struct associator<Associator,
2886     detail::read_until_match_op_v2<AsyncReadStream,
2887       DynamicBuffer_v2, MatchCondition, ReadHandler>,
2888     DefaultCandidate>
2889   : Associator<ReadHandler, DefaultCandidate>
2890 {
2891   static typename Associator<ReadHandler, DefaultCandidate>::type get(
2892       const detail::read_until_match_op_v2<AsyncReadStream,
2893         DynamicBuffer_v2, MatchCondition, ReadHandler>& h) noexcept
2894   {
2895     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
2896   }
2897 
2898   static auto get(
2899       const detail::read_until_match_op_v2<AsyncReadStream,
2900         DynamicBuffer_v2, MatchCondition, ReadHandler>& h,
2901       const DefaultCandidate& c) noexcept
2902     -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
2903   {
2904     return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
2905   }
2906 };
2907 
2908 #endif // !defined(GENERATING_DOCUMENTATION)
2909 
2910 template <typename AsyncReadStream,
2911     typename DynamicBuffer_v2, typename MatchCondition,
2912     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
2913       std::size_t)) ReadToken>
2914 inline auto async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
2915     MatchCondition match_condition, ReadToken&& token,
2916     constraint_t<
2917       is_match_condition<MatchCondition>::value
2918     >,
2919     constraint_t<
2920       is_dynamic_buffer_v2<DynamicBuffer_v2>::value
2921     >)
2922   -> decltype(
2923     async_initiate<ReadToken,
2924       void (boost::system::error_code, std::size_t)>(
2925         declval<detail::initiate_async_read_until_match_v2<AsyncReadStream>>(),
2926         token, static_cast<DynamicBuffer_v2&&>(buffers),
2927         match_condition))
2928 {
2929   return async_initiate<ReadToken,
2930     void (boost::system::error_code, std::size_t)>(
2931       detail::initiate_async_read_until_match_v2<AsyncReadStream>(s),
2932       token, static_cast<DynamicBuffer_v2&&>(buffers),
2933       match_condition);
2934 }
2935 
2936 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
2937 
2938 } // namespace asio
2939 } // namespace boost
2940 
2941 #include <boost/asio/detail/pop_options.hpp>
2942 
2943 #endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP