File indexing completed on 2025-01-18 09:28:57
0001
0002
0003
0004
0005
0006
0007
0008
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
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
0042
0043
0044
0045
0046
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 }
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
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
0119 iterator iter = std::find(start_pos, end, delim);
0120 if (iter != end)
0121 {
0122
0123 ec = boost::system::error_code();
0124 return iter - begin + 1;
0125 }
0126 else
0127 {
0128
0129 search_position = end - begin;
0130 }
0131
0132
0133 if (b.size() == b.max_size())
0134 {
0135 ec = error::not_found;
0136 return 0;
0137 }
0138
0139
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
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
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
0200 ec = boost::system::error_code();
0201 return result.first - begin + delim.length();
0202 }
0203 else
0204 {
0205
0206 search_position = result.first - begin;
0207 }
0208 }
0209 else
0210 {
0211
0212 search_position = end - begin;
0213 }
0214
0215
0216 if (b.size() == b.max_size())
0217 {
0218 ec = error::not_found;
0219 return 0;
0220 }
0221
0222
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 }
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
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
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
0299 ec = boost::system::error_code();
0300 return match_results[0].second - begin;
0301 }
0302 else
0303 {
0304
0305 search_position = match_results[0].first - begin;
0306 }
0307 }
0308 else
0309 {
0310
0311 search_position = end - begin;
0312 }
0313
0314
0315 if (b.size() == b.max_size())
0316 {
0317 ec = error::not_found;
0318 return 0;
0319 }
0320
0321
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
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
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
0386 std::pair<iterator, bool> result = match_condition(start_pos, end);
0387 if (result.second)
0388 {
0389
0390 ec = boost::system::error_code();
0391 return result.first - begin;
0392 }
0393 else if (result.first != end)
0394 {
0395
0396 search_position = result.first - begin;
0397 }
0398 else
0399 {
0400
0401 search_position = end - begin;
0402 }
0403
0404
0405 if (b.size() == b.max_size())
0406 {
0407 ec = error::not_found;
0408 return 0;
0409 }
0410
0411
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
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
0493 #endif
0494 #endif
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
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
0532 iterator iter = std::find(start_pos, end, delim);
0533 if (iter != end)
0534 {
0535
0536 ec = boost::system::error_code();
0537 return iter - begin + 1;
0538 }
0539 else
0540 {
0541
0542 search_position = end - begin;
0543 }
0544
0545
0546 if (b.size() == b.max_size())
0547 {
0548 ec = error::not_found;
0549 return 0;
0550 }
0551
0552
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
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
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
0608 ec = boost::system::error_code();
0609 return result.first - begin + delim.length();
0610 }
0611 else
0612 {
0613
0614 search_position = result.first - begin;
0615 }
0616 }
0617 else
0618 {
0619
0620 search_position = end - begin;
0621 }
0622
0623
0624 if (b.size() == b.max_size())
0625 {
0626 ec = error::not_found;
0627 return 0;
0628 }
0629
0630
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
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
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
0691 ec = boost::system::error_code();
0692 return match_results[0].second - begin;
0693 }
0694 else
0695 {
0696
0697 search_position = match_results[0].first - begin;
0698 }
0699 }
0700 else
0701 {
0702
0703 search_position = end - begin;
0704 }
0705
0706
0707 if (b.size() == b.max_size())
0708 {
0709 ec = error::not_found;
0710 return 0;
0711 }
0712
0713
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
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
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
0773 std::pair<iterator, bool> result = match_condition(start_pos, end);
0774 if (result.second)
0775 {
0776
0777 ec = boost::system::error_code();
0778 return result.first - begin;
0779 }
0780 else if (result.first != end)
0781 {
0782
0783 search_position = result.first - begin;
0784 }
0785 else
0786 {
0787
0788 search_position = end - begin;
0789 }
0790
0791
0792 if (b.size() == b.max_size())
0793 {
0794 ec = error::not_found;
0795 return 0;
0796 }
0797
0798
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
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
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
0882 iterator iter = std::find(start_pos, end, delim_);
0883 if (iter != end)
0884 {
0885
0886 search_position_ = iter - begin + 1;
0887 bytes_to_read = 0;
0888 }
0889
0890
0891 else if (buffers_.size() == buffers_.max_size())
0892 {
0893 search_position_ = not_found;
0894 bytes_to_read = 0;
0895 }
0896
0897
0898 else
0899 {
0900
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
0911 if (!start && bytes_to_read == 0)
0912 break;
0913
0914
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
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
0986
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 }
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
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
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
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
1127 search_position_ = result.first - begin + delim_.length();
1128 bytes_to_read = 0;
1129 }
1130
1131
1132 else if (buffers_.size() == buffers_.max_size())
1133 {
1134 search_position_ = not_found;
1135 bytes_to_read = 0;
1136 }
1137
1138
1139 else
1140 {
1141 if (result.first != end)
1142 {
1143
1144
1145 search_position_ = result.first - begin;
1146 }
1147 else
1148 {
1149
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
1162 if (!start && bytes_to_read == 0)
1163 break;
1164
1165
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
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
1237
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 }
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
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
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
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
1386 search_position_ = match_results[0].second - begin;
1387 bytes_to_read = 0;
1388 }
1389
1390
1391 else if (buffers_.size() == buffers_.max_size())
1392 {
1393 search_position_ = not_found;
1394 bytes_to_read = 0;
1395 }
1396
1397
1398 else
1399 {
1400 if (match)
1401 {
1402
1403
1404 search_position_ = match_results[0].first - begin;
1405 }
1406 else
1407 {
1408
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
1421 if (!start && bytes_to_read == 0)
1422 break;
1423
1424
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
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
1495
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 }
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
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
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
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
1633 std::pair<iterator, bool> result = match_condition_(start_pos, end);
1634 if (result.second)
1635 {
1636
1637 search_position_ = result.first - begin;
1638 bytes_to_read = 0;
1639 }
1640
1641
1642 else if (buffers_.size() == buffers_.max_size())
1643 {
1644 search_position_ = not_found;
1645 bytes_to_read = 0;
1646 }
1647
1648
1649 else
1650 {
1651 if (result.first != end)
1652 {
1653
1654
1655 search_position_ = result.first - begin;
1656 }
1657 else
1658 {
1659
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
1672 if (!start && bytes_to_read == 0)
1673 break;
1674
1675
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
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
1748
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 }
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
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
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
1905 #endif
1906 #endif
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
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
1980 iterator iter = std::find(start_pos, end, delim_);
1981 if (iter != end)
1982 {
1983
1984 search_position_ = iter - begin + 1;
1985 bytes_to_read_ = 0;
1986 }
1987
1988
1989 else if (buffers_.size() == buffers_.max_size())
1990 {
1991 search_position_ = not_found;
1992 bytes_to_read_ = 0;
1993 }
1994
1995
1996 else
1997 {
1998
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
2009 if (!start && bytes_to_read_ == 0)
2010 break;
2011
2012
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
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
2086
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 }
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
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
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
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
2229 search_position_ = result.first - begin + delim_.length();
2230 bytes_to_read_ = 0;
2231 }
2232
2233
2234 else if (buffers_.size() == buffers_.max_size())
2235 {
2236 search_position_ = not_found;
2237 bytes_to_read_ = 0;
2238 }
2239
2240
2241 else
2242 {
2243 if (result.first != end)
2244 {
2245
2246
2247 search_position_ = result.first - begin;
2248 }
2249 else
2250 {
2251
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
2264 if (!start && bytes_to_read_ == 0)
2265 break;
2266
2267
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
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
2342
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 }
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
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
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
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
2494 search_position_ = match_results[0].second - begin;
2495 bytes_to_read_ = 0;
2496 }
2497
2498
2499 else if (buffers_.size() == buffers_.max_size())
2500 {
2501 search_position_ = not_found;
2502 bytes_to_read_ = 0;
2503 }
2504
2505
2506 else
2507 {
2508 if (match)
2509 {
2510
2511
2512 search_position_ = match_results[0].first - begin;
2513 }
2514 else
2515 {
2516
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
2529 if (!start && bytes_to_read_ == 0)
2530 break;
2531
2532
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
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
2607
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 }
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
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
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
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
2747 std::pair<iterator, bool> result = match_condition_(start_pos, end);
2748 if (result.second)
2749 {
2750
2751 search_position_ = result.first - begin;
2752 bytes_to_read_ = 0;
2753 }
2754
2755
2756 else if (buffers_.size() == buffers_.max_size())
2757 {
2758 search_position_ = not_found;
2759 bytes_to_read_ = 0;
2760 }
2761
2762
2763 else
2764 {
2765 if (result.first != end)
2766 {
2767
2768
2769 search_position_ = result.first - begin;
2770 }
2771 else
2772 {
2773
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
2786 if (!start && bytes_to_read_ == 0)
2787 break;
2788
2789
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
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
2865
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 }
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
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
2937
2938 }
2939 }
2940
2941 #include <boost/asio/detail/pop_options.hpp>
2942
2943 #endif