File indexing completed on 2025-07-05 08:27:29
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 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0074 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
0075 struct regex_match_flags
0076 {
0077 template <typename T>
0078 operator T() const
0079 {
0080 return T::match_default | T::match_partial;
0081 }
0082 };
0083 #endif
0084 #endif
0085 }
0086
0087 #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
0088
0089 template <typename SyncReadStream, typename DynamicBuffer_v1>
0090 inline std::size_t read_until(SyncReadStream& s,
0091 DynamicBuffer_v1&& buffers, char delim,
0092 constraint_t<
0093 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0094 >,
0095 constraint_t<
0096 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0097 >)
0098 {
0099 boost::system::error_code ec;
0100 std::size_t bytes_transferred = read_until(s,
0101 static_cast<DynamicBuffer_v1&&>(buffers), delim, ec);
0102 boost::asio::detail::throw_error(ec, "read_until");
0103 return bytes_transferred;
0104 }
0105
0106 template <typename SyncReadStream, typename DynamicBuffer_v1>
0107 std::size_t read_until(SyncReadStream& s,
0108 DynamicBuffer_v1&& buffers,
0109 char delim, boost::system::error_code& ec,
0110 constraint_t<
0111 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0112 >,
0113 constraint_t<
0114 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0115 >)
0116 {
0117 decay_t<DynamicBuffer_v1> b(
0118 static_cast<DynamicBuffer_v1&&>(buffers));
0119
0120 std::size_t search_position = 0;
0121 for (;;)
0122 {
0123
0124 typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
0125 typedef buffers_iterator<buffers_type> iterator;
0126 buffers_type data_buffers = b.data();
0127 iterator begin = iterator::begin(data_buffers);
0128 iterator start_pos = begin + search_position;
0129 iterator end = iterator::end(data_buffers);
0130
0131
0132 iterator iter = std::find(start_pos, end, delim);
0133 if (iter != end)
0134 {
0135
0136 ec = boost::system::error_code();
0137 return iter - begin + 1;
0138 }
0139 else
0140 {
0141
0142 search_position = end - begin;
0143 }
0144
0145
0146 if (b.size() == b.max_size())
0147 {
0148 ec = error::not_found;
0149 return 0;
0150 }
0151
0152
0153 std::size_t bytes_to_read = std::min<std::size_t>(
0154 std::max<std::size_t>(512, b.capacity() - b.size()),
0155 std::min<std::size_t>(65536, b.max_size() - b.size()));
0156 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
0157 if (ec)
0158 return 0;
0159 }
0160 }
0161
0162 template <typename SyncReadStream, typename DynamicBuffer_v1>
0163 inline std::size_t read_until(SyncReadStream& s,
0164 DynamicBuffer_v1&& buffers,
0165 BOOST_ASIO_STRING_VIEW_PARAM delim,
0166 constraint_t<
0167 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0168 >,
0169 constraint_t<
0170 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0171 >)
0172 {
0173 boost::system::error_code ec;
0174 std::size_t bytes_transferred = read_until(s,
0175 static_cast<DynamicBuffer_v1&&>(buffers), delim, ec);
0176 boost::asio::detail::throw_error(ec, "read_until");
0177 return bytes_transferred;
0178 }
0179
0180 template <typename SyncReadStream, typename DynamicBuffer_v1>
0181 std::size_t read_until(SyncReadStream& s,
0182 DynamicBuffer_v1&& buffers,
0183 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec,
0184 constraint_t<
0185 is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value
0186 >,
0187 constraint_t<
0188 !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value
0189 >)
0190 {
0191 decay_t<DynamicBuffer_v1> b(
0192 static_cast<DynamicBuffer_v1&&>(buffers));
0193
0194 std::size_t search_position = 0;
0195 for (;;)
0196 {
0197
0198 typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
0199 typedef buffers_iterator<buffers_type> iterator;
0200 buffers_type data_buffers = b.data();
0201 iterator begin = iterator::begin(data_buffers);
0202 iterator start_pos = begin + search_position;
0203 iterator end = iterator::end(data_buffers);
0204
0205
0206 std::pair<iterator, bool> result = detail::partial_search(
0207 start_pos, end, delim.begin(), delim.end());
0208 if (result.first != end)
0209 {
0210 if (result.second)
0211 {
0212
0213 ec = boost::system::error_code();
0214 return result.first - begin + delim.length();
0215 }
0216 else
0217 {
0218
0219 search_position = result.first - begin;
0220 }
0221 }
0222 else
0223 {
0224
0225 search_position = end - begin;
0226 }
0227
0228
0229 if (b.size() == b.max_size())
0230 {
0231 ec = error::not_found;
0232 return 0;
0233 }
0234
0235
0236 std::size_t bytes_to_read = std::min<std::size_t>(
0237 std::max<std::size_t>(512, b.capacity() - b.size()),
0238 std::min<std::size_t>(65536, b.max_size() - b.size()));
0239 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
0240 if (ec)
0241 return 0;
0242 }
0243 }
0244
0245 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0246 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
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 namespace detail
1033 {
1034 template <typename AsyncReadStream,
1035 typename DynamicBuffer_v1, typename ReadHandler>
1036 class read_until_delim_string_op_v1
1037 : public base_from_cancellation_state<ReadHandler>
1038 {
1039 public:
1040 template <typename BufferSequence>
1041 read_until_delim_string_op_v1(AsyncReadStream& stream,
1042 BufferSequence&& buffers,
1043 const std::string& delim, ReadHandler& handler)
1044 : base_from_cancellation_state<ReadHandler>(
1045 handler, enable_partial_cancellation()),
1046 stream_(stream),
1047 buffers_(static_cast<BufferSequence&&>(buffers)),
1048 delim_(delim),
1049 start_(0),
1050 search_position_(0),
1051 handler_(static_cast<ReadHandler&&>(handler))
1052 {
1053 }
1054
1055 read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other)
1056 : base_from_cancellation_state<ReadHandler>(other),
1057 stream_(other.stream_),
1058 buffers_(other.buffers_),
1059 delim_(other.delim_),
1060 start_(other.start_),
1061 search_position_(other.search_position_),
1062 handler_(other.handler_)
1063 {
1064 }
1065
1066 read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other)
1067 : base_from_cancellation_state<ReadHandler>(
1068 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1069 stream_(other.stream_),
1070 buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
1071 delim_(static_cast<std::string&&>(other.delim_)),
1072 start_(other.start_),
1073 search_position_(other.search_position_),
1074 handler_(static_cast<ReadHandler&&>(other.handler_))
1075 {
1076 }
1077
1078 void operator()(boost::system::error_code ec,
1079 std::size_t bytes_transferred, int start = 0)
1080 {
1081 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1082 std::size_t bytes_to_read;
1083 switch (start_ = start)
1084 {
1085 case 1:
1086 for (;;)
1087 {
1088 {
1089
1090 typedef typename DynamicBuffer_v1::const_buffers_type
1091 buffers_type;
1092 typedef buffers_iterator<buffers_type> iterator;
1093 buffers_type data_buffers = buffers_.data();
1094 iterator begin = iterator::begin(data_buffers);
1095 iterator start_pos = begin + search_position_;
1096 iterator end = iterator::end(data_buffers);
1097
1098
1099 std::pair<iterator, bool> result = detail::partial_search(
1100 start_pos, end, delim_.begin(), delim_.end());
1101 if (result.first != end && result.second)
1102 {
1103
1104 search_position_ = result.first - begin + delim_.length();
1105 bytes_to_read = 0;
1106 }
1107
1108
1109 else if (buffers_.size() == buffers_.max_size())
1110 {
1111 search_position_ = not_found;
1112 bytes_to_read = 0;
1113 }
1114
1115
1116 else
1117 {
1118 if (result.first != end)
1119 {
1120
1121
1122 search_position_ = result.first - begin;
1123 }
1124 else
1125 {
1126
1127 search_position_ = end - begin;
1128 }
1129
1130 bytes_to_read = std::min<std::size_t>(
1131 std::max<std::size_t>(512,
1132 buffers_.capacity() - buffers_.size()),
1133 std::min<std::size_t>(65536,
1134 buffers_.max_size() - buffers_.size()));
1135 }
1136 }
1137
1138
1139 if (!start && bytes_to_read == 0)
1140 break;
1141
1142
1143 {
1144 BOOST_ASIO_HANDLER_LOCATION((
1145 __FILE__, __LINE__, "async_read_until"));
1146 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1147 static_cast<read_until_delim_string_op_v1&&>(*this));
1148 }
1149 return; default:
1150 buffers_.commit(bytes_transferred);
1151 if (ec || bytes_transferred == 0)
1152 break;
1153 if (this->cancelled() != cancellation_type::none)
1154 {
1155 ec = error::operation_aborted;
1156 break;
1157 }
1158 }
1159
1160 const boost::system::error_code result_ec =
1161 (search_position_ == not_found)
1162 ? error::not_found : ec;
1163
1164 const std::size_t result_n =
1165 (ec || search_position_ == not_found)
1166 ? 0 : search_position_;
1167
1168 static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
1169 }
1170 }
1171
1172
1173 AsyncReadStream& stream_;
1174 DynamicBuffer_v1 buffers_;
1175 std::string delim_;
1176 int start_;
1177 std::size_t search_position_;
1178 ReadHandler handler_;
1179 };
1180
1181 template <typename AsyncReadStream,
1182 typename DynamicBuffer_v1, typename ReadHandler>
1183 inline bool asio_handler_is_continuation(
1184 read_until_delim_string_op_v1<AsyncReadStream,
1185 DynamicBuffer_v1, ReadHandler>* this_handler)
1186 {
1187 return this_handler->start_ == 0 ? true
1188 : boost_asio_handler_cont_helpers::is_continuation(
1189 this_handler->handler_);
1190 }
1191
1192 template <typename AsyncReadStream>
1193 class initiate_async_read_until_delim_string_v1
1194 {
1195 public:
1196 typedef typename AsyncReadStream::executor_type executor_type;
1197
1198 explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream)
1199 : stream_(stream)
1200 {
1201 }
1202
1203 executor_type get_executor() const noexcept
1204 {
1205 return stream_.get_executor();
1206 }
1207
1208 template <typename ReadHandler, typename DynamicBuffer_v1>
1209 void operator()(ReadHandler&& handler,
1210 DynamicBuffer_v1&& buffers,
1211 const std::string& delim) const
1212 {
1213
1214
1215 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1216
1217 non_const_lvalue<ReadHandler> handler2(handler);
1218 read_until_delim_string_op_v1<AsyncReadStream,
1219 decay_t<DynamicBuffer_v1>,
1220 decay_t<ReadHandler>>(
1221 stream_, static_cast<DynamicBuffer_v1&&>(buffers),
1222 delim, handler2.value)(boost::system::error_code(), 0, 1);
1223 }
1224
1225 private:
1226 AsyncReadStream& stream_;
1227 };
1228 }
1229
1230 #if !defined(GENERATING_DOCUMENTATION)
1231
1232 template <template <typename, typename> class Associator,
1233 typename AsyncReadStream, typename DynamicBuffer_v1,
1234 typename ReadHandler, typename DefaultCandidate>
1235 struct associator<Associator,
1236 detail::read_until_delim_string_op_v1<AsyncReadStream,
1237 DynamicBuffer_v1, ReadHandler>,
1238 DefaultCandidate>
1239 : Associator<ReadHandler, DefaultCandidate>
1240 {
1241 static typename Associator<ReadHandler, DefaultCandidate>::type get(
1242 const detail::read_until_delim_string_op_v1<
1243 AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h) noexcept
1244 {
1245 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1246 }
1247
1248 static auto get(
1249 const detail::read_until_delim_string_op_v1<
1250 AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h,
1251 const DefaultCandidate& c) noexcept
1252 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1253 {
1254 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1255 }
1256 };
1257
1258 #endif
1259
1260 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
1261 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
1262
1263 namespace detail
1264 {
1265 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1266 typename RegEx, typename ReadHandler>
1267 class read_until_expr_op_v1
1268 : public base_from_cancellation_state<ReadHandler>
1269 {
1270 public:
1271 template <typename BufferSequence, typename Traits>
1272 read_until_expr_op_v1(AsyncReadStream& stream, BufferSequence&& buffers,
1273 const boost::basic_regex<char, Traits>& expr, ReadHandler& handler)
1274 : base_from_cancellation_state<ReadHandler>(
1275 handler, enable_partial_cancellation()),
1276 stream_(stream),
1277 buffers_(static_cast<BufferSequence&&>(buffers)),
1278 expr_(expr),
1279 start_(0),
1280 search_position_(0),
1281 handler_(static_cast<ReadHandler&&>(handler))
1282 {
1283 }
1284
1285 read_until_expr_op_v1(const read_until_expr_op_v1& other)
1286 : base_from_cancellation_state<ReadHandler>(other),
1287 stream_(other.stream_),
1288 buffers_(other.buffers_),
1289 expr_(other.expr_),
1290 start_(other.start_),
1291 search_position_(other.search_position_),
1292 handler_(other.handler_)
1293 {
1294 }
1295
1296 read_until_expr_op_v1(read_until_expr_op_v1&& other)
1297 : base_from_cancellation_state<ReadHandler>(
1298 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1299 stream_(other.stream_),
1300 buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
1301 expr_(other.expr_),
1302 start_(other.start_),
1303 search_position_(other.search_position_),
1304 handler_(static_cast<ReadHandler&&>(other.handler_))
1305 {
1306 }
1307
1308 void operator()(boost::system::error_code ec,
1309 std::size_t bytes_transferred, int start = 0)
1310 {
1311 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1312 std::size_t bytes_to_read;
1313 switch (start_ = start)
1314 {
1315 case 1:
1316 for (;;)
1317 {
1318 {
1319
1320 typedef typename DynamicBuffer_v1::const_buffers_type
1321 buffers_type;
1322 typedef buffers_iterator<buffers_type> iterator;
1323 buffers_type data_buffers = buffers_.data();
1324 iterator begin = iterator::begin(data_buffers);
1325 iterator start_pos = begin + search_position_;
1326 iterator end = iterator::end(data_buffers);
1327
1328
1329 boost::match_results<iterator,
1330 typename std::vector<boost::sub_match<iterator>>::allocator_type>
1331 match_results;
1332 bool match = regex_search(start_pos, end,
1333 match_results, expr_, regex_match_flags());
1334 if (match && match_results[0].matched)
1335 {
1336
1337 search_position_ = match_results[0].second - begin;
1338 bytes_to_read = 0;
1339 }
1340
1341
1342 else if (buffers_.size() == buffers_.max_size())
1343 {
1344 search_position_ = not_found;
1345 bytes_to_read = 0;
1346 }
1347
1348
1349 else
1350 {
1351 if (match)
1352 {
1353
1354
1355 search_position_ = match_results[0].first - begin;
1356 }
1357 else
1358 {
1359
1360 search_position_ = end - begin;
1361 }
1362
1363 bytes_to_read = std::min<std::size_t>(
1364 std::max<std::size_t>(512,
1365 buffers_.capacity() - buffers_.size()),
1366 std::min<std::size_t>(65536,
1367 buffers_.max_size() - buffers_.size()));
1368 }
1369 }
1370
1371
1372 if (!start && bytes_to_read == 0)
1373 break;
1374
1375
1376 {
1377 BOOST_ASIO_HANDLER_LOCATION((
1378 __FILE__, __LINE__, "async_read_until"));
1379 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1380 static_cast<read_until_expr_op_v1&&>(*this));
1381 }
1382 return; default:
1383 buffers_.commit(bytes_transferred);
1384 if (ec || bytes_transferred == 0)
1385 break;
1386 if (this->cancelled() != cancellation_type::none)
1387 {
1388 ec = error::operation_aborted;
1389 break;
1390 }
1391 }
1392
1393 const boost::system::error_code result_ec =
1394 (search_position_ == not_found)
1395 ? error::not_found : ec;
1396
1397 const std::size_t result_n =
1398 (ec || search_position_ == not_found)
1399 ? 0 : search_position_;
1400
1401 static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
1402 }
1403 }
1404
1405
1406 AsyncReadStream& stream_;
1407 DynamicBuffer_v1 buffers_;
1408 RegEx expr_;
1409 int start_;
1410 std::size_t search_position_;
1411 ReadHandler handler_;
1412 };
1413
1414 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1415 typename RegEx, typename ReadHandler>
1416 inline bool asio_handler_is_continuation(
1417 read_until_expr_op_v1<AsyncReadStream,
1418 DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
1419 {
1420 return this_handler->start_ == 0 ? true
1421 : boost_asio_handler_cont_helpers::is_continuation(
1422 this_handler->handler_);
1423 }
1424
1425 template <typename AsyncReadStream>
1426 class initiate_async_read_until_expr_v1
1427 {
1428 public:
1429 typedef typename AsyncReadStream::executor_type executor_type;
1430
1431 explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream)
1432 : stream_(stream)
1433 {
1434 }
1435
1436 executor_type get_executor() const noexcept
1437 {
1438 return stream_.get_executor();
1439 }
1440
1441 template <typename ReadHandler, typename DynamicBuffer_v1, typename RegEx>
1442 void operator()(ReadHandler&& handler,
1443 DynamicBuffer_v1&& buffers, const RegEx& expr) const
1444 {
1445
1446
1447 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1448
1449 non_const_lvalue<ReadHandler> handler2(handler);
1450 read_until_expr_op_v1<AsyncReadStream,
1451 decay_t<DynamicBuffer_v1>,
1452 RegEx, decay_t<ReadHandler>>(
1453 stream_, static_cast<DynamicBuffer_v1&&>(buffers),
1454 expr, handler2.value)(boost::system::error_code(), 0, 1);
1455 }
1456
1457 private:
1458 AsyncReadStream& stream_;
1459 };
1460 }
1461
1462 #if !defined(GENERATING_DOCUMENTATION)
1463
1464 template <template <typename, typename> class Associator,
1465 typename AsyncReadStream, typename DynamicBuffer_v1,
1466 typename RegEx, typename ReadHandler, typename DefaultCandidate>
1467 struct associator<Associator,
1468 detail::read_until_expr_op_v1<AsyncReadStream,
1469 DynamicBuffer_v1, RegEx, ReadHandler>,
1470 DefaultCandidate>
1471 : Associator<ReadHandler, DefaultCandidate>
1472 {
1473 static typename Associator<ReadHandler, DefaultCandidate>::type get(
1474 const detail::read_until_expr_op_v1<AsyncReadStream,
1475 DynamicBuffer_v1, RegEx, ReadHandler>& h) noexcept
1476 {
1477 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1478 }
1479
1480 static auto get(
1481 const detail::read_until_expr_op_v1<AsyncReadStream,
1482 DynamicBuffer_v1, RegEx, ReadHandler>& h,
1483 const DefaultCandidate& c) noexcept
1484 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1485 {
1486 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1487 }
1488 };
1489
1490 #endif
1491
1492 #endif
1493
1494 namespace detail
1495 {
1496 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1497 typename MatchCondition, typename ReadHandler>
1498 class read_until_match_op_v1
1499 : public base_from_cancellation_state<ReadHandler>
1500 {
1501 public:
1502 template <typename BufferSequence>
1503 read_until_match_op_v1(AsyncReadStream& stream,
1504 BufferSequence&& buffers,
1505 MatchCondition match_condition, ReadHandler& handler)
1506 : base_from_cancellation_state<ReadHandler>(
1507 handler, enable_partial_cancellation()),
1508 stream_(stream),
1509 buffers_(static_cast<BufferSequence&&>(buffers)),
1510 match_condition_(match_condition),
1511 start_(0),
1512 search_position_(0),
1513 handler_(static_cast<ReadHandler&&>(handler))
1514 {
1515 }
1516
1517 read_until_match_op_v1(const read_until_match_op_v1& other)
1518 : base_from_cancellation_state<ReadHandler>(other),
1519 stream_(other.stream_),
1520 buffers_(other.buffers_),
1521 match_condition_(other.match_condition_),
1522 start_(other.start_),
1523 search_position_(other.search_position_),
1524 handler_(other.handler_)
1525 {
1526 }
1527
1528 read_until_match_op_v1(read_until_match_op_v1&& other)
1529 : base_from_cancellation_state<ReadHandler>(
1530 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1531 stream_(other.stream_),
1532 buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)),
1533 match_condition_(other.match_condition_),
1534 start_(other.start_),
1535 search_position_(other.search_position_),
1536 handler_(static_cast<ReadHandler&&>(other.handler_))
1537 {
1538 }
1539
1540 void operator()(boost::system::error_code ec,
1541 std::size_t bytes_transferred, int start = 0)
1542 {
1543 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1544 std::size_t bytes_to_read;
1545 switch (start_ = start)
1546 {
1547 case 1:
1548 for (;;)
1549 {
1550 {
1551
1552 typedef typename DynamicBuffer_v1::const_buffers_type
1553 buffers_type;
1554 typedef buffers_iterator<buffers_type> iterator;
1555 buffers_type data_buffers = buffers_.data();
1556 iterator begin = iterator::begin(data_buffers);
1557 iterator start_pos = begin + search_position_;
1558 iterator end = iterator::end(data_buffers);
1559
1560
1561 std::pair<iterator, bool> result = match_condition_(start_pos, end);
1562 if (result.second)
1563 {
1564
1565 search_position_ = result.first - begin;
1566 bytes_to_read = 0;
1567 }
1568
1569
1570 else if (buffers_.size() == buffers_.max_size())
1571 {
1572 search_position_ = not_found;
1573 bytes_to_read = 0;
1574 }
1575
1576
1577 else
1578 {
1579 if (result.first != end)
1580 {
1581
1582
1583 search_position_ = result.first - begin;
1584 }
1585 else
1586 {
1587
1588 search_position_ = end - begin;
1589 }
1590
1591 bytes_to_read = std::min<std::size_t>(
1592 std::max<std::size_t>(512,
1593 buffers_.capacity() - buffers_.size()),
1594 std::min<std::size_t>(65536,
1595 buffers_.max_size() - buffers_.size()));
1596 }
1597 }
1598
1599
1600 if (!start && bytes_to_read == 0)
1601 break;
1602
1603
1604 {
1605 BOOST_ASIO_HANDLER_LOCATION((
1606 __FILE__, __LINE__, "async_read_until"));
1607 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1608 static_cast<read_until_match_op_v1&&>(*this));
1609 }
1610 return; default:
1611 buffers_.commit(bytes_transferred);
1612 if (ec || bytes_transferred == 0)
1613 break;
1614 if (this->cancelled() != cancellation_type::none)
1615 {
1616 ec = error::operation_aborted;
1617 break;
1618 }
1619 }
1620
1621 const boost::system::error_code result_ec =
1622 (search_position_ == not_found)
1623 ? error::not_found : ec;
1624
1625 const std::size_t result_n =
1626 (ec || search_position_ == not_found)
1627 ? 0 : search_position_;
1628
1629 static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
1630 }
1631 }
1632
1633
1634 AsyncReadStream& stream_;
1635 DynamicBuffer_v1 buffers_;
1636 MatchCondition match_condition_;
1637 int start_;
1638 std::size_t search_position_;
1639 ReadHandler handler_;
1640 };
1641
1642 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1643 typename MatchCondition, typename ReadHandler>
1644 inline bool asio_handler_is_continuation(
1645 read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
1646 MatchCondition, ReadHandler>* this_handler)
1647 {
1648 return this_handler->start_ == 0 ? true
1649 : boost_asio_handler_cont_helpers::is_continuation(
1650 this_handler->handler_);
1651 }
1652
1653 template <typename AsyncReadStream>
1654 class initiate_async_read_until_match_v1
1655 {
1656 public:
1657 typedef typename AsyncReadStream::executor_type executor_type;
1658
1659 explicit initiate_async_read_until_match_v1(AsyncReadStream& stream)
1660 : stream_(stream)
1661 {
1662 }
1663
1664 executor_type get_executor() const noexcept
1665 {
1666 return stream_.get_executor();
1667 }
1668
1669 template <typename ReadHandler,
1670 typename DynamicBuffer_v1, typename MatchCondition>
1671 void operator()(ReadHandler&& handler,
1672 DynamicBuffer_v1&& buffers,
1673 MatchCondition match_condition) const
1674 {
1675
1676
1677 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1678
1679 non_const_lvalue<ReadHandler> handler2(handler);
1680 read_until_match_op_v1<AsyncReadStream,
1681 decay_t<DynamicBuffer_v1>,
1682 MatchCondition, decay_t<ReadHandler>>(
1683 stream_, static_cast<DynamicBuffer_v1&&>(buffers),
1684 match_condition, handler2.value)(boost::system::error_code(), 0, 1);
1685 }
1686
1687 private:
1688 AsyncReadStream& stream_;
1689 };
1690 }
1691
1692 #if !defined(GENERATING_DOCUMENTATION)
1693
1694 template <template <typename, typename> class Associator,
1695 typename AsyncReadStream, typename DynamicBuffer_v1,
1696 typename MatchCondition, typename ReadHandler, typename DefaultCandidate>
1697 struct associator<Associator,
1698 detail::read_until_match_op_v1<AsyncReadStream,
1699 DynamicBuffer_v1, MatchCondition, ReadHandler>,
1700 DefaultCandidate>
1701 : Associator<ReadHandler, DefaultCandidate>
1702 {
1703 static typename Associator<ReadHandler, DefaultCandidate>::type get(
1704 const detail::read_until_match_op_v1<AsyncReadStream,
1705 DynamicBuffer_v1, MatchCondition, ReadHandler>& h) noexcept
1706 {
1707 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1708 }
1709
1710 static auto get(
1711 const detail::read_until_match_op_v1<AsyncReadStream,
1712 DynamicBuffer_v1, MatchCondition, ReadHandler>& h,
1713 const DefaultCandidate& c) noexcept
1714 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1715 {
1716 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1717 }
1718 };
1719
1720 #endif
1721
1722 #endif
1723 #endif
1724
1725 namespace detail
1726 {
1727 template <typename AsyncReadStream,
1728 typename DynamicBuffer_v2, typename ReadHandler>
1729 class read_until_delim_op_v2
1730 : public base_from_cancellation_state<ReadHandler>
1731 {
1732 public:
1733 template <typename BufferSequence>
1734 read_until_delim_op_v2(AsyncReadStream& stream,
1735 BufferSequence&& buffers,
1736 char delim, ReadHandler& handler)
1737 : base_from_cancellation_state<ReadHandler>(
1738 handler, enable_partial_cancellation()),
1739 stream_(stream),
1740 buffers_(static_cast<BufferSequence&&>(buffers)),
1741 delim_(delim),
1742 start_(0),
1743 search_position_(0),
1744 bytes_to_read_(0),
1745 handler_(static_cast<ReadHandler&&>(handler))
1746 {
1747 }
1748
1749 read_until_delim_op_v2(const read_until_delim_op_v2& other)
1750 : base_from_cancellation_state<ReadHandler>(other),
1751 stream_(other.stream_),
1752 buffers_(other.buffers_),
1753 delim_(other.delim_),
1754 start_(other.start_),
1755 search_position_(other.search_position_),
1756 bytes_to_read_(other.bytes_to_read_),
1757 handler_(other.handler_)
1758 {
1759 }
1760
1761 read_until_delim_op_v2(read_until_delim_op_v2&& other)
1762 : base_from_cancellation_state<ReadHandler>(
1763 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1764 stream_(other.stream_),
1765 buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
1766 delim_(other.delim_),
1767 start_(other.start_),
1768 search_position_(other.search_position_),
1769 bytes_to_read_(other.bytes_to_read_),
1770 handler_(static_cast<ReadHandler&&>(other.handler_))
1771 {
1772 }
1773
1774 void operator()(boost::system::error_code ec,
1775 std::size_t bytes_transferred, int start = 0)
1776 {
1777 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1778 std::size_t pos;
1779 switch (start_ = start)
1780 {
1781 case 1:
1782 for (;;)
1783 {
1784 {
1785
1786 typedef typename DynamicBuffer_v2::const_buffers_type
1787 buffers_type;
1788 typedef buffers_iterator<buffers_type> iterator;
1789 buffers_type data_buffers =
1790 const_cast<const DynamicBuffer_v2&>(buffers_).data(
1791 0, buffers_.size());
1792 iterator begin = iterator::begin(data_buffers);
1793 iterator start_pos = begin + search_position_;
1794 iterator end = iterator::end(data_buffers);
1795
1796
1797 iterator iter = std::find(start_pos, end, delim_);
1798 if (iter != end)
1799 {
1800
1801 search_position_ = iter - begin + 1;
1802 bytes_to_read_ = 0;
1803 }
1804
1805
1806 else if (buffers_.size() == buffers_.max_size())
1807 {
1808 search_position_ = not_found;
1809 bytes_to_read_ = 0;
1810 }
1811
1812
1813 else
1814 {
1815
1816 search_position_ = end - begin;
1817 bytes_to_read_ = std::min<std::size_t>(
1818 std::max<std::size_t>(512,
1819 buffers_.capacity() - buffers_.size()),
1820 std::min<std::size_t>(65536,
1821 buffers_.max_size() - buffers_.size()));
1822 }
1823 }
1824
1825
1826 if (!start && bytes_to_read_ == 0)
1827 break;
1828
1829
1830 pos = buffers_.size();
1831 buffers_.grow(bytes_to_read_);
1832 {
1833 BOOST_ASIO_HANDLER_LOCATION((
1834 __FILE__, __LINE__, "async_read_until"));
1835 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
1836 static_cast<read_until_delim_op_v2&&>(*this));
1837 }
1838 return; default:
1839 buffers_.shrink(bytes_to_read_ - bytes_transferred);
1840 if (ec || bytes_transferred == 0)
1841 break;
1842 if (this->cancelled() != cancellation_type::none)
1843 {
1844 ec = error::operation_aborted;
1845 break;
1846 }
1847 }
1848
1849 const boost::system::error_code result_ec =
1850 (search_position_ == not_found)
1851 ? error::not_found : ec;
1852
1853 const std::size_t result_n =
1854 (ec || search_position_ == not_found)
1855 ? 0 : search_position_;
1856
1857 static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
1858 }
1859 }
1860
1861
1862 AsyncReadStream& stream_;
1863 DynamicBuffer_v2 buffers_;
1864 char delim_;
1865 int start_;
1866 std::size_t search_position_;
1867 std::size_t bytes_to_read_;
1868 ReadHandler handler_;
1869 };
1870
1871 template <typename AsyncReadStream,
1872 typename DynamicBuffer_v2, typename ReadHandler>
1873 inline bool asio_handler_is_continuation(
1874 read_until_delim_op_v2<AsyncReadStream,
1875 DynamicBuffer_v2, ReadHandler>* this_handler)
1876 {
1877 return this_handler->start_ == 0 ? true
1878 : boost_asio_handler_cont_helpers::is_continuation(
1879 this_handler->handler_);
1880 }
1881
1882 template <typename AsyncReadStream>
1883 class initiate_async_read_until_delim_v2
1884 {
1885 public:
1886 typedef typename AsyncReadStream::executor_type executor_type;
1887
1888 explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream)
1889 : stream_(stream)
1890 {
1891 }
1892
1893 executor_type get_executor() const noexcept
1894 {
1895 return stream_.get_executor();
1896 }
1897
1898 template <typename ReadHandler, typename DynamicBuffer_v2>
1899 void operator()(ReadHandler&& handler,
1900 DynamicBuffer_v2&& buffers, char delim) const
1901 {
1902
1903
1904 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1905
1906 non_const_lvalue<ReadHandler> handler2(handler);
1907 read_until_delim_op_v2<AsyncReadStream,
1908 decay_t<DynamicBuffer_v2>,
1909 decay_t<ReadHandler>>(
1910 stream_, static_cast<DynamicBuffer_v2&&>(buffers),
1911 delim, handler2.value)(boost::system::error_code(), 0, 1);
1912 }
1913
1914 private:
1915 AsyncReadStream& stream_;
1916 };
1917 }
1918
1919 #if !defined(GENERATING_DOCUMENTATION)
1920
1921 template <template <typename, typename> class Associator,
1922 typename AsyncReadStream, typename DynamicBuffer_v2,
1923 typename ReadHandler, typename DefaultCandidate>
1924 struct associator<Associator,
1925 detail::read_until_delim_op_v2<AsyncReadStream,
1926 DynamicBuffer_v2, ReadHandler>,
1927 DefaultCandidate>
1928 : Associator<ReadHandler, DefaultCandidate>
1929 {
1930 static typename Associator<ReadHandler, DefaultCandidate>::type get(
1931 const detail::read_until_delim_op_v2<AsyncReadStream,
1932 DynamicBuffer_v2, ReadHandler>& h) noexcept
1933 {
1934 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
1935 }
1936
1937 static auto get(
1938 const detail::read_until_delim_op_v2<AsyncReadStream,
1939 DynamicBuffer_v2, ReadHandler>& h,
1940 const DefaultCandidate& c) noexcept
1941 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
1942 {
1943 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
1944 }
1945 };
1946
1947 #endif
1948
1949 namespace detail
1950 {
1951 template <typename AsyncReadStream,
1952 typename DynamicBuffer_v2, typename ReadHandler>
1953 class read_until_delim_string_op_v2
1954 : public base_from_cancellation_state<ReadHandler>
1955 {
1956 public:
1957 template <typename BufferSequence>
1958 read_until_delim_string_op_v2(AsyncReadStream& stream,
1959 BufferSequence&& buffers,
1960 const std::string& delim, ReadHandler& handler)
1961 : base_from_cancellation_state<ReadHandler>(
1962 handler, enable_partial_cancellation()),
1963 stream_(stream),
1964 buffers_(static_cast<BufferSequence&&>(buffers)),
1965 delim_(delim),
1966 start_(0),
1967 search_position_(0),
1968 bytes_to_read_(0),
1969 handler_(static_cast<ReadHandler&&>(handler))
1970 {
1971 }
1972
1973 read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other)
1974 : base_from_cancellation_state<ReadHandler>(other),
1975 stream_(other.stream_),
1976 buffers_(other.buffers_),
1977 delim_(other.delim_),
1978 start_(other.start_),
1979 search_position_(other.search_position_),
1980 bytes_to_read_(other.bytes_to_read_),
1981 handler_(other.handler_)
1982 {
1983 }
1984
1985 read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other)
1986 : base_from_cancellation_state<ReadHandler>(
1987 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
1988 stream_(other.stream_),
1989 buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
1990 delim_(static_cast<std::string&&>(other.delim_)),
1991 start_(other.start_),
1992 search_position_(other.search_position_),
1993 bytes_to_read_(other.bytes_to_read_),
1994 handler_(static_cast<ReadHandler&&>(other.handler_))
1995 {
1996 }
1997
1998 void operator()(boost::system::error_code ec,
1999 std::size_t bytes_transferred, int start = 0)
2000 {
2001 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
2002 std::size_t pos;
2003 switch (start_ = start)
2004 {
2005 case 1:
2006 for (;;)
2007 {
2008 {
2009
2010 typedef typename DynamicBuffer_v2::const_buffers_type
2011 buffers_type;
2012 typedef buffers_iterator<buffers_type> iterator;
2013 buffers_type data_buffers =
2014 const_cast<const DynamicBuffer_v2&>(buffers_).data(
2015 0, buffers_.size());
2016 iterator begin = iterator::begin(data_buffers);
2017 iterator start_pos = begin + search_position_;
2018 iterator end = iterator::end(data_buffers);
2019
2020
2021 std::pair<iterator, bool> result = detail::partial_search(
2022 start_pos, end, delim_.begin(), delim_.end());
2023 if (result.first != end && result.second)
2024 {
2025
2026 search_position_ = result.first - begin + delim_.length();
2027 bytes_to_read_ = 0;
2028 }
2029
2030
2031 else if (buffers_.size() == buffers_.max_size())
2032 {
2033 search_position_ = not_found;
2034 bytes_to_read_ = 0;
2035 }
2036
2037
2038 else
2039 {
2040 if (result.first != end)
2041 {
2042
2043
2044 search_position_ = result.first - begin;
2045 }
2046 else
2047 {
2048
2049 search_position_ = end - begin;
2050 }
2051
2052 bytes_to_read_ = std::min<std::size_t>(
2053 std::max<std::size_t>(512,
2054 buffers_.capacity() - buffers_.size()),
2055 std::min<std::size_t>(65536,
2056 buffers_.max_size() - buffers_.size()));
2057 }
2058 }
2059
2060
2061 if (!start && bytes_to_read_ == 0)
2062 break;
2063
2064
2065 pos = buffers_.size();
2066 buffers_.grow(bytes_to_read_);
2067 {
2068 BOOST_ASIO_HANDLER_LOCATION((
2069 __FILE__, __LINE__, "async_read_until"));
2070 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2071 static_cast<read_until_delim_string_op_v2&&>(*this));
2072 }
2073 return; default:
2074 buffers_.shrink(bytes_to_read_ - bytes_transferred);
2075 if (ec || bytes_transferred == 0)
2076 break;
2077 if (this->cancelled() != cancellation_type::none)
2078 {
2079 ec = error::operation_aborted;
2080 break;
2081 }
2082 }
2083
2084 const boost::system::error_code result_ec =
2085 (search_position_ == not_found)
2086 ? error::not_found : ec;
2087
2088 const std::size_t result_n =
2089 (ec || search_position_ == not_found)
2090 ? 0 : search_position_;
2091
2092 static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
2093 }
2094 }
2095
2096
2097 AsyncReadStream& stream_;
2098 DynamicBuffer_v2 buffers_;
2099 std::string delim_;
2100 int start_;
2101 std::size_t search_position_;
2102 std::size_t bytes_to_read_;
2103 ReadHandler handler_;
2104 };
2105
2106 template <typename AsyncReadStream,
2107 typename DynamicBuffer_v2, typename ReadHandler>
2108 inline bool asio_handler_is_continuation(
2109 read_until_delim_string_op_v2<AsyncReadStream,
2110 DynamicBuffer_v2, ReadHandler>* this_handler)
2111 {
2112 return this_handler->start_ == 0 ? true
2113 : boost_asio_handler_cont_helpers::is_continuation(
2114 this_handler->handler_);
2115 }
2116
2117 template <typename AsyncReadStream>
2118 class initiate_async_read_until_delim_string_v2
2119 {
2120 public:
2121 typedef typename AsyncReadStream::executor_type executor_type;
2122
2123 explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream)
2124 : stream_(stream)
2125 {
2126 }
2127
2128 executor_type get_executor() const noexcept
2129 {
2130 return stream_.get_executor();
2131 }
2132
2133 template <typename ReadHandler, typename DynamicBuffer_v2>
2134 void operator()(ReadHandler&& handler,
2135 DynamicBuffer_v2&& buffers,
2136 const std::string& delim) const
2137 {
2138
2139
2140 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2141
2142 non_const_lvalue<ReadHandler> handler2(handler);
2143 read_until_delim_string_op_v2<AsyncReadStream,
2144 decay_t<DynamicBuffer_v2>,
2145 decay_t<ReadHandler>>(
2146 stream_, static_cast<DynamicBuffer_v2&&>(buffers),
2147 delim, handler2.value)(boost::system::error_code(), 0, 1);
2148 }
2149
2150 private:
2151 AsyncReadStream& stream_;
2152 };
2153 }
2154
2155 #if !defined(GENERATING_DOCUMENTATION)
2156
2157 template <template <typename, typename> class Associator,
2158 typename AsyncReadStream, typename DynamicBuffer_v2,
2159 typename ReadHandler, typename DefaultCandidate>
2160 struct associator<Associator,
2161 detail::read_until_delim_string_op_v2<AsyncReadStream,
2162 DynamicBuffer_v2, ReadHandler>,
2163 DefaultCandidate>
2164 : Associator<ReadHandler, DefaultCandidate>
2165 {
2166 static typename Associator<ReadHandler, DefaultCandidate>::type get(
2167 const detail::read_until_delim_string_op_v2<
2168 AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h) noexcept
2169 {
2170 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
2171 }
2172
2173 static auto get(
2174 const detail::read_until_delim_string_op_v2<
2175 AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h,
2176 const DefaultCandidate& c) noexcept
2177 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
2178 {
2179 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
2180 }
2181 };
2182
2183 #endif
2184
2185 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
2186 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
2187
2188 namespace detail
2189 {
2190 template <typename AsyncReadStream, typename DynamicBuffer_v2,
2191 typename RegEx, typename ReadHandler>
2192 class read_until_expr_op_v2
2193 : public base_from_cancellation_state<ReadHandler>
2194 {
2195 public:
2196 template <typename BufferSequence, typename Traits>
2197 read_until_expr_op_v2(AsyncReadStream& stream, BufferSequence&& buffers,
2198 const boost::basic_regex<char, Traits>& expr, ReadHandler& handler)
2199 : base_from_cancellation_state<ReadHandler>(
2200 handler, enable_partial_cancellation()),
2201 stream_(stream),
2202 buffers_(static_cast<BufferSequence&&>(buffers)),
2203 expr_(expr),
2204 start_(0),
2205 search_position_(0),
2206 bytes_to_read_(0),
2207 handler_(static_cast<ReadHandler&&>(handler))
2208 {
2209 }
2210
2211 read_until_expr_op_v2(const read_until_expr_op_v2& other)
2212 : base_from_cancellation_state<ReadHandler>(other),
2213 stream_(other.stream_),
2214 buffers_(other.buffers_),
2215 expr_(other.expr_),
2216 start_(other.start_),
2217 search_position_(other.search_position_),
2218 bytes_to_read_(other.bytes_to_read_),
2219 handler_(other.handler_)
2220 {
2221 }
2222
2223 read_until_expr_op_v2(read_until_expr_op_v2&& other)
2224 : base_from_cancellation_state<ReadHandler>(
2225 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
2226 stream_(other.stream_),
2227 buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
2228 expr_(other.expr_),
2229 start_(other.start_),
2230 search_position_(other.search_position_),
2231 bytes_to_read_(other.bytes_to_read_),
2232 handler_(static_cast<ReadHandler&&>(other.handler_))
2233 {
2234 }
2235
2236 void operator()(boost::system::error_code ec,
2237 std::size_t bytes_transferred, int start = 0)
2238 {
2239 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
2240 std::size_t pos;
2241 switch (start_ = start)
2242 {
2243 case 1:
2244 for (;;)
2245 {
2246 {
2247
2248 typedef typename DynamicBuffer_v2::const_buffers_type
2249 buffers_type;
2250 typedef buffers_iterator<buffers_type> iterator;
2251 buffers_type data_buffers =
2252 const_cast<const DynamicBuffer_v2&>(buffers_).data(
2253 0, buffers_.size());
2254 iterator begin = iterator::begin(data_buffers);
2255 iterator start_pos = begin + search_position_;
2256 iterator end = iterator::end(data_buffers);
2257
2258
2259 boost::match_results<iterator,
2260 typename std::vector<boost::sub_match<iterator>>::allocator_type>
2261 match_results;
2262 bool match = regex_search(start_pos, end,
2263 match_results, expr_, regex_match_flags());
2264 if (match && match_results[0].matched)
2265 {
2266
2267 search_position_ = match_results[0].second - begin;
2268 bytes_to_read_ = 0;
2269 }
2270
2271
2272 else if (buffers_.size() == buffers_.max_size())
2273 {
2274 search_position_ = not_found;
2275 bytes_to_read_ = 0;
2276 }
2277
2278
2279 else
2280 {
2281 if (match)
2282 {
2283
2284
2285 search_position_ = match_results[0].first - begin;
2286 }
2287 else
2288 {
2289
2290 search_position_ = end - begin;
2291 }
2292
2293 bytes_to_read_ = std::min<std::size_t>(
2294 std::max<std::size_t>(512,
2295 buffers_.capacity() - buffers_.size()),
2296 std::min<std::size_t>(65536,
2297 buffers_.max_size() - buffers_.size()));
2298 }
2299 }
2300
2301
2302 if (!start && bytes_to_read_ == 0)
2303 break;
2304
2305
2306 pos = buffers_.size();
2307 buffers_.grow(bytes_to_read_);
2308 {
2309 BOOST_ASIO_HANDLER_LOCATION((
2310 __FILE__, __LINE__, "async_read_until"));
2311 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2312 static_cast<read_until_expr_op_v2&&>(*this));
2313 }
2314 return; default:
2315 buffers_.shrink(bytes_to_read_ - bytes_transferred);
2316 if (ec || bytes_transferred == 0)
2317 break;
2318 if (this->cancelled() != cancellation_type::none)
2319 {
2320 ec = error::operation_aborted;
2321 break;
2322 }
2323 }
2324
2325 const boost::system::error_code result_ec =
2326 (search_position_ == not_found)
2327 ? error::not_found : ec;
2328
2329 const std::size_t result_n =
2330 (ec || search_position_ == not_found)
2331 ? 0 : search_position_;
2332
2333 static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
2334 }
2335 }
2336
2337
2338 AsyncReadStream& stream_;
2339 DynamicBuffer_v2 buffers_;
2340 RegEx expr_;
2341 int start_;
2342 std::size_t search_position_;
2343 std::size_t bytes_to_read_;
2344 ReadHandler handler_;
2345 };
2346
2347 template <typename AsyncReadStream, typename DynamicBuffer_v2,
2348 typename RegEx, typename ReadHandler>
2349 inline bool asio_handler_is_continuation(
2350 read_until_expr_op_v2<AsyncReadStream,
2351 DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
2352 {
2353 return this_handler->start_ == 0 ? true
2354 : boost_asio_handler_cont_helpers::is_continuation(
2355 this_handler->handler_);
2356 }
2357
2358 template <typename AsyncReadStream>
2359 class initiate_async_read_until_expr_v2
2360 {
2361 public:
2362 typedef typename AsyncReadStream::executor_type executor_type;
2363
2364 explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream)
2365 : stream_(stream)
2366 {
2367 }
2368
2369 executor_type get_executor() const noexcept
2370 {
2371 return stream_.get_executor();
2372 }
2373
2374 template <typename ReadHandler, typename DynamicBuffer_v2, typename RegEx>
2375 void operator()(ReadHandler&& handler,
2376 DynamicBuffer_v2&& buffers,
2377 const RegEx& expr) const
2378 {
2379
2380
2381 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2382
2383 non_const_lvalue<ReadHandler> handler2(handler);
2384 read_until_expr_op_v2<AsyncReadStream,
2385 decay_t<DynamicBuffer_v2>,
2386 RegEx, decay_t<ReadHandler>>(
2387 stream_, static_cast<DynamicBuffer_v2&&>(buffers),
2388 expr, handler2.value)(boost::system::error_code(), 0, 1);
2389 }
2390
2391 private:
2392 AsyncReadStream& stream_;
2393 };
2394 }
2395
2396 #if !defined(GENERATING_DOCUMENTATION)
2397
2398 template <template <typename, typename> class Associator,
2399 typename AsyncReadStream, typename DynamicBuffer_v2,
2400 typename RegEx, typename ReadHandler, typename DefaultCandidate>
2401 struct associator<Associator,
2402 detail::read_until_expr_op_v2<AsyncReadStream,
2403 DynamicBuffer_v2, RegEx, ReadHandler>,
2404 DefaultCandidate>
2405 : Associator<ReadHandler, DefaultCandidate>
2406 {
2407 static typename Associator<ReadHandler, DefaultCandidate>::type get(
2408 const detail::read_until_expr_op_v2<AsyncReadStream,
2409 DynamicBuffer_v2, RegEx, ReadHandler>& h) noexcept
2410 {
2411 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
2412 }
2413
2414 static auto get(
2415 const detail::read_until_expr_op_v2<AsyncReadStream,
2416 DynamicBuffer_v2, RegEx, ReadHandler>& h,
2417 const DefaultCandidate& c) noexcept
2418 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
2419 {
2420 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
2421 }
2422 };
2423
2424 #endif
2425
2426 #endif
2427
2428 namespace detail
2429 {
2430 template <typename AsyncReadStream, typename DynamicBuffer_v2,
2431 typename MatchCondition, typename ReadHandler>
2432 class read_until_match_op_v2
2433 : public base_from_cancellation_state<ReadHandler>
2434 {
2435 public:
2436 template <typename BufferSequence>
2437 read_until_match_op_v2(AsyncReadStream& stream,
2438 BufferSequence&& buffers,
2439 MatchCondition match_condition, ReadHandler& handler)
2440 : base_from_cancellation_state<ReadHandler>(
2441 handler, enable_partial_cancellation()),
2442 stream_(stream),
2443 buffers_(static_cast<BufferSequence&&>(buffers)),
2444 match_condition_(match_condition),
2445 start_(0),
2446 search_position_(0),
2447 bytes_to_read_(0),
2448 handler_(static_cast<ReadHandler&&>(handler))
2449 {
2450 }
2451
2452 read_until_match_op_v2(const read_until_match_op_v2& other)
2453 : base_from_cancellation_state<ReadHandler>(other),
2454 stream_(other.stream_),
2455 buffers_(other.buffers_),
2456 match_condition_(other.match_condition_),
2457 start_(other.start_),
2458 search_position_(other.search_position_),
2459 bytes_to_read_(other.bytes_to_read_),
2460 handler_(other.handler_)
2461 {
2462 }
2463
2464 read_until_match_op_v2(read_until_match_op_v2&& other)
2465 : base_from_cancellation_state<ReadHandler>(
2466 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
2467 stream_(other.stream_),
2468 buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)),
2469 match_condition_(other.match_condition_),
2470 start_(other.start_),
2471 search_position_(other.search_position_),
2472 bytes_to_read_(other.bytes_to_read_),
2473 handler_(static_cast<ReadHandler&&>(other.handler_))
2474 {
2475 }
2476
2477 void operator()(boost::system::error_code ec,
2478 std::size_t bytes_transferred, int start = 0)
2479 {
2480 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
2481 std::size_t pos;
2482 switch (start_ = start)
2483 {
2484 case 1:
2485 for (;;)
2486 {
2487 {
2488
2489 typedef typename DynamicBuffer_v2::const_buffers_type
2490 buffers_type;
2491 typedef buffers_iterator<buffers_type> iterator;
2492 buffers_type data_buffers =
2493 const_cast<const DynamicBuffer_v2&>(buffers_).data(
2494 0, buffers_.size());
2495 iterator begin = iterator::begin(data_buffers);
2496 iterator start_pos = begin + search_position_;
2497 iterator end = iterator::end(data_buffers);
2498
2499
2500 std::pair<iterator, bool> result = match_condition_(start_pos, end);
2501 if (result.second)
2502 {
2503
2504 search_position_ = result.first - begin;
2505 bytes_to_read_ = 0;
2506 }
2507
2508
2509 else if (buffers_.size() == buffers_.max_size())
2510 {
2511 search_position_ = not_found;
2512 bytes_to_read_ = 0;
2513 }
2514
2515
2516 else
2517 {
2518 if (result.first != end)
2519 {
2520
2521
2522 search_position_ = result.first - begin;
2523 }
2524 else
2525 {
2526
2527 search_position_ = end - begin;
2528 }
2529
2530 bytes_to_read_ = std::min<std::size_t>(
2531 std::max<std::size_t>(512,
2532 buffers_.capacity() - buffers_.size()),
2533 std::min<std::size_t>(65536,
2534 buffers_.max_size() - buffers_.size()));
2535 }
2536 }
2537
2538
2539 if (!start && bytes_to_read_ == 0)
2540 break;
2541
2542
2543 pos = buffers_.size();
2544 buffers_.grow(bytes_to_read_);
2545 {
2546 BOOST_ASIO_HANDLER_LOCATION((
2547 __FILE__, __LINE__, "async_read_until"));
2548 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2549 static_cast<read_until_match_op_v2&&>(*this));
2550 }
2551 return; default:
2552 buffers_.shrink(bytes_to_read_ - bytes_transferred);
2553 if (ec || bytes_transferred == 0)
2554 break;
2555 if (this->cancelled() != cancellation_type::none)
2556 {
2557 ec = error::operation_aborted;
2558 break;
2559 }
2560 }
2561
2562 const boost::system::error_code result_ec =
2563 (search_position_ == not_found)
2564 ? error::not_found : ec;
2565
2566 const std::size_t result_n =
2567 (ec || search_position_ == not_found)
2568 ? 0 : search_position_;
2569
2570 static_cast<ReadHandler&&>(handler_)(result_ec, result_n);
2571 }
2572 }
2573
2574
2575 AsyncReadStream& stream_;
2576 DynamicBuffer_v2 buffers_;
2577 MatchCondition match_condition_;
2578 int start_;
2579 std::size_t search_position_;
2580 std::size_t bytes_to_read_;
2581 ReadHandler handler_;
2582 };
2583
2584 template <typename AsyncReadStream, typename DynamicBuffer_v2,
2585 typename MatchCondition, typename ReadHandler>
2586 inline bool asio_handler_is_continuation(
2587 read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
2588 MatchCondition, ReadHandler>* this_handler)
2589 {
2590 return this_handler->start_ == 0 ? true
2591 : boost_asio_handler_cont_helpers::is_continuation(
2592 this_handler->handler_);
2593 }
2594
2595 template <typename AsyncReadStream>
2596 class initiate_async_read_until_match_v2
2597 {
2598 public:
2599 typedef typename AsyncReadStream::executor_type executor_type;
2600
2601 explicit initiate_async_read_until_match_v2(AsyncReadStream& stream)
2602 : stream_(stream)
2603 {
2604 }
2605
2606 executor_type get_executor() const noexcept
2607 {
2608 return stream_.get_executor();
2609 }
2610
2611 template <typename ReadHandler,
2612 typename DynamicBuffer_v2, typename MatchCondition>
2613 void operator()(ReadHandler&& handler,
2614 DynamicBuffer_v2&& buffers,
2615 MatchCondition match_condition) const
2616 {
2617
2618
2619 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2620
2621 non_const_lvalue<ReadHandler> handler2(handler);
2622 read_until_match_op_v2<AsyncReadStream, decay_t<DynamicBuffer_v2>,
2623 MatchCondition, decay_t<ReadHandler>>(
2624 stream_, static_cast<DynamicBuffer_v2&&>(buffers),
2625 match_condition, handler2.value)(boost::system::error_code(), 0, 1);
2626 }
2627
2628 private:
2629 AsyncReadStream& stream_;
2630 };
2631 }
2632
2633 #if !defined(GENERATING_DOCUMENTATION)
2634
2635 template <template <typename, typename> class Associator,
2636 typename AsyncReadStream, typename DynamicBuffer_v2,
2637 typename MatchCondition, typename ReadHandler, typename DefaultCandidate>
2638 struct associator<Associator,
2639 detail::read_until_match_op_v2<AsyncReadStream,
2640 DynamicBuffer_v2, MatchCondition, ReadHandler>,
2641 DefaultCandidate>
2642 : Associator<ReadHandler, DefaultCandidate>
2643 {
2644 static typename Associator<ReadHandler, DefaultCandidate>::type get(
2645 const detail::read_until_match_op_v2<AsyncReadStream,
2646 DynamicBuffer_v2, MatchCondition, ReadHandler>& h) noexcept
2647 {
2648 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
2649 }
2650
2651 static auto get(
2652 const detail::read_until_match_op_v2<AsyncReadStream,
2653 DynamicBuffer_v2, MatchCondition, ReadHandler>& h,
2654 const DefaultCandidate& c) noexcept
2655 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
2656 {
2657 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
2658 }
2659 };
2660
2661 #endif
2662
2663 #endif
2664
2665 }
2666 }
2667
2668 #include <boost/asio/detail/pop_options.hpp>
2669
2670 #endif