]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/impl/read_until.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / asio / impl / read_until.hpp
CommitLineData
7c673cae
FG
1//
2// impl/read_until.hpp
3// ~~~~~~~~~~~~~~~~~~~
4//
1e59de90 5// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7c673cae
FG
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
12#define BOOST_ASIO_IMPL_READ_UNTIL_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <algorithm>
19#include <string>
20#include <vector>
21#include <utility>
1e59de90 22#include <boost/asio/associator.hpp>
7c673cae
FG
23#include <boost/asio/buffer.hpp>
24#include <boost/asio/buffers_iterator.hpp>
1e59de90 25#include <boost/asio/detail/base_from_cancellation_state.hpp>
7c673cae
FG
26#include <boost/asio/detail/bind_handler.hpp>
27#include <boost/asio/detail/handler_alloc_helpers.hpp>
28#include <boost/asio/detail/handler_cont_helpers.hpp>
29#include <boost/asio/detail/handler_invoke_helpers.hpp>
20effc67 30#include <boost/asio/detail/handler_tracking.hpp>
7c673cae
FG
31#include <boost/asio/detail/handler_type_requirements.hpp>
32#include <boost/asio/detail/limits.hpp>
92f5a8d4 33#include <boost/asio/detail/non_const_lvalue.hpp>
7c673cae
FG
34#include <boost/asio/detail/throw_error.hpp>
35
36#include <boost/asio/detail/push_options.hpp>
37
38namespace boost {
39namespace asio {
40
92f5a8d4
TL
41namespace detail
42{
43 // Algorithm that finds a subsequence of equal values in a sequence. Returns
44 // (iterator,true) if a full match was found, in which case the iterator
45 // points to the beginning of the match. Returns (iterator,false) if a
46 // partial match was found at the end of the first sequence, in which case
47 // the iterator points to the beginning of the partial match. Returns
48 // (last1,false) if no full or partial match was found.
49 template <typename Iterator1, typename Iterator2>
50 std::pair<Iterator1, bool> partial_search(
51 Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
52 {
53 for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
54 {
55 Iterator1 test_iter1 = iter1;
56 Iterator2 test_iter2 = first2;
57 for (;; ++test_iter1, ++test_iter2)
58 {
59 if (test_iter2 == last2)
60 return std::make_pair(iter1, true);
61 if (test_iter1 == last1)
62 {
63 if (test_iter2 != first2)
64 return std::make_pair(iter1, false);
65 else
66 break;
67 }
68 if (*test_iter1 != *test_iter2)
69 break;
70 }
71 }
72 return std::make_pair(last1, false);
73 }
74} // namespace detail
75
76#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
77
78template <typename SyncReadStream, typename DynamicBuffer_v1>
7c673cae 79inline std::size_t read_until(SyncReadStream& s,
92f5a8d4 80 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim,
1e59de90 81 typename constraint<
92f5a8d4 82 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
83 >::type,
84 typename constraint<
85 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
86 >::type)
7c673cae
FG
87{
88 boost::system::error_code ec;
b32b8144 89 std::size_t bytes_transferred = read_until(s,
92f5a8d4 90 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec);
7c673cae
FG
91 boost::asio::detail::throw_error(ec, "read_until");
92 return bytes_transferred;
93}
94
92f5a8d4 95template <typename SyncReadStream, typename DynamicBuffer_v1>
7c673cae 96std::size_t read_until(SyncReadStream& s,
92f5a8d4
TL
97 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
98 char delim, boost::system::error_code& ec,
1e59de90 99 typename constraint<
92f5a8d4 100 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
101 >::type,
102 typename constraint<
103 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
104 >::type)
7c673cae 105{
92f5a8d4
TL
106 typename decay<DynamicBuffer_v1>::type b(
107 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
b32b8144 108
7c673cae
FG
109 std::size_t search_position = 0;
110 for (;;)
111 {
112 // Determine the range of the data to be searched.
92f5a8d4 113 typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
b32b8144
FG
114 typedef buffers_iterator<buffers_type> iterator;
115 buffers_type data_buffers = b.data();
116 iterator begin = iterator::begin(data_buffers);
7c673cae 117 iterator start_pos = begin + search_position;
b32b8144 118 iterator end = iterator::end(data_buffers);
7c673cae
FG
119
120 // Look for a match.
121 iterator iter = std::find(start_pos, end, delim);
122 if (iter != end)
123 {
124 // Found a match. We're done.
125 ec = boost::system::error_code();
126 return iter - begin + 1;
127 }
128 else
129 {
130 // No match. Next search can start with the new data.
131 search_position = end - begin;
132 }
133
134 // Check if buffer is full.
135 if (b.size() == b.max_size())
136 {
137 ec = error::not_found;
138 return 0;
139 }
140
141 // Need more data.
b32b8144
FG
142 std::size_t bytes_to_read = std::min<std::size_t>(
143 std::max<std::size_t>(512, b.capacity() - b.size()),
144 std::min<std::size_t>(65536, b.max_size() - b.size()));
7c673cae
FG
145 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
146 if (ec)
147 return 0;
148 }
149}
150
92f5a8d4 151template <typename SyncReadStream, typename DynamicBuffer_v1>
7c673cae 152inline std::size_t read_until(SyncReadStream& s,
92f5a8d4
TL
153 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
154 BOOST_ASIO_STRING_VIEW_PARAM delim,
1e59de90 155 typename constraint<
92f5a8d4 156 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
157 >::type,
158 typename constraint<
159 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
160 >::type)
7c673cae
FG
161{
162 boost::system::error_code ec;
b32b8144 163 std::size_t bytes_transferred = read_until(s,
92f5a8d4 164 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec);
7c673cae
FG
165 boost::asio::detail::throw_error(ec, "read_until");
166 return bytes_transferred;
167}
168
92f5a8d4 169template <typename SyncReadStream, typename DynamicBuffer_v1>
7c673cae 170std::size_t read_until(SyncReadStream& s,
92f5a8d4
TL
171 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
172 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec,
1e59de90 173 typename constraint<
92f5a8d4 174 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
175 >::type,
176 typename constraint<
177 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
178 >::type)
7c673cae 179{
92f5a8d4
TL
180 typename decay<DynamicBuffer_v1>::type b(
181 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
b32b8144 182
7c673cae
FG
183 std::size_t search_position = 0;
184 for (;;)
185 {
186 // Determine the range of the data to be searched.
92f5a8d4 187 typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
b32b8144
FG
188 typedef buffers_iterator<buffers_type> iterator;
189 buffers_type data_buffers = b.data();
190 iterator begin = iterator::begin(data_buffers);
7c673cae 191 iterator start_pos = begin + search_position;
b32b8144 192 iterator end = iterator::end(data_buffers);
7c673cae
FG
193
194 // Look for a match.
195 std::pair<iterator, bool> result = detail::partial_search(
196 start_pos, end, delim.begin(), delim.end());
197 if (result.first != end)
198 {
199 if (result.second)
200 {
201 // Full match. We're done.
202 ec = boost::system::error_code();
203 return result.first - begin + delim.length();
204 }
205 else
206 {
207 // Partial match. Next search needs to start from beginning of match.
208 search_position = result.first - begin;
209 }
210 }
211 else
212 {
213 // No match. Next search can start with the new data.
214 search_position = end - begin;
215 }
216
217 // Check if buffer is full.
218 if (b.size() == b.max_size())
219 {
220 ec = error::not_found;
221 return 0;
222 }
223
224 // Need more data.
b32b8144
FG
225 std::size_t bytes_to_read = std::min<std::size_t>(
226 std::max<std::size_t>(512, b.capacity() - b.size()),
227 std::min<std::size_t>(65536, b.max_size() - b.size()));
7c673cae
FG
228 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
229 if (ec)
230 return 0;
231 }
232}
233
b32b8144 234#if !defined(BOOST_ASIO_NO_EXTENSIONS)
7c673cae
FG
235#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
236
92f5a8d4 237template <typename SyncReadStream, typename DynamicBuffer_v1>
7c673cae 238inline std::size_t read_until(SyncReadStream& s,
92f5a8d4
TL
239 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
240 const boost::regex& expr,
1e59de90 241 typename constraint<
92f5a8d4 242 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
243 >::type,
244 typename constraint<
245 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
246 >::type)
7c673cae
FG
247{
248 boost::system::error_code ec;
b32b8144 249 std::size_t bytes_transferred = read_until(s,
92f5a8d4 250 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr, ec);
7c673cae
FG
251 boost::asio::detail::throw_error(ec, "read_until");
252 return bytes_transferred;
253}
254
92f5a8d4 255template <typename SyncReadStream, typename DynamicBuffer_v1>
7c673cae 256std::size_t read_until(SyncReadStream& s,
92f5a8d4
TL
257 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
258 const boost::regex& expr, boost::system::error_code& ec,
1e59de90 259 typename constraint<
92f5a8d4 260 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
261 >::type,
262 typename constraint<
263 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
264 >::type)
7c673cae 265{
92f5a8d4
TL
266 typename decay<DynamicBuffer_v1>::type b(
267 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
b32b8144 268
7c673cae
FG
269 std::size_t search_position = 0;
270 for (;;)
271 {
272 // Determine the range of the data to be searched.
92f5a8d4 273 typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
b32b8144
FG
274 typedef buffers_iterator<buffers_type> iterator;
275 buffers_type data_buffers = b.data();
276 iterator begin = iterator::begin(data_buffers);
7c673cae 277 iterator start_pos = begin + search_position;
b32b8144 278 iterator end = iterator::end(data_buffers);
7c673cae
FG
279
280 // Look for a match.
281 boost::match_results<iterator,
282 typename std::vector<boost::sub_match<iterator> >::allocator_type>
283 match_results;
284 if (regex_search(start_pos, end, match_results, expr,
285 boost::match_default | boost::match_partial))
286 {
287 if (match_results[0].matched)
288 {
289 // Full match. We're done.
290 ec = boost::system::error_code();
291 return match_results[0].second - begin;
292 }
293 else
294 {
295 // Partial match. Next search needs to start from beginning of match.
296 search_position = match_results[0].first - begin;
297 }
298 }
299 else
300 {
301 // No match. Next search can start with the new data.
302 search_position = end - begin;
303 }
304
305 // Check if buffer is full.
306 if (b.size() == b.max_size())
307 {
308 ec = error::not_found;
309 return 0;
310 }
311
312 // Need more data.
92f5a8d4
TL
313 std::size_t bytes_to_read = std::min<std::size_t>(
314 std::max<std::size_t>(512, b.capacity() - b.size()),
315 std::min<std::size_t>(65536, b.max_size() - b.size()));
7c673cae
FG
316 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
317 if (ec)
318 return 0;
319 }
320}
321
322#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
323
b32b8144 324template <typename SyncReadStream,
92f5a8d4 325 typename DynamicBuffer_v1, typename MatchCondition>
b32b8144 326inline std::size_t read_until(SyncReadStream& s,
92f5a8d4 327 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
b32b8144 328 MatchCondition match_condition,
1e59de90 329 typename constraint<
92f5a8d4 330 is_match_condition<MatchCondition>::value
1e59de90
TL
331 >::type,
332 typename constraint<
333 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
334 >::type,
335 typename constraint<
336 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
337 >::type)
b32b8144
FG
338{
339 boost::system::error_code ec;
340 std::size_t bytes_transferred = read_until(s,
92f5a8d4 341 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
b32b8144
FG
342 match_condition, ec);
343 boost::asio::detail::throw_error(ec, "read_until");
344 return bytes_transferred;
345}
346
347template <typename SyncReadStream,
92f5a8d4 348 typename DynamicBuffer_v1, typename MatchCondition>
7c673cae 349std::size_t read_until(SyncReadStream& s,
92f5a8d4 350 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
7c673cae 351 MatchCondition match_condition, boost::system::error_code& ec,
1e59de90 352 typename constraint<
92f5a8d4 353 is_match_condition<MatchCondition>::value
1e59de90
TL
354 >::type,
355 typename constraint<
356 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
357 >::type,
358 typename constraint<
359 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
360 >::type)
7c673cae 361{
92f5a8d4
TL
362 typename decay<DynamicBuffer_v1>::type b(
363 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));
b32b8144 364
7c673cae
FG
365 std::size_t search_position = 0;
366 for (;;)
367 {
368 // Determine the range of the data to be searched.
92f5a8d4 369 typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;
b32b8144
FG
370 typedef buffers_iterator<buffers_type> iterator;
371 buffers_type data_buffers = b.data();
372 iterator begin = iterator::begin(data_buffers);
7c673cae 373 iterator start_pos = begin + search_position;
b32b8144 374 iterator end = iterator::end(data_buffers);
7c673cae
FG
375
376 // Look for a match.
377 std::pair<iterator, bool> result = match_condition(start_pos, end);
378 if (result.second)
379 {
380 // Full match. We're done.
381 ec = boost::system::error_code();
382 return result.first - begin;
383 }
384 else if (result.first != end)
385 {
386 // Partial match. Next search needs to start from beginning of match.
387 search_position = result.first - begin;
388 }
389 else
390 {
391 // No match. Next search can start with the new data.
392 search_position = end - begin;
393 }
394
92f5a8d4
TL
395 // Check if buffer is full.
396 if (b.size() == b.max_size())
397 {
398 ec = error::not_found;
399 return 0;
400 }
401
402 // Need more data.
403 std::size_t bytes_to_read = std::min<std::size_t>(
404 std::max<std::size_t>(512, b.capacity() - b.size()),
405 std::min<std::size_t>(65536, b.max_size() - b.size()));
406 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
407 if (ec)
408 return 0;
409 }
410}
411
412#if !defined(BOOST_ASIO_NO_IOSTREAM)
413
414template <typename SyncReadStream, typename Allocator>
415inline std::size_t read_until(SyncReadStream& s,
416 boost::asio::basic_streambuf<Allocator>& b, char delim)
417{
418 return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
419}
420
421template <typename SyncReadStream, typename Allocator>
422inline std::size_t read_until(SyncReadStream& s,
423 boost::asio::basic_streambuf<Allocator>& b, char delim,
424 boost::system::error_code& ec)
425{
426 return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
427}
428
429template <typename SyncReadStream, typename Allocator>
430inline std::size_t read_until(SyncReadStream& s,
431 boost::asio::basic_streambuf<Allocator>& b,
432 BOOST_ASIO_STRING_VIEW_PARAM delim)
433{
434 return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
435}
436
437template <typename SyncReadStream, typename Allocator>
438inline std::size_t read_until(SyncReadStream& s,
439 boost::asio::basic_streambuf<Allocator>& b,
440 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec)
441{
442 return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
443}
444
445#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
446
447template <typename SyncReadStream, typename Allocator>
448inline std::size_t read_until(SyncReadStream& s,
449 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
450{
451 return read_until(s, basic_streambuf_ref<Allocator>(b), expr);
452}
453
454template <typename SyncReadStream, typename Allocator>
455inline std::size_t read_until(SyncReadStream& s,
456 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
457 boost::system::error_code& ec)
458{
459 return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec);
460}
461
462#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
463
464template <typename SyncReadStream, typename Allocator, typename MatchCondition>
465inline std::size_t read_until(SyncReadStream& s,
466 boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
1e59de90 467 typename constraint<is_match_condition<MatchCondition>::value>::type)
92f5a8d4
TL
468{
469 return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition);
470}
471
472template <typename SyncReadStream, typename Allocator, typename MatchCondition>
473inline std::size_t read_until(SyncReadStream& s,
474 boost::asio::basic_streambuf<Allocator>& b,
475 MatchCondition match_condition, boost::system::error_code& ec,
1e59de90 476 typename constraint<is_match_condition<MatchCondition>::value>::type)
92f5a8d4
TL
477{
478 return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec);
479}
480
481#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
482#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
483#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
484
485template <typename SyncReadStream, typename DynamicBuffer_v2>
486inline std::size_t read_until(SyncReadStream& s,
487 DynamicBuffer_v2 buffers, char delim,
1e59de90 488 typename constraint<
92f5a8d4 489 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 490 >::type)
92f5a8d4
TL
491{
492 boost::system::error_code ec;
493 std::size_t bytes_transferred = read_until(s,
494 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec);
495 boost::asio::detail::throw_error(ec, "read_until");
496 return bytes_transferred;
497}
498
499template <typename SyncReadStream, typename DynamicBuffer_v2>
500std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
501 char delim, boost::system::error_code& ec,
1e59de90 502 typename constraint<
92f5a8d4 503 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 504 >::type)
92f5a8d4
TL
505{
506 DynamicBuffer_v2& b = buffers;
507
508 std::size_t search_position = 0;
509 for (;;)
510 {
511 // Determine the range of the data to be searched.
512 typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
513 typedef buffers_iterator<buffers_type> iterator;
514 buffers_type data_buffers =
515 const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
516 iterator begin = iterator::begin(data_buffers);
517 iterator start_pos = begin + search_position;
518 iterator end = iterator::end(data_buffers);
519
520 // Look for a match.
521 iterator iter = std::find(start_pos, end, delim);
522 if (iter != end)
523 {
524 // Found a match. We're done.
525 ec = boost::system::error_code();
526 return iter - begin + 1;
527 }
528 else
529 {
530 // No match. Next search can start with the new data.
531 search_position = end - begin;
532 }
533
534 // Check if buffer is full.
535 if (b.size() == b.max_size())
536 {
537 ec = error::not_found;
538 return 0;
539 }
540
541 // Need more data.
542 std::size_t bytes_to_read = std::min<std::size_t>(
543 std::max<std::size_t>(512, b.capacity() - b.size()),
544 std::min<std::size_t>(65536, b.max_size() - b.size()));
545 std::size_t pos = b.size();
546 b.grow(bytes_to_read);
547 std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
548 b.shrink(bytes_to_read - bytes_transferred);
549 if (ec)
550 return 0;
551 }
552}
553
554template <typename SyncReadStream, typename DynamicBuffer_v2>
555inline std::size_t read_until(SyncReadStream& s,
556 DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim,
1e59de90 557 typename constraint<
92f5a8d4 558 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 559 >::type)
92f5a8d4
TL
560{
561 boost::system::error_code ec;
562 std::size_t bytes_transferred = read_until(s,
563 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec);
564 boost::asio::detail::throw_error(ec, "read_until");
565 return bytes_transferred;
566}
567
568template <typename SyncReadStream, typename DynamicBuffer_v2>
569std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
570 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec,
1e59de90 571 typename constraint<
92f5a8d4 572 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 573 >::type)
92f5a8d4
TL
574{
575 DynamicBuffer_v2& b = buffers;
576
577 std::size_t search_position = 0;
578 for (;;)
579 {
580 // Determine the range of the data to be searched.
581 typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
582 typedef buffers_iterator<buffers_type> iterator;
583 buffers_type data_buffers =
584 const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
585 iterator begin = iterator::begin(data_buffers);
586 iterator start_pos = begin + search_position;
587 iterator end = iterator::end(data_buffers);
588
589 // Look for a match.
590 std::pair<iterator, bool> result = detail::partial_search(
591 start_pos, end, delim.begin(), delim.end());
592 if (result.first != end)
593 {
594 if (result.second)
595 {
596 // Full match. We're done.
597 ec = boost::system::error_code();
598 return result.first - begin + delim.length();
599 }
600 else
601 {
602 // Partial match. Next search needs to start from beginning of match.
603 search_position = result.first - begin;
604 }
605 }
606 else
607 {
608 // No match. Next search can start with the new data.
609 search_position = end - begin;
610 }
611
612 // Check if buffer is full.
613 if (b.size() == b.max_size())
614 {
615 ec = error::not_found;
616 return 0;
617 }
618
619 // Need more data.
620 std::size_t bytes_to_read = std::min<std::size_t>(
621 std::max<std::size_t>(512, b.capacity() - b.size()),
622 std::min<std::size_t>(65536, b.max_size() - b.size()));
623 std::size_t pos = b.size();
624 b.grow(bytes_to_read);
625 std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
626 b.shrink(bytes_to_read - bytes_transferred);
627 if (ec)
628 return 0;
629 }
630}
631
632#if !defined(BOOST_ASIO_NO_EXTENSIONS)
633#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
634
635template <typename SyncReadStream, typename DynamicBuffer_v2>
636inline std::size_t read_until(SyncReadStream& s,
637 DynamicBuffer_v2 buffers, const boost::regex& expr,
1e59de90 638 typename constraint<
92f5a8d4 639 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 640 >::type)
92f5a8d4
TL
641{
642 boost::system::error_code ec;
643 std::size_t bytes_transferred = read_until(s,
644 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr, ec);
645 boost::asio::detail::throw_error(ec, "read_until");
646 return bytes_transferred;
647}
648
649template <typename SyncReadStream, typename DynamicBuffer_v2>
650std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
651 const boost::regex& expr, boost::system::error_code& ec,
1e59de90 652 typename constraint<
92f5a8d4 653 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 654 >::type)
92f5a8d4
TL
655{
656 DynamicBuffer_v2& b = buffers;
657
658 std::size_t search_position = 0;
659 for (;;)
660 {
661 // Determine the range of the data to be searched.
662 typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
663 typedef buffers_iterator<buffers_type> iterator;
664 buffers_type data_buffers =
665 const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
666 iterator begin = iterator::begin(data_buffers);
667 iterator start_pos = begin + search_position;
668 iterator end = iterator::end(data_buffers);
669
670 // Look for a match.
671 boost::match_results<iterator,
672 typename std::vector<boost::sub_match<iterator> >::allocator_type>
673 match_results;
674 if (regex_search(start_pos, end, match_results, expr,
675 boost::match_default | boost::match_partial))
676 {
677 if (match_results[0].matched)
678 {
679 // Full match. We're done.
680 ec = boost::system::error_code();
681 return match_results[0].second - begin;
682 }
683 else
684 {
685 // Partial match. Next search needs to start from beginning of match.
686 search_position = match_results[0].first - begin;
687 }
688 }
689 else
690 {
691 // No match. Next search can start with the new data.
692 search_position = end - begin;
693 }
694
695 // Check if buffer is full.
696 if (b.size() == b.max_size())
697 {
698 ec = error::not_found;
699 return 0;
700 }
701
702 // Need more data.
703 std::size_t bytes_to_read = std::min<std::size_t>(
704 std::max<std::size_t>(512, b.capacity() - b.size()),
705 std::min<std::size_t>(65536, b.max_size() - b.size()));
706 std::size_t pos = b.size();
707 b.grow(bytes_to_read);
708 std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
709 b.shrink(bytes_to_read - bytes_transferred);
710 if (ec)
711 return 0;
712 }
713}
714
715#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
716
717template <typename SyncReadStream,
718 typename DynamicBuffer_v2, typename MatchCondition>
719inline std::size_t read_until(SyncReadStream& s,
720 DynamicBuffer_v2 buffers, MatchCondition match_condition,
1e59de90 721 typename constraint<
92f5a8d4 722 is_match_condition<MatchCondition>::value
1e59de90
TL
723 >::type,
724 typename constraint<
725 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
726 >::type)
92f5a8d4
TL
727{
728 boost::system::error_code ec;
729 std::size_t bytes_transferred = read_until(s,
730 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
731 match_condition, ec);
732 boost::asio::detail::throw_error(ec, "read_until");
733 return bytes_transferred;
734}
735
736template <typename SyncReadStream,
737 typename DynamicBuffer_v2, typename MatchCondition>
738std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,
739 MatchCondition match_condition, boost::system::error_code& ec,
1e59de90 740 typename constraint<
92f5a8d4 741 is_match_condition<MatchCondition>::value
1e59de90
TL
742 >::type,
743 typename constraint<
744 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
745 >::type)
92f5a8d4
TL
746{
747 DynamicBuffer_v2& b = buffers;
748
749 std::size_t search_position = 0;
750 for (;;)
751 {
752 // Determine the range of the data to be searched.
753 typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;
754 typedef buffers_iterator<buffers_type> iterator;
755 buffers_type data_buffers =
756 const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());
757 iterator begin = iterator::begin(data_buffers);
758 iterator start_pos = begin + search_position;
759 iterator end = iterator::end(data_buffers);
760
761 // Look for a match.
762 std::pair<iterator, bool> result = match_condition(start_pos, end);
763 if (result.second)
764 {
765 // Full match. We're done.
766 ec = boost::system::error_code();
767 return result.first - begin;
768 }
769 else if (result.first != end)
770 {
771 // Partial match. Next search needs to start from beginning of match.
772 search_position = result.first - begin;
773 }
774 else
775 {
776 // No match. Next search can start with the new data.
777 search_position = end - begin;
778 }
779
780 // Check if buffer is full.
781 if (b.size() == b.max_size())
782 {
783 ec = error::not_found;
784 return 0;
785 }
786
787 // Need more data.
788 std::size_t bytes_to_read = std::min<std::size_t>(
789 std::max<std::size_t>(512, b.capacity() - b.size()),
790 std::min<std::size_t>(65536, b.max_size() - b.size()));
791 std::size_t pos = b.size();
792 b.grow(bytes_to_read);
793 std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);
794 b.shrink(bytes_to_read - bytes_transferred);
795 if (ec)
796 return 0;
797 }
798}
799
800#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
801
802#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
803
804namespace detail
805{
806 template <typename AsyncReadStream,
807 typename DynamicBuffer_v1, typename ReadHandler>
808 class read_until_delim_op_v1
1e59de90 809 : public base_from_cancellation_state<ReadHandler>
92f5a8d4
TL
810 {
811 public:
812 template <typename BufferSequence>
813 read_until_delim_op_v1(AsyncReadStream& stream,
814 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
815 char delim, ReadHandler& handler)
1e59de90
TL
816 : base_from_cancellation_state<ReadHandler>(
817 handler, enable_partial_cancellation()),
818 stream_(stream),
92f5a8d4
TL
819 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
820 delim_(delim),
821 start_(0),
822 search_position_(0),
823 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
824 {
825 }
826
827#if defined(BOOST_ASIO_HAS_MOVE)
828 read_until_delim_op_v1(const read_until_delim_op_v1& other)
1e59de90
TL
829 : base_from_cancellation_state<ReadHandler>(other),
830 stream_(other.stream_),
92f5a8d4
TL
831 buffers_(other.buffers_),
832 delim_(other.delim_),
833 start_(other.start_),
834 search_position_(other.search_position_),
835 handler_(other.handler_)
836 {
837 }
838
839 read_until_delim_op_v1(read_until_delim_op_v1&& other)
1e59de90
TL
840 : base_from_cancellation_state<ReadHandler>(
841 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
842 ReadHandler>)(other)),
843 stream_(other.stream_),
92f5a8d4
TL
844 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
845 delim_(other.delim_),
846 start_(other.start_),
847 search_position_(other.search_position_),
848 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
849 {
850 }
851#endif // defined(BOOST_ASIO_HAS_MOVE)
852
1e59de90 853 void operator()(boost::system::error_code ec,
92f5a8d4
TL
854 std::size_t bytes_transferred, int start = 0)
855 {
856 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
857 std::size_t bytes_to_read;
858 switch (start_ = start)
859 {
860 case 1:
861 for (;;)
862 {
863 {
864 // Determine the range of the data to be searched.
865 typedef typename DynamicBuffer_v1::const_buffers_type
866 buffers_type;
867 typedef buffers_iterator<buffers_type> iterator;
868 buffers_type data_buffers = buffers_.data();
869 iterator begin = iterator::begin(data_buffers);
870 iterator start_pos = begin + search_position_;
871 iterator end = iterator::end(data_buffers);
872
873 // Look for a match.
874 iterator iter = std::find(start_pos, end, delim_);
875 if (iter != end)
876 {
877 // Found a match. We're done.
878 search_position_ = iter - begin + 1;
879 bytes_to_read = 0;
880 }
881
882 // No match yet. Check if buffer is full.
883 else if (buffers_.size() == buffers_.max_size())
884 {
885 search_position_ = not_found;
886 bytes_to_read = 0;
887 }
888
889 // Need to read some more data.
890 else
891 {
892 // Next search can start with the new data.
893 search_position_ = end - begin;
894 bytes_to_read = std::min<std::size_t>(
895 std::max<std::size_t>(512,
896 buffers_.capacity() - buffers_.size()),
897 std::min<std::size_t>(65536,
898 buffers_.max_size() - buffers_.size()));
899 }
900 }
901
902 // Check if we're done.
903 if (!start && bytes_to_read == 0)
904 break;
905
20effc67
TL
906 // Start a new asynchronous read operation to obtain more data.
907 {
908 BOOST_ASIO_HANDLER_LOCATION((
909 __FILE__, __LINE__, "async_read_until"));
910 stream_.async_read_some(buffers_.prepare(bytes_to_read),
911 BOOST_ASIO_MOVE_CAST(read_until_delim_op_v1)(*this));
912 }
92f5a8d4
TL
913 return; default:
914 buffers_.commit(bytes_transferred);
915 if (ec || bytes_transferred == 0)
916 break;
1e59de90
TL
917 if (this->cancelled() != cancellation_type::none)
918 {
919 ec = error::operation_aborted;
920 break;
921 }
92f5a8d4
TL
922 }
923
924 const boost::system::error_code result_ec =
925 (search_position_ == not_found)
926 ? error::not_found : ec;
927
928 const std::size_t result_n =
929 (ec || search_position_ == not_found)
930 ? 0 : search_position_;
931
1e59de90 932 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
92f5a8d4
TL
933 }
934 }
935
936 //private:
937 AsyncReadStream& stream_;
938 DynamicBuffer_v1 buffers_;
939 char delim_;
940 int start_;
941 std::size_t search_position_;
942 ReadHandler handler_;
943 };
944
945 template <typename AsyncReadStream,
946 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
947 inline asio_handler_allocate_is_deprecated
948 asio_handler_allocate(std::size_t size,
92f5a8d4
TL
949 read_until_delim_op_v1<AsyncReadStream,
950 DynamicBuffer_v1, ReadHandler>* this_handler)
951 {
20effc67
TL
952#if defined(BOOST_ASIO_NO_DEPRECATED)
953 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
954 return asio_handler_allocate_is_no_longer_used();
955#else // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
956 return boost_asio_handler_alloc_helpers::allocate(
957 size, this_handler->handler_);
20effc67 958#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
959 }
960
961 template <typename AsyncReadStream,
962 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
963 inline asio_handler_deallocate_is_deprecated
964 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4
TL
965 read_until_delim_op_v1<AsyncReadStream,
966 DynamicBuffer_v1, ReadHandler>* this_handler)
967 {
968 boost_asio_handler_alloc_helpers::deallocate(
969 pointer, size, this_handler->handler_);
20effc67
TL
970#if defined(BOOST_ASIO_NO_DEPRECATED)
971 return asio_handler_deallocate_is_no_longer_used();
972#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
973 }
974
975 template <typename AsyncReadStream,
976 typename DynamicBuffer_v1, typename ReadHandler>
977 inline bool asio_handler_is_continuation(
978 read_until_delim_op_v1<AsyncReadStream,
979 DynamicBuffer_v1, ReadHandler>* this_handler)
980 {
981 return this_handler->start_ == 0 ? true
982 : boost_asio_handler_cont_helpers::is_continuation(
983 this_handler->handler_);
984 }
985
986 template <typename Function, typename AsyncReadStream,
987 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
988 inline asio_handler_invoke_is_deprecated
989 asio_handler_invoke(Function& function,
92f5a8d4
TL
990 read_until_delim_op_v1<AsyncReadStream,
991 DynamicBuffer_v1, ReadHandler>* this_handler)
992 {
993 boost_asio_handler_invoke_helpers::invoke(
994 function, this_handler->handler_);
20effc67
TL
995#if defined(BOOST_ASIO_NO_DEPRECATED)
996 return asio_handler_invoke_is_no_longer_used();
997#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
998 }
999
1000 template <typename Function, typename AsyncReadStream,
1001 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
1002 inline asio_handler_invoke_is_deprecated
1003 asio_handler_invoke(const Function& function,
92f5a8d4
TL
1004 read_until_delim_op_v1<AsyncReadStream,
1005 DynamicBuffer_v1, ReadHandler>* this_handler)
1006 {
1007 boost_asio_handler_invoke_helpers::invoke(
1008 function, this_handler->handler_);
20effc67
TL
1009#if defined(BOOST_ASIO_NO_DEPRECATED)
1010 return asio_handler_invoke_is_no_longer_used();
1011#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1012 }
1013
1014 template <typename AsyncReadStream>
1015 class initiate_async_read_until_delim_v1
1016 {
1017 public:
1018 typedef typename AsyncReadStream::executor_type executor_type;
1019
1020 explicit initiate_async_read_until_delim_v1(AsyncReadStream& stream)
1021 : stream_(stream)
1022 {
1023 }
1024
1025 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
1026 {
1027 return stream_.get_executor();
1028 }
1029
1030 template <typename ReadHandler, typename DynamicBuffer_v1>
1031 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1032 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
1033 char delim) const
1034 {
1035 // If you get an error on the following line it means that your handler
1036 // does not meet the documented type requirements for a ReadHandler.
1037 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1038
1039 non_const_lvalue<ReadHandler> handler2(handler);
1040 read_until_delim_op_v1<AsyncReadStream,
1041 typename decay<DynamicBuffer_v1>::type,
1042 typename decay<ReadHandler>::type>(
1043 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
1044 delim, handler2.value)(boost::system::error_code(), 0, 1);
1045 }
1046
1047 private:
1048 AsyncReadStream& stream_;
1049 };
1050} // namespace detail
1051
1052#if !defined(GENERATING_DOCUMENTATION)
1053
1e59de90
TL
1054template <template <typename, typename> class Associator,
1055 typename AsyncReadStream, typename DynamicBuffer_v1,
1056 typename ReadHandler, typename DefaultCandidate>
1057struct associator<Associator,
92f5a8d4
TL
1058 detail::read_until_delim_op_v1<AsyncReadStream,
1059 DynamicBuffer_v1, ReadHandler>,
1e59de90
TL
1060 DefaultCandidate>
1061 : Associator<ReadHandler, DefaultCandidate>
92f5a8d4 1062{
1e59de90 1063 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
1064 const detail::read_until_delim_op_v1<AsyncReadStream,
1065 DynamicBuffer_v1, ReadHandler>& h,
1e59de90 1066 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
92f5a8d4 1067 {
1e59de90 1068 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
92f5a8d4
TL
1069 }
1070};
1071
1072#endif // !defined(GENERATING_DOCUMENTATION)
1073
1074template <typename AsyncReadStream, typename DynamicBuffer_v1,
1075 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
1076 std::size_t)) ReadToken>
1077BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
1078 void (boost::system::error_code, std::size_t))
1079async_read_until(AsyncReadStream& s,
1080 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
1e59de90
TL
1081 char delim, BOOST_ASIO_MOVE_ARG(ReadToken) token,
1082 typename constraint<
92f5a8d4 1083 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
1084 >::type,
1085 typename constraint<
1086 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
1087 >::type)
92f5a8d4 1088{
1e59de90 1089 return async_initiate<ReadToken,
92f5a8d4
TL
1090 void (boost::system::error_code, std::size_t)>(
1091 detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s),
1e59de90 1092 token, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim);
92f5a8d4
TL
1093}
1094
1095namespace detail
1096{
1097 template <typename AsyncReadStream,
1098 typename DynamicBuffer_v1, typename ReadHandler>
1099 class read_until_delim_string_op_v1
1e59de90 1100 : public base_from_cancellation_state<ReadHandler>
92f5a8d4
TL
1101 {
1102 public:
1103 template <typename BufferSequence>
1104 read_until_delim_string_op_v1(AsyncReadStream& stream,
1105 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
1106 const std::string& delim, ReadHandler& handler)
1e59de90
TL
1107 : base_from_cancellation_state<ReadHandler>(
1108 handler, enable_partial_cancellation()),
1109 stream_(stream),
92f5a8d4
TL
1110 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
1111 delim_(delim),
1112 start_(0),
1113 search_position_(0),
1114 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
1115 {
1116 }
1117
1118#if defined(BOOST_ASIO_HAS_MOVE)
1119 read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other)
1e59de90
TL
1120 : base_from_cancellation_state<ReadHandler>(other),
1121 stream_(other.stream_),
92f5a8d4
TL
1122 buffers_(other.buffers_),
1123 delim_(other.delim_),
1124 start_(other.start_),
1125 search_position_(other.search_position_),
1126 handler_(other.handler_)
1127 {
1128 }
1129
1130 read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other)
1e59de90
TL
1131 : base_from_cancellation_state<ReadHandler>(
1132 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
1133 ReadHandler>)(other)),
1134 stream_(other.stream_),
92f5a8d4
TL
1135 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
1136 delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
1137 start_(other.start_),
1138 search_position_(other.search_position_),
1139 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
1140 {
1141 }
1142#endif // defined(BOOST_ASIO_HAS_MOVE)
1143
1e59de90 1144 void operator()(boost::system::error_code ec,
92f5a8d4
TL
1145 std::size_t bytes_transferred, int start = 0)
1146 {
1147 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1148 std::size_t bytes_to_read;
1149 switch (start_ = start)
1150 {
1151 case 1:
1152 for (;;)
1153 {
1154 {
1155 // Determine the range of the data to be searched.
1156 typedef typename DynamicBuffer_v1::const_buffers_type
1157 buffers_type;
1158 typedef buffers_iterator<buffers_type> iterator;
1159 buffers_type data_buffers = buffers_.data();
1160 iterator begin = iterator::begin(data_buffers);
1161 iterator start_pos = begin + search_position_;
1162 iterator end = iterator::end(data_buffers);
1163
1164 // Look for a match.
1165 std::pair<iterator, bool> result = detail::partial_search(
1166 start_pos, end, delim_.begin(), delim_.end());
1167 if (result.first != end && result.second)
1168 {
1169 // Full match. We're done.
1170 search_position_ = result.first - begin + delim_.length();
1171 bytes_to_read = 0;
1172 }
1173
1174 // No match yet. Check if buffer is full.
1175 else if (buffers_.size() == buffers_.max_size())
1176 {
1177 search_position_ = not_found;
1178 bytes_to_read = 0;
1179 }
1180
1181 // Need to read some more data.
1182 else
1183 {
1184 if (result.first != end)
1185 {
1186 // Partial match. Next search needs to start from beginning of
1187 // match.
1188 search_position_ = result.first - begin;
1189 }
1190 else
1191 {
1192 // Next search can start with the new data.
1193 search_position_ = end - begin;
1194 }
1195
1196 bytes_to_read = std::min<std::size_t>(
1197 std::max<std::size_t>(512,
1198 buffers_.capacity() - buffers_.size()),
1199 std::min<std::size_t>(65536,
1200 buffers_.max_size() - buffers_.size()));
1201 }
1202 }
1203
1204 // Check if we're done.
1205 if (!start && bytes_to_read == 0)
1206 break;
1207
20effc67
TL
1208 // Start a new asynchronous read operation to obtain more data.
1209 {
1210 BOOST_ASIO_HANDLER_LOCATION((
1211 __FILE__, __LINE__, "async_read_until"));
1212 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1213 BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v1)(*this));
1214 }
92f5a8d4
TL
1215 return; default:
1216 buffers_.commit(bytes_transferred);
1217 if (ec || bytes_transferred == 0)
1218 break;
1e59de90
TL
1219 if (this->cancelled() != cancellation_type::none)
1220 {
1221 ec = error::operation_aborted;
1222 break;
1223 }
92f5a8d4
TL
1224 }
1225
1226 const boost::system::error_code result_ec =
1227 (search_position_ == not_found)
1228 ? error::not_found : ec;
1229
1230 const std::size_t result_n =
1231 (ec || search_position_ == not_found)
1232 ? 0 : search_position_;
1233
1e59de90 1234 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
92f5a8d4
TL
1235 }
1236 }
1237
1238 //private:
1239 AsyncReadStream& stream_;
1240 DynamicBuffer_v1 buffers_;
1241 std::string delim_;
1242 int start_;
1243 std::size_t search_position_;
1244 ReadHandler handler_;
1245 };
1246
1247 template <typename AsyncReadStream,
1248 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
1249 inline asio_handler_allocate_is_deprecated
1250 asio_handler_allocate(std::size_t size,
92f5a8d4
TL
1251 read_until_delim_string_op_v1<AsyncReadStream,
1252 DynamicBuffer_v1, ReadHandler>* this_handler)
1253 {
20effc67
TL
1254#if defined(BOOST_ASIO_NO_DEPRECATED)
1255 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
1256 return asio_handler_allocate_is_no_longer_used();
1257#else // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1258 return boost_asio_handler_alloc_helpers::allocate(
1259 size, this_handler->handler_);
20effc67 1260#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1261 }
1262
1263 template <typename AsyncReadStream,
1264 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
1265 inline asio_handler_deallocate_is_deprecated
1266 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4
TL
1267 read_until_delim_string_op_v1<AsyncReadStream,
1268 DynamicBuffer_v1, ReadHandler>* this_handler)
1269 {
1270 boost_asio_handler_alloc_helpers::deallocate(
1271 pointer, size, this_handler->handler_);
20effc67
TL
1272#if defined(BOOST_ASIO_NO_DEPRECATED)
1273 return asio_handler_deallocate_is_no_longer_used();
1274#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1275 }
1276
1277 template <typename AsyncReadStream,
1278 typename DynamicBuffer_v1, typename ReadHandler>
1279 inline bool asio_handler_is_continuation(
1280 read_until_delim_string_op_v1<AsyncReadStream,
1281 DynamicBuffer_v1, ReadHandler>* this_handler)
1282 {
1283 return this_handler->start_ == 0 ? true
1284 : boost_asio_handler_cont_helpers::is_continuation(
1285 this_handler->handler_);
1286 }
1287
1288 template <typename Function, typename AsyncReadStream,
1289 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
1290 inline asio_handler_invoke_is_deprecated
1291 asio_handler_invoke(Function& function,
92f5a8d4
TL
1292 read_until_delim_string_op_v1<AsyncReadStream,
1293 DynamicBuffer_v1, ReadHandler>* this_handler)
1294 {
1295 boost_asio_handler_invoke_helpers::invoke(
1296 function, this_handler->handler_);
20effc67
TL
1297#if defined(BOOST_ASIO_NO_DEPRECATED)
1298 return asio_handler_invoke_is_no_longer_used();
1299#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1300 }
1301
1302 template <typename Function, typename AsyncReadStream,
1303 typename DynamicBuffer_v1, typename ReadHandler>
20effc67
TL
1304 inline asio_handler_invoke_is_deprecated
1305 asio_handler_invoke(const Function& function,
92f5a8d4
TL
1306 read_until_delim_string_op_v1<AsyncReadStream,
1307 DynamicBuffer_v1, ReadHandler>* this_handler)
1308 {
1309 boost_asio_handler_invoke_helpers::invoke(
1310 function, this_handler->handler_);
20effc67
TL
1311#if defined(BOOST_ASIO_NO_DEPRECATED)
1312 return asio_handler_invoke_is_no_longer_used();
1313#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1314 }
1315
1316 template <typename AsyncReadStream>
1317 class initiate_async_read_until_delim_string_v1
1318 {
1319 public:
1320 typedef typename AsyncReadStream::executor_type executor_type;
1321
1322 explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream)
1323 : stream_(stream)
1324 {
1325 }
1326
1327 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
1328 {
1329 return stream_.get_executor();
1330 }
1331
1332 template <typename ReadHandler, typename DynamicBuffer_v1>
1333 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1334 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
1335 const std::string& delim) const
1336 {
1337 // If you get an error on the following line it means that your handler
1338 // does not meet the documented type requirements for a ReadHandler.
1339 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1340
1341 non_const_lvalue<ReadHandler> handler2(handler);
1342 read_until_delim_string_op_v1<AsyncReadStream,
1343 typename decay<DynamicBuffer_v1>::type,
1344 typename decay<ReadHandler>::type>(
1345 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
1346 delim, handler2.value)(boost::system::error_code(), 0, 1);
1347 }
1348
1349 private:
1350 AsyncReadStream& stream_;
1351 };
1352} // namespace detail
1353
1354#if !defined(GENERATING_DOCUMENTATION)
1355
1e59de90
TL
1356template <template <typename, typename> class Associator,
1357 typename AsyncReadStream, typename DynamicBuffer_v1,
1358 typename ReadHandler, typename DefaultCandidate>
1359struct associator<Associator,
92f5a8d4
TL
1360 detail::read_until_delim_string_op_v1<AsyncReadStream,
1361 DynamicBuffer_v1, ReadHandler>,
1e59de90
TL
1362 DefaultCandidate>
1363 : Associator<ReadHandler, DefaultCandidate>
92f5a8d4 1364{
1e59de90 1365 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
1366 const detail::read_until_delim_string_op_v1<AsyncReadStream,
1367 DynamicBuffer_v1, ReadHandler>& h,
1e59de90 1368 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
92f5a8d4 1369 {
1e59de90 1370 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
92f5a8d4
TL
1371 }
1372};
1373
1374#endif // !defined(GENERATING_DOCUMENTATION)
1375
1376template <typename AsyncReadStream, typename DynamicBuffer_v1,
1377 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
1378 std::size_t)) ReadToken>
1379BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
1380 void (boost::system::error_code, std::size_t))
1381async_read_until(AsyncReadStream& s,
1382 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
1383 BOOST_ASIO_STRING_VIEW_PARAM delim,
1e59de90
TL
1384 BOOST_ASIO_MOVE_ARG(ReadToken) token,
1385 typename constraint<
92f5a8d4 1386 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
1387 >::type,
1388 typename constraint<
1389 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
1390 >::type)
92f5a8d4 1391{
1e59de90 1392 return async_initiate<ReadToken,
92f5a8d4
TL
1393 void (boost::system::error_code, std::size_t)>(
1394 detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s),
1e59de90 1395 token, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
92f5a8d4
TL
1396 static_cast<std::string>(delim));
1397}
1398
1399#if !defined(BOOST_ASIO_NO_EXTENSIONS)
1400#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
1401
1402namespace detail
1403{
1404 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1405 typename RegEx, typename ReadHandler>
1406 class read_until_expr_op_v1
1e59de90 1407 : public base_from_cancellation_state<ReadHandler>
92f5a8d4
TL
1408 {
1409 public:
1410 template <typename BufferSequence>
1411 read_until_expr_op_v1(AsyncReadStream& stream,
1412 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
1413 const boost::regex& expr, ReadHandler& handler)
1e59de90
TL
1414 : base_from_cancellation_state<ReadHandler>(
1415 handler, enable_partial_cancellation()),
1416 stream_(stream),
92f5a8d4
TL
1417 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
1418 expr_(expr),
1419 start_(0),
1420 search_position_(0),
1421 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
1422 {
1423 }
1424
1425#if defined(BOOST_ASIO_HAS_MOVE)
1426 read_until_expr_op_v1(const read_until_expr_op_v1& other)
1e59de90
TL
1427 : base_from_cancellation_state<ReadHandler>(other),
1428 stream_(other.stream_),
92f5a8d4
TL
1429 buffers_(other.buffers_),
1430 expr_(other.expr_),
1431 start_(other.start_),
1432 search_position_(other.search_position_),
1433 handler_(other.handler_)
1434 {
1435 }
1436
1437 read_until_expr_op_v1(read_until_expr_op_v1&& other)
1e59de90
TL
1438 : base_from_cancellation_state<ReadHandler>(
1439 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
1440 ReadHandler>)(other)),
1441 stream_(other.stream_),
92f5a8d4
TL
1442 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
1443 expr_(other.expr_),
1444 start_(other.start_),
1445 search_position_(other.search_position_),
1446 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
1447 {
1448 }
1449#endif // defined(BOOST_ASIO_HAS_MOVE)
1450
1e59de90 1451 void operator()(boost::system::error_code ec,
92f5a8d4
TL
1452 std::size_t bytes_transferred, int start = 0)
1453 {
1454 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1455 std::size_t bytes_to_read;
1456 switch (start_ = start)
1457 {
1458 case 1:
1459 for (;;)
1460 {
1461 {
1462 // Determine the range of the data to be searched.
1463 typedef typename DynamicBuffer_v1::const_buffers_type
1464 buffers_type;
1465 typedef buffers_iterator<buffers_type> iterator;
1466 buffers_type data_buffers = buffers_.data();
1467 iterator begin = iterator::begin(data_buffers);
1468 iterator start_pos = begin + search_position_;
1469 iterator end = iterator::end(data_buffers);
1470
1471 // Look for a match.
1472 boost::match_results<iterator,
1473 typename std::vector<boost::sub_match<iterator> >::allocator_type>
1474 match_results;
1475 bool match = regex_search(start_pos, end, match_results, expr_,
1476 boost::match_default | boost::match_partial);
1477 if (match && match_results[0].matched)
1478 {
1479 // Full match. We're done.
1480 search_position_ = match_results[0].second - begin;
1481 bytes_to_read = 0;
1482 }
1483
1484 // No match yet. Check if buffer is full.
1485 else if (buffers_.size() == buffers_.max_size())
1486 {
1487 search_position_ = not_found;
1488 bytes_to_read = 0;
1489 }
1490
1491 // Need to read some more data.
1492 else
1493 {
1494 if (match)
1495 {
1496 // Partial match. Next search needs to start from beginning of
1497 // match.
1498 search_position_ = match_results[0].first - begin;
1499 }
1500 else
1501 {
1502 // Next search can start with the new data.
1503 search_position_ = end - begin;
1504 }
1505
1506 bytes_to_read = std::min<std::size_t>(
1507 std::max<std::size_t>(512,
1508 buffers_.capacity() - buffers_.size()),
1509 std::min<std::size_t>(65536,
1510 buffers_.max_size() - buffers_.size()));
1511 }
1512 }
1513
1514 // Check if we're done.
1515 if (!start && bytes_to_read == 0)
1516 break;
1517
20effc67
TL
1518 // Start a new asynchronous read operation to obtain more data.
1519 {
1520 BOOST_ASIO_HANDLER_LOCATION((
1521 __FILE__, __LINE__, "async_read_until"));
1522 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1523 BOOST_ASIO_MOVE_CAST(read_until_expr_op_v1)(*this));
1524 }
92f5a8d4
TL
1525 return; default:
1526 buffers_.commit(bytes_transferred);
1527 if (ec || bytes_transferred == 0)
1528 break;
1e59de90
TL
1529 if (this->cancelled() != cancellation_type::none)
1530 {
1531 ec = error::operation_aborted;
1532 break;
1533 }
92f5a8d4
TL
1534 }
1535
1536 const boost::system::error_code result_ec =
1537 (search_position_ == not_found)
1538 ? error::not_found : ec;
1539
1540 const std::size_t result_n =
1541 (ec || search_position_ == not_found)
1542 ? 0 : search_position_;
1543
1e59de90 1544 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
92f5a8d4
TL
1545 }
1546 }
1547
1548 //private:
1549 AsyncReadStream& stream_;
1550 DynamicBuffer_v1 buffers_;
1551 RegEx expr_;
1552 int start_;
1553 std::size_t search_position_;
1554 ReadHandler handler_;
1555 };
1556
1557 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1558 typename RegEx, typename ReadHandler>
20effc67
TL
1559 inline asio_handler_allocate_is_deprecated
1560 asio_handler_allocate(std::size_t size,
92f5a8d4
TL
1561 read_until_expr_op_v1<AsyncReadStream,
1562 DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
1563 {
20effc67
TL
1564#if defined(BOOST_ASIO_NO_DEPRECATED)
1565 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
1566 return asio_handler_allocate_is_no_longer_used();
1567#else // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1568 return boost_asio_handler_alloc_helpers::allocate(
1569 size, this_handler->handler_);
20effc67 1570#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1571 }
1572
1573 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1574 typename RegEx, typename ReadHandler>
20effc67
TL
1575 inline asio_handler_deallocate_is_deprecated
1576 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4
TL
1577 read_until_expr_op_v1<AsyncReadStream,
1578 DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
1579 {
1580 boost_asio_handler_alloc_helpers::deallocate(
1581 pointer, size, this_handler->handler_);
20effc67
TL
1582#if defined(BOOST_ASIO_NO_DEPRECATED)
1583 return asio_handler_deallocate_is_no_longer_used();
1584#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1585 }
1586
1587 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1588 typename RegEx, typename ReadHandler>
1589 inline bool asio_handler_is_continuation(
1590 read_until_expr_op_v1<AsyncReadStream,
1591 DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
1592 {
1593 return this_handler->start_ == 0 ? true
1594 : boost_asio_handler_cont_helpers::is_continuation(
1595 this_handler->handler_);
1596 }
1597
1598 template <typename Function, typename AsyncReadStream,
1599 typename DynamicBuffer_v1, typename RegEx, typename ReadHandler>
20effc67
TL
1600 inline asio_handler_invoke_is_deprecated
1601 asio_handler_invoke(Function& function,
92f5a8d4
TL
1602 read_until_expr_op_v1<AsyncReadStream,
1603 DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
1604 {
1605 boost_asio_handler_invoke_helpers::invoke(
1606 function, this_handler->handler_);
20effc67
TL
1607#if defined(BOOST_ASIO_NO_DEPRECATED)
1608 return asio_handler_invoke_is_no_longer_used();
1609#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1610 }
1611
1612 template <typename Function, typename AsyncReadStream,
1613 typename DynamicBuffer_v1, typename RegEx, typename ReadHandler>
20effc67
TL
1614 inline asio_handler_invoke_is_deprecated
1615 asio_handler_invoke(const Function& function,
92f5a8d4
TL
1616 read_until_expr_op_v1<AsyncReadStream,
1617 DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)
1618 {
1619 boost_asio_handler_invoke_helpers::invoke(
1620 function, this_handler->handler_);
20effc67
TL
1621#if defined(BOOST_ASIO_NO_DEPRECATED)
1622 return asio_handler_invoke_is_no_longer_used();
1623#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1624 }
1625
1626 template <typename AsyncReadStream>
1627 class initiate_async_read_until_expr_v1
1628 {
1629 public:
1630 typedef typename AsyncReadStream::executor_type executor_type;
1631
1632 explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream)
1633 : stream_(stream)
1634 {
1635 }
1636
1637 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
1638 {
1639 return stream_.get_executor();
1640 }
1641
1642 template <typename ReadHandler, typename DynamicBuffer_v1, typename RegEx>
1643 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1644 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, const RegEx& expr) const
1645 {
1646 // If you get an error on the following line it means that your handler
1647 // does not meet the documented type requirements for a ReadHandler.
1648 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1649
1650 non_const_lvalue<ReadHandler> handler2(handler);
1651 read_until_expr_op_v1<AsyncReadStream,
1652 typename decay<DynamicBuffer_v1>::type,
1653 RegEx, typename decay<ReadHandler>::type>(
1654 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
1655 expr, handler2.value)(boost::system::error_code(), 0, 1);
1656 }
1657
1658 private:
1659 AsyncReadStream& stream_;
1660 };
1661} // namespace detail
1662
1663#if !defined(GENERATING_DOCUMENTATION)
1664
1e59de90
TL
1665template <template <typename, typename> class Associator,
1666 typename AsyncReadStream, typename DynamicBuffer_v1,
1667 typename RegEx, typename ReadHandler, typename DefaultCandidate>
1668struct associator<Associator,
92f5a8d4
TL
1669 detail::read_until_expr_op_v1<AsyncReadStream,
1670 DynamicBuffer_v1, RegEx, ReadHandler>,
1e59de90
TL
1671 DefaultCandidate>
1672 : Associator<ReadHandler, DefaultCandidate>
92f5a8d4 1673{
1e59de90 1674 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
1675 const detail::read_until_expr_op_v1<AsyncReadStream,
1676 DynamicBuffer_v1, RegEx, ReadHandler>& h,
1e59de90 1677 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
92f5a8d4 1678 {
1e59de90 1679 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
92f5a8d4
TL
1680 }
1681};
1682
1683#endif // !defined(GENERATING_DOCUMENTATION)
1684
1685template <typename AsyncReadStream, typename DynamicBuffer_v1,
1686 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
1687 std::size_t)) ReadToken>
1688BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
1689 void (boost::system::error_code, std::size_t))
1690async_read_until(AsyncReadStream& s,
1691 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
1692 const boost::regex& expr,
1e59de90
TL
1693 BOOST_ASIO_MOVE_ARG(ReadToken) token,
1694 typename constraint<
92f5a8d4 1695 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
1e59de90
TL
1696 >::type,
1697 typename constraint<
1698 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
1699 >::type)
92f5a8d4 1700{
1e59de90 1701 return async_initiate<ReadToken,
92f5a8d4
TL
1702 void (boost::system::error_code, std::size_t)>(
1703 detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s),
1e59de90 1704 token, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr);
92f5a8d4
TL
1705}
1706
1707#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1708
1709namespace detail
1710{
1711 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1712 typename MatchCondition, typename ReadHandler>
1713 class read_until_match_op_v1
1e59de90 1714 : public base_from_cancellation_state<ReadHandler>
92f5a8d4
TL
1715 {
1716 public:
1717 template <typename BufferSequence>
1718 read_until_match_op_v1(AsyncReadStream& stream,
1719 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
1720 MatchCondition match_condition, ReadHandler& handler)
1e59de90
TL
1721 : base_from_cancellation_state<ReadHandler>(
1722 handler, enable_partial_cancellation()),
1723 stream_(stream),
92f5a8d4
TL
1724 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
1725 match_condition_(match_condition),
1726 start_(0),
1727 search_position_(0),
1728 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
1729 {
1730 }
1731
1732#if defined(BOOST_ASIO_HAS_MOVE)
1733 read_until_match_op_v1(const read_until_match_op_v1& other)
1e59de90
TL
1734 : base_from_cancellation_state<ReadHandler>(other),
1735 stream_(other.stream_),
92f5a8d4
TL
1736 buffers_(other.buffers_),
1737 match_condition_(other.match_condition_),
1738 start_(other.start_),
1739 search_position_(other.search_position_),
1740 handler_(other.handler_)
1741 {
1742 }
1743
1744 read_until_match_op_v1(read_until_match_op_v1&& other)
1e59de90
TL
1745 : base_from_cancellation_state<ReadHandler>(
1746 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
1747 ReadHandler>)(other)),
1748 stream_(other.stream_),
92f5a8d4
TL
1749 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),
1750 match_condition_(other.match_condition_),
1751 start_(other.start_),
1752 search_position_(other.search_position_),
1753 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
1754 {
1755 }
1756#endif // defined(BOOST_ASIO_HAS_MOVE)
1757
1e59de90 1758 void operator()(boost::system::error_code ec,
92f5a8d4
TL
1759 std::size_t bytes_transferred, int start = 0)
1760 {
1761 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1762 std::size_t bytes_to_read;
1763 switch (start_ = start)
1764 {
1765 case 1:
1766 for (;;)
1767 {
1768 {
1769 // Determine the range of the data to be searched.
1770 typedef typename DynamicBuffer_v1::const_buffers_type
1771 buffers_type;
1772 typedef buffers_iterator<buffers_type> iterator;
1773 buffers_type data_buffers = buffers_.data();
1774 iterator begin = iterator::begin(data_buffers);
1775 iterator start_pos = begin + search_position_;
1776 iterator end = iterator::end(data_buffers);
1777
1778 // Look for a match.
1779 std::pair<iterator, bool> result = match_condition_(start_pos, end);
1780 if (result.second)
1781 {
1782 // Full match. We're done.
1783 search_position_ = result.first - begin;
1784 bytes_to_read = 0;
1785 }
1786
1787 // No match yet. Check if buffer is full.
1788 else if (buffers_.size() == buffers_.max_size())
1789 {
1790 search_position_ = not_found;
1791 bytes_to_read = 0;
1792 }
1793
1794 // Need to read some more data.
1795 else
1796 {
1797 if (result.first != end)
1798 {
1799 // Partial match. Next search needs to start from beginning of
1800 // match.
1801 search_position_ = result.first - begin;
1802 }
1803 else
1804 {
1805 // Next search can start with the new data.
1806 search_position_ = end - begin;
1807 }
1808
1809 bytes_to_read = std::min<std::size_t>(
1810 std::max<std::size_t>(512,
1811 buffers_.capacity() - buffers_.size()),
1812 std::min<std::size_t>(65536,
1813 buffers_.max_size() - buffers_.size()));
1814 }
1815 }
1816
1817 // Check if we're done.
1818 if (!start && bytes_to_read == 0)
1819 break;
1820
20effc67
TL
1821 // Start a new asynchronous read operation to obtain more data.
1822 {
1823 BOOST_ASIO_HANDLER_LOCATION((
1824 __FILE__, __LINE__, "async_read_until"));
1825 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1826 BOOST_ASIO_MOVE_CAST(read_until_match_op_v1)(*this));
1827 }
92f5a8d4
TL
1828 return; default:
1829 buffers_.commit(bytes_transferred);
1830 if (ec || bytes_transferred == 0)
1831 break;
1e59de90
TL
1832 if (this->cancelled() != cancellation_type::none)
1833 {
1834 ec = error::operation_aborted;
1835 break;
1836 }
92f5a8d4
TL
1837 }
1838
1839 const boost::system::error_code result_ec =
1840 (search_position_ == not_found)
1841 ? error::not_found : ec;
1842
1843 const std::size_t result_n =
1844 (ec || search_position_ == not_found)
1845 ? 0 : search_position_;
1846
1e59de90 1847 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
92f5a8d4
TL
1848 }
1849 }
1850
1851 //private:
1852 AsyncReadStream& stream_;
1853 DynamicBuffer_v1 buffers_;
1854 MatchCondition match_condition_;
1855 int start_;
1856 std::size_t search_position_;
1857 ReadHandler handler_;
1858 };
1859
1860 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1861 typename MatchCondition, typename ReadHandler>
20effc67
TL
1862 inline asio_handler_allocate_is_deprecated
1863 asio_handler_allocate(std::size_t size,
92f5a8d4
TL
1864 read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
1865 MatchCondition, ReadHandler>* this_handler)
1866 {
20effc67
TL
1867#if defined(BOOST_ASIO_NO_DEPRECATED)
1868 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
1869 return asio_handler_allocate_is_no_longer_used();
1870#else // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1871 return boost_asio_handler_alloc_helpers::allocate(
1872 size, this_handler->handler_);
20effc67 1873#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1874 }
1875
1876 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1877 typename MatchCondition, typename ReadHandler>
20effc67
TL
1878 inline asio_handler_deallocate_is_deprecated
1879 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4
TL
1880 read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
1881 MatchCondition, ReadHandler>* this_handler)
1882 {
1883 boost_asio_handler_alloc_helpers::deallocate(
1884 pointer, size, this_handler->handler_);
20effc67
TL
1885#if defined(BOOST_ASIO_NO_DEPRECATED)
1886 return asio_handler_deallocate_is_no_longer_used();
1887#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1888 }
1889
1890 template <typename AsyncReadStream, typename DynamicBuffer_v1,
1891 typename MatchCondition, typename ReadHandler>
1892 inline bool asio_handler_is_continuation(
1893 read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
1894 MatchCondition, ReadHandler>* this_handler)
1895 {
1896 return this_handler->start_ == 0 ? true
1897 : boost_asio_handler_cont_helpers::is_continuation(
1898 this_handler->handler_);
1899 }
1900
1901 template <typename Function, typename AsyncReadStream,
1902 typename DynamicBuffer_v1, typename MatchCondition,
1903 typename ReadHandler>
20effc67
TL
1904 inline asio_handler_invoke_is_deprecated
1905 asio_handler_invoke(Function& function,
92f5a8d4
TL
1906 read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
1907 MatchCondition, ReadHandler>* this_handler)
1908 {
1909 boost_asio_handler_invoke_helpers::invoke(
1910 function, this_handler->handler_);
20effc67
TL
1911#if defined(BOOST_ASIO_NO_DEPRECATED)
1912 return asio_handler_invoke_is_no_longer_used();
1913#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1914 }
1915
1916 template <typename Function, typename AsyncReadStream,
1917 typename DynamicBuffer_v1, typename MatchCondition,
1918 typename ReadHandler>
20effc67
TL
1919 inline asio_handler_invoke_is_deprecated
1920 asio_handler_invoke(const Function& function,
92f5a8d4
TL
1921 read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,
1922 MatchCondition, ReadHandler>* this_handler)
1923 {
1924 boost_asio_handler_invoke_helpers::invoke(
1925 function, this_handler->handler_);
20effc67
TL
1926#if defined(BOOST_ASIO_NO_DEPRECATED)
1927 return asio_handler_invoke_is_no_longer_used();
1928#endif // defined(BOOST_ASIO_NO_DEPRECATED)
92f5a8d4
TL
1929 }
1930
1931 template <typename AsyncReadStream>
1932 class initiate_async_read_until_match_v1
1933 {
1934 public:
1935 typedef typename AsyncReadStream::executor_type executor_type;
1936
1937 explicit initiate_async_read_until_match_v1(AsyncReadStream& stream)
1938 : stream_(stream)
1939 {
1940 }
1941
1942 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
1943 {
1944 return stream_.get_executor();
1945 }
1946
1947 template <typename ReadHandler,
1948 typename DynamicBuffer_v1, typename MatchCondition>
1949 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1950 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
1951 MatchCondition match_condition) const
1952 {
1953 // If you get an error on the following line it means that your handler
1954 // does not meet the documented type requirements for a ReadHandler.
1955 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1956
1957 non_const_lvalue<ReadHandler> handler2(handler);
1958 read_until_match_op_v1<AsyncReadStream,
1959 typename decay<DynamicBuffer_v1>::type,
1960 MatchCondition, typename decay<ReadHandler>::type>(
1961 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),
1962 match_condition, handler2.value)(boost::system::error_code(), 0, 1);
1963 }
1964
1965 private:
1966 AsyncReadStream& stream_;
1967 };
1968} // namespace detail
1969
1970#if !defined(GENERATING_DOCUMENTATION)
1971
1e59de90
TL
1972template <template <typename, typename> class Associator,
1973 typename AsyncReadStream, typename DynamicBuffer_v1,
1974 typename MatchCondition, typename ReadHandler, typename DefaultCandidate>
1975struct associator<Associator,
92f5a8d4
TL
1976 detail::read_until_match_op_v1<AsyncReadStream,
1977 DynamicBuffer_v1, MatchCondition, ReadHandler>,
1e59de90
TL
1978 DefaultCandidate>
1979 : Associator<ReadHandler, DefaultCandidate>
92f5a8d4 1980{
1e59de90 1981 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
1982 const detail::read_until_match_op_v1<AsyncReadStream,
1983 DynamicBuffer_v1, MatchCondition, ReadHandler>& h,
1e59de90 1984 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
92f5a8d4 1985 {
1e59de90 1986 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
7c673cae 1987 }
92f5a8d4 1988};
7c673cae 1989
92f5a8d4 1990#endif // !defined(GENERATING_DOCUMENTATION)
b32b8144 1991
92f5a8d4
TL
1992template <typename AsyncReadStream,
1993 typename DynamicBuffer_v1, typename MatchCondition,
1994 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
1995 std::size_t)) ReadToken>
1996BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
1997 void (boost::system::error_code, std::size_t))
1998async_read_until(AsyncReadStream& s,
1999 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,
1e59de90
TL
2000 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadToken) token,
2001 typename constraint<
92f5a8d4 2002 is_match_condition<MatchCondition>::value
1e59de90
TL
2003 >::type,
2004 typename constraint<
2005 is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value
2006 >::type,
2007 typename constraint<
2008 !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value
2009 >::type)
b32b8144 2010{
1e59de90 2011 return async_initiate<ReadToken,
92f5a8d4 2012 void (boost::system::error_code, std::size_t)>(
1e59de90 2013 detail::initiate_async_read_until_match_v1<AsyncReadStream>(s), token,
92f5a8d4 2014 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition);
b32b8144
FG
2015}
2016
92f5a8d4 2017#if !defined(BOOST_ASIO_NO_IOSTREAM)
b32b8144 2018
92f5a8d4
TL
2019template <typename AsyncReadStream, typename Allocator,
2020 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
2021 std::size_t)) ReadToken>
2022inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
2023 void (boost::system::error_code, std::size_t))
2024async_read_until(AsyncReadStream& s,
b32b8144 2025 boost::asio::basic_streambuf<Allocator>& b,
1e59de90 2026 char delim, BOOST_ASIO_MOVE_ARG(ReadToken) token)
b32b8144 2027{
92f5a8d4 2028 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1e59de90 2029 delim, BOOST_ASIO_MOVE_CAST(ReadToken)(token));
b32b8144
FG
2030}
2031
92f5a8d4
TL
2032template <typename AsyncReadStream, typename Allocator,
2033 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
2034 std::size_t)) ReadToken>
2035inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
2036 void (boost::system::error_code, std::size_t))
2037async_read_until(AsyncReadStream& s,
b32b8144 2038 boost::asio::basic_streambuf<Allocator>& b,
92f5a8d4 2039 BOOST_ASIO_STRING_VIEW_PARAM delim,
1e59de90 2040 BOOST_ASIO_MOVE_ARG(ReadToken) token)
b32b8144 2041{
92f5a8d4 2042 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1e59de90 2043 delim, BOOST_ASIO_MOVE_CAST(ReadToken)(token));
b32b8144
FG
2044}
2045
2046#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
2047
92f5a8d4
TL
2048template <typename AsyncReadStream, typename Allocator,
2049 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
2050 std::size_t)) ReadToken>
2051inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
2052 void (boost::system::error_code, std::size_t))
2053async_read_until(AsyncReadStream& s,
b32b8144 2054 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
1e59de90 2055 BOOST_ASIO_MOVE_ARG(ReadToken) token)
b32b8144 2056{
92f5a8d4 2057 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1e59de90 2058 expr, BOOST_ASIO_MOVE_CAST(ReadToken)(token));
b32b8144
FG
2059}
2060
2061#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
2062
92f5a8d4
TL
2063template <typename AsyncReadStream, typename Allocator, typename MatchCondition,
2064 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
2065 std::size_t)) ReadToken>
2066inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
92f5a8d4
TL
2067 void (boost::system::error_code, std::size_t))
2068async_read_until(AsyncReadStream& s,
b32b8144 2069 boost::asio::basic_streambuf<Allocator>& b,
1e59de90
TL
2070 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadToken) token,
2071 typename constraint<is_match_condition<MatchCondition>::value>::type)
b32b8144 2072{
92f5a8d4 2073 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1e59de90 2074 match_condition, BOOST_ASIO_MOVE_CAST(ReadToken)(token));
7c673cae
FG
2075}
2076
b32b8144
FG
2077#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
2078#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
92f5a8d4 2079#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1)
b32b8144 2080
7c673cae
FG
2081namespace detail
2082{
b32b8144 2083 template <typename AsyncReadStream,
92f5a8d4
TL
2084 typename DynamicBuffer_v2, typename ReadHandler>
2085 class read_until_delim_op_v2
1e59de90 2086 : public base_from_cancellation_state<ReadHandler>
7c673cae
FG
2087 {
2088 public:
b32b8144 2089 template <typename BufferSequence>
92f5a8d4 2090 read_until_delim_op_v2(AsyncReadStream& stream,
b32b8144 2091 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae 2092 char delim, ReadHandler& handler)
1e59de90
TL
2093 : base_from_cancellation_state<ReadHandler>(
2094 handler, enable_partial_cancellation()),
2095 stream_(stream),
b32b8144 2096 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
2097 delim_(delim),
2098 start_(0),
2099 search_position_(0),
92f5a8d4 2100 bytes_to_read_(0),
7c673cae
FG
2101 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
2102 {
2103 }
2104
2105#if defined(BOOST_ASIO_HAS_MOVE)
92f5a8d4 2106 read_until_delim_op_v2(const read_until_delim_op_v2& other)
1e59de90
TL
2107 : base_from_cancellation_state<ReadHandler>(other),
2108 stream_(other.stream_),
b32b8144 2109 buffers_(other.buffers_),
7c673cae
FG
2110 delim_(other.delim_),
2111 start_(other.start_),
2112 search_position_(other.search_position_),
92f5a8d4 2113 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
2114 handler_(other.handler_)
2115 {
2116 }
2117
92f5a8d4 2118 read_until_delim_op_v2(read_until_delim_op_v2&& other)
1e59de90
TL
2119 : base_from_cancellation_state<ReadHandler>(
2120 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
2121 ReadHandler>)(other)),
2122 stream_(other.stream_),
92f5a8d4 2123 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
7c673cae
FG
2124 delim_(other.delim_),
2125 start_(other.start_),
2126 search_position_(other.search_position_),
92f5a8d4 2127 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
2128 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
2129 {
2130 }
2131#endif // defined(BOOST_ASIO_HAS_MOVE)
2132
1e59de90 2133 void operator()(boost::system::error_code ec,
7c673cae
FG
2134 std::size_t bytes_transferred, int start = 0)
2135 {
2136 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
92f5a8d4 2137 std::size_t pos;
7c673cae
FG
2138 switch (start_ = start)
2139 {
2140 case 1:
2141 for (;;)
2142 {
2143 {
2144 // Determine the range of the data to be searched.
92f5a8d4 2145 typedef typename DynamicBuffer_v2::const_buffers_type
b32b8144
FG
2146 buffers_type;
2147 typedef buffers_iterator<buffers_type> iterator;
92f5a8d4
TL
2148 buffers_type data_buffers =
2149 const_cast<const DynamicBuffer_v2&>(buffers_).data(
2150 0, buffers_.size());
b32b8144 2151 iterator begin = iterator::begin(data_buffers);
7c673cae 2152 iterator start_pos = begin + search_position_;
b32b8144 2153 iterator end = iterator::end(data_buffers);
7c673cae
FG
2154
2155 // Look for a match.
2156 iterator iter = std::find(start_pos, end, delim_);
2157 if (iter != end)
2158 {
2159 // Found a match. We're done.
2160 search_position_ = iter - begin + 1;
92f5a8d4 2161 bytes_to_read_ = 0;
7c673cae
FG
2162 }
2163
2164 // No match yet. Check if buffer is full.
b32b8144 2165 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
2166 {
2167 search_position_ = not_found;
92f5a8d4 2168 bytes_to_read_ = 0;
7c673cae
FG
2169 }
2170
2171 // Need to read some more data.
2172 else
2173 {
2174 // Next search can start with the new data.
2175 search_position_ = end - begin;
92f5a8d4 2176 bytes_to_read_ = std::min<std::size_t>(
b32b8144
FG
2177 std::max<std::size_t>(512,
2178 buffers_.capacity() - buffers_.size()),
2179 std::min<std::size_t>(65536,
2180 buffers_.max_size() - buffers_.size()));
7c673cae
FG
2181 }
2182 }
2183
2184 // Check if we're done.
92f5a8d4 2185 if (!start && bytes_to_read_ == 0)
7c673cae
FG
2186 break;
2187
20effc67 2188 // Start a new asynchronous read operation to obtain more data.
92f5a8d4
TL
2189 pos = buffers_.size();
2190 buffers_.grow(bytes_to_read_);
20effc67
TL
2191 {
2192 BOOST_ASIO_HANDLER_LOCATION((
2193 __FILE__, __LINE__, "async_read_until"));
2194 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2195 BOOST_ASIO_MOVE_CAST(read_until_delim_op_v2)(*this));
2196 }
7c673cae 2197 return; default:
92f5a8d4 2198 buffers_.shrink(bytes_to_read_ - bytes_transferred);
7c673cae
FG
2199 if (ec || bytes_transferred == 0)
2200 break;
1e59de90
TL
2201 if (this->cancelled() != cancellation_type::none)
2202 {
2203 ec = error::operation_aborted;
2204 break;
2205 }
7c673cae
FG
2206 }
2207
2208 const boost::system::error_code result_ec =
2209 (search_position_ == not_found)
2210 ? error::not_found : ec;
2211
2212 const std::size_t result_n =
2213 (ec || search_position_ == not_found)
2214 ? 0 : search_position_;
2215
1e59de90 2216 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
7c673cae
FG
2217 }
2218 }
2219
2220 //private:
2221 AsyncReadStream& stream_;
92f5a8d4 2222 DynamicBuffer_v2 buffers_;
7c673cae
FG
2223 char delim_;
2224 int start_;
2225 std::size_t search_position_;
92f5a8d4 2226 std::size_t bytes_to_read_;
7c673cae
FG
2227 ReadHandler handler_;
2228 };
2229
b32b8144 2230 template <typename AsyncReadStream,
92f5a8d4 2231 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2232 inline asio_handler_allocate_is_deprecated
2233 asio_handler_allocate(std::size_t size,
92f5a8d4
TL
2234 read_until_delim_op_v2<AsyncReadStream,
2235 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae 2236 {
20effc67
TL
2237#if defined(BOOST_ASIO_NO_DEPRECATED)
2238 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
2239 return asio_handler_allocate_is_no_longer_used();
2240#else // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2241 return boost_asio_handler_alloc_helpers::allocate(
2242 size, this_handler->handler_);
20effc67 2243#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2244 }
2245
b32b8144 2246 template <typename AsyncReadStream,
92f5a8d4 2247 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2248 inline asio_handler_deallocate_is_deprecated
2249 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4
TL
2250 read_until_delim_op_v2<AsyncReadStream,
2251 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2252 {
2253 boost_asio_handler_alloc_helpers::deallocate(
2254 pointer, size, this_handler->handler_);
20effc67
TL
2255#if defined(BOOST_ASIO_NO_DEPRECATED)
2256 return asio_handler_deallocate_is_no_longer_used();
2257#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2258 }
2259
b32b8144 2260 template <typename AsyncReadStream,
92f5a8d4 2261 typename DynamicBuffer_v2, typename ReadHandler>
7c673cae 2262 inline bool asio_handler_is_continuation(
92f5a8d4
TL
2263 read_until_delim_op_v2<AsyncReadStream,
2264 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2265 {
2266 return this_handler->start_ == 0 ? true
2267 : boost_asio_handler_cont_helpers::is_continuation(
2268 this_handler->handler_);
2269 }
2270
b32b8144 2271 template <typename Function, typename AsyncReadStream,
92f5a8d4 2272 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2273 inline asio_handler_invoke_is_deprecated
2274 asio_handler_invoke(Function& function,
92f5a8d4
TL
2275 read_until_delim_op_v2<AsyncReadStream,
2276 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2277 {
2278 boost_asio_handler_invoke_helpers::invoke(
2279 function, this_handler->handler_);
20effc67
TL
2280#if defined(BOOST_ASIO_NO_DEPRECATED)
2281 return asio_handler_invoke_is_no_longer_used();
2282#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2283 }
2284
b32b8144 2285 template <typename Function, typename AsyncReadStream,
92f5a8d4 2286 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2287 inline asio_handler_invoke_is_deprecated
2288 asio_handler_invoke(const Function& function,
92f5a8d4
TL
2289 read_until_delim_op_v2<AsyncReadStream,
2290 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2291 {
2292 boost_asio_handler_invoke_helpers::invoke(
2293 function, this_handler->handler_);
20effc67
TL
2294#if defined(BOOST_ASIO_NO_DEPRECATED)
2295 return asio_handler_invoke_is_no_longer_used();
2296#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae 2297 }
92f5a8d4
TL
2298
2299 template <typename AsyncReadStream>
2300 class initiate_async_read_until_delim_v2
2301 {
2302 public:
2303 typedef typename AsyncReadStream::executor_type executor_type;
2304
2305 explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream)
2306 : stream_(stream)
2307 {
2308 }
2309
2310 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
2311 {
2312 return stream_.get_executor();
2313 }
2314
2315 template <typename ReadHandler, typename DynamicBuffer_v2>
2316 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
2317 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, char delim) const
2318 {
2319 // If you get an error on the following line it means that your handler
2320 // does not meet the documented type requirements for a ReadHandler.
2321 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2322
2323 non_const_lvalue<ReadHandler> handler2(handler);
2324 read_until_delim_op_v2<AsyncReadStream,
2325 typename decay<DynamicBuffer_v2>::type,
2326 typename decay<ReadHandler>::type>(
2327 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
2328 delim, handler2.value)(boost::system::error_code(), 0, 1);
2329 }
2330
2331 private:
2332 AsyncReadStream& stream_;
2333 };
7c673cae
FG
2334} // namespace detail
2335
b32b8144
FG
2336#if !defined(GENERATING_DOCUMENTATION)
2337
1e59de90
TL
2338template <template <typename, typename> class Associator,
2339 typename AsyncReadStream, typename DynamicBuffer_v2,
2340 typename ReadHandler, typename DefaultCandidate>
2341struct associator<Associator,
92f5a8d4
TL
2342 detail::read_until_delim_op_v2<AsyncReadStream,
2343 DynamicBuffer_v2, ReadHandler>,
1e59de90
TL
2344 DefaultCandidate>
2345 : Associator<ReadHandler, DefaultCandidate>
b32b8144 2346{
1e59de90 2347 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
2348 const detail::read_until_delim_op_v2<AsyncReadStream,
2349 DynamicBuffer_v2, ReadHandler>& h,
1e59de90 2350 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
b32b8144 2351 {
1e59de90 2352 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
b32b8144
FG
2353 }
2354};
2355
2356#endif // !defined(GENERATING_DOCUMENTATION)
2357
92f5a8d4
TL
2358template <typename AsyncReadStream, typename DynamicBuffer_v2,
2359 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
2360 std::size_t)) ReadToken>
2361BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
7c673cae 2362 void (boost::system::error_code, std::size_t))
92f5a8d4 2363async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
1e59de90
TL
2364 char delim, BOOST_ASIO_MOVE_ARG(ReadToken) token,
2365 typename constraint<
92f5a8d4 2366 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 2367 >::type)
7c673cae 2368{
1e59de90 2369 return async_initiate<ReadToken,
92f5a8d4
TL
2370 void (boost::system::error_code, std::size_t)>(
2371 detail::initiate_async_read_until_delim_v2<AsyncReadStream>(s),
1e59de90 2372 token, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim);
7c673cae
FG
2373}
2374
2375namespace detail
2376{
b32b8144 2377 template <typename AsyncReadStream,
92f5a8d4
TL
2378 typename DynamicBuffer_v2, typename ReadHandler>
2379 class read_until_delim_string_op_v2
1e59de90 2380 : public base_from_cancellation_state<ReadHandler>
7c673cae
FG
2381 {
2382 public:
b32b8144 2383 template <typename BufferSequence>
92f5a8d4 2384 read_until_delim_string_op_v2(AsyncReadStream& stream,
b32b8144 2385 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae 2386 const std::string& delim, ReadHandler& handler)
1e59de90
TL
2387 : base_from_cancellation_state<ReadHandler>(
2388 handler, enable_partial_cancellation()),
2389 stream_(stream),
b32b8144 2390 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
2391 delim_(delim),
2392 start_(0),
2393 search_position_(0),
92f5a8d4 2394 bytes_to_read_(0),
7c673cae
FG
2395 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
2396 {
2397 }
2398
2399#if defined(BOOST_ASIO_HAS_MOVE)
92f5a8d4 2400 read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other)
1e59de90
TL
2401 : base_from_cancellation_state<ReadHandler>(other),
2402 stream_(other.stream_),
b32b8144 2403 buffers_(other.buffers_),
7c673cae
FG
2404 delim_(other.delim_),
2405 start_(other.start_),
2406 search_position_(other.search_position_),
92f5a8d4 2407 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
2408 handler_(other.handler_)
2409 {
2410 }
2411
92f5a8d4 2412 read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other)
1e59de90
TL
2413 : base_from_cancellation_state<ReadHandler>(
2414 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
2415 ReadHandler>)(other)),
2416 stream_(other.stream_),
92f5a8d4 2417 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
7c673cae
FG
2418 delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
2419 start_(other.start_),
2420 search_position_(other.search_position_),
92f5a8d4 2421 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
2422 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
2423 {
2424 }
2425#endif // defined(BOOST_ASIO_HAS_MOVE)
2426
1e59de90 2427 void operator()(boost::system::error_code ec,
7c673cae
FG
2428 std::size_t bytes_transferred, int start = 0)
2429 {
2430 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
92f5a8d4 2431 std::size_t pos;
7c673cae
FG
2432 switch (start_ = start)
2433 {
2434 case 1:
2435 for (;;)
2436 {
2437 {
2438 // Determine the range of the data to be searched.
92f5a8d4 2439 typedef typename DynamicBuffer_v2::const_buffers_type
b32b8144
FG
2440 buffers_type;
2441 typedef buffers_iterator<buffers_type> iterator;
92f5a8d4
TL
2442 buffers_type data_buffers =
2443 const_cast<const DynamicBuffer_v2&>(buffers_).data(
2444 0, buffers_.size());
b32b8144 2445 iterator begin = iterator::begin(data_buffers);
7c673cae 2446 iterator start_pos = begin + search_position_;
b32b8144 2447 iterator end = iterator::end(data_buffers);
7c673cae
FG
2448
2449 // Look for a match.
2450 std::pair<iterator, bool> result = detail::partial_search(
2451 start_pos, end, delim_.begin(), delim_.end());
2452 if (result.first != end && result.second)
2453 {
2454 // Full match. We're done.
2455 search_position_ = result.first - begin + delim_.length();
92f5a8d4 2456 bytes_to_read_ = 0;
7c673cae
FG
2457 }
2458
2459 // No match yet. Check if buffer is full.
b32b8144 2460 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
2461 {
2462 search_position_ = not_found;
92f5a8d4 2463 bytes_to_read_ = 0;
7c673cae
FG
2464 }
2465
2466 // Need to read some more data.
2467 else
2468 {
2469 if (result.first != end)
2470 {
2471 // Partial match. Next search needs to start from beginning of
2472 // match.
2473 search_position_ = result.first - begin;
2474 }
2475 else
2476 {
2477 // Next search can start with the new data.
2478 search_position_ = end - begin;
2479 }
2480
92f5a8d4 2481 bytes_to_read_ = std::min<std::size_t>(
b32b8144
FG
2482 std::max<std::size_t>(512,
2483 buffers_.capacity() - buffers_.size()),
2484 std::min<std::size_t>(65536,
2485 buffers_.max_size() - buffers_.size()));
7c673cae
FG
2486 }
2487 }
2488
2489 // Check if we're done.
92f5a8d4 2490 if (!start && bytes_to_read_ == 0)
7c673cae
FG
2491 break;
2492
20effc67 2493 // Start a new asynchronous read operation to obtain more data.
92f5a8d4
TL
2494 pos = buffers_.size();
2495 buffers_.grow(bytes_to_read_);
20effc67
TL
2496 {
2497 BOOST_ASIO_HANDLER_LOCATION((
2498 __FILE__, __LINE__, "async_read_until"));
2499 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2500 BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v2)(*this));
2501 }
7c673cae 2502 return; default:
92f5a8d4 2503 buffers_.shrink(bytes_to_read_ - bytes_transferred);
7c673cae
FG
2504 if (ec || bytes_transferred == 0)
2505 break;
1e59de90
TL
2506 if (this->cancelled() != cancellation_type::none)
2507 {
2508 ec = error::operation_aborted;
2509 break;
2510 }
7c673cae
FG
2511 }
2512
2513 const boost::system::error_code result_ec =
2514 (search_position_ == not_found)
2515 ? error::not_found : ec;
2516
2517 const std::size_t result_n =
2518 (ec || search_position_ == not_found)
2519 ? 0 : search_position_;
2520
1e59de90 2521 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
7c673cae
FG
2522 }
2523 }
2524
2525 //private:
2526 AsyncReadStream& stream_;
92f5a8d4 2527 DynamicBuffer_v2 buffers_;
7c673cae
FG
2528 std::string delim_;
2529 int start_;
2530 std::size_t search_position_;
92f5a8d4 2531 std::size_t bytes_to_read_;
7c673cae
FG
2532 ReadHandler handler_;
2533 };
2534
b32b8144 2535 template <typename AsyncReadStream,
92f5a8d4 2536 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2537 inline asio_handler_allocate_is_deprecated
2538 asio_handler_allocate(std::size_t size,
92f5a8d4
TL
2539 read_until_delim_string_op_v2<AsyncReadStream,
2540 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae 2541 {
20effc67
TL
2542#if defined(BOOST_ASIO_NO_DEPRECATED)
2543 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
2544 return asio_handler_allocate_is_no_longer_used();
2545#else // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2546 return boost_asio_handler_alloc_helpers::allocate(
2547 size, this_handler->handler_);
20effc67 2548#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2549 }
2550
b32b8144 2551 template <typename AsyncReadStream,
92f5a8d4 2552 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2553 inline asio_handler_deallocate_is_deprecated
2554 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4
TL
2555 read_until_delim_string_op_v2<AsyncReadStream,
2556 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2557 {
2558 boost_asio_handler_alloc_helpers::deallocate(
2559 pointer, size, this_handler->handler_);
20effc67
TL
2560#if defined(BOOST_ASIO_NO_DEPRECATED)
2561 return asio_handler_deallocate_is_no_longer_used();
2562#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2563 }
2564
b32b8144 2565 template <typename AsyncReadStream,
92f5a8d4 2566 typename DynamicBuffer_v2, typename ReadHandler>
7c673cae 2567 inline bool asio_handler_is_continuation(
92f5a8d4
TL
2568 read_until_delim_string_op_v2<AsyncReadStream,
2569 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2570 {
2571 return this_handler->start_ == 0 ? true
2572 : boost_asio_handler_cont_helpers::is_continuation(
2573 this_handler->handler_);
2574 }
2575
2576 template <typename Function, typename AsyncReadStream,
92f5a8d4 2577 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2578 inline asio_handler_invoke_is_deprecated
2579 asio_handler_invoke(Function& function,
92f5a8d4
TL
2580 read_until_delim_string_op_v2<AsyncReadStream,
2581 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2582 {
2583 boost_asio_handler_invoke_helpers::invoke(
2584 function, this_handler->handler_);
20effc67
TL
2585#if defined(BOOST_ASIO_NO_DEPRECATED)
2586 return asio_handler_invoke_is_no_longer_used();
2587#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2588 }
2589
2590 template <typename Function, typename AsyncReadStream,
92f5a8d4 2591 typename DynamicBuffer_v2, typename ReadHandler>
20effc67
TL
2592 inline asio_handler_invoke_is_deprecated
2593 asio_handler_invoke(const Function& function,
92f5a8d4
TL
2594 read_until_delim_string_op_v2<AsyncReadStream,
2595 DynamicBuffer_v2, ReadHandler>* this_handler)
7c673cae
FG
2596 {
2597 boost_asio_handler_invoke_helpers::invoke(
2598 function, this_handler->handler_);
20effc67
TL
2599#if defined(BOOST_ASIO_NO_DEPRECATED)
2600 return asio_handler_invoke_is_no_longer_used();
2601#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae 2602 }
92f5a8d4
TL
2603
2604 template <typename AsyncReadStream>
2605 class initiate_async_read_until_delim_string_v2
2606 {
2607 public:
2608 typedef typename AsyncReadStream::executor_type executor_type;
2609
2610 explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream)
2611 : stream_(stream)
2612 {
2613 }
2614
2615 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
2616 {
2617 return stream_.get_executor();
2618 }
2619
2620 template <typename ReadHandler, typename DynamicBuffer_v2>
2621 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
2622 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
2623 const std::string& delim) const
2624 {
2625 // If you get an error on the following line it means that your handler
2626 // does not meet the documented type requirements for a ReadHandler.
2627 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2628
2629 non_const_lvalue<ReadHandler> handler2(handler);
2630 read_until_delim_string_op_v2<AsyncReadStream,
2631 typename decay<DynamicBuffer_v2>::type,
2632 typename decay<ReadHandler>::type>(
2633 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
2634 delim, handler2.value)(boost::system::error_code(), 0, 1);
2635 }
2636
2637 private:
2638 AsyncReadStream& stream_;
2639 };
7c673cae
FG
2640} // namespace detail
2641
b32b8144
FG
2642#if !defined(GENERATING_DOCUMENTATION)
2643
1e59de90
TL
2644template <template <typename, typename> class Associator,
2645 typename AsyncReadStream, typename DynamicBuffer_v2,
2646 typename ReadHandler, typename DefaultCandidate>
2647struct associator<Associator,
92f5a8d4
TL
2648 detail::read_until_delim_string_op_v2<AsyncReadStream,
2649 DynamicBuffer_v2, ReadHandler>,
1e59de90
TL
2650 DefaultCandidate>
2651 : Associator<ReadHandler, DefaultCandidate>
b32b8144 2652{
1e59de90 2653 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
2654 const detail::read_until_delim_string_op_v2<AsyncReadStream,
2655 DynamicBuffer_v2, ReadHandler>& h,
1e59de90 2656 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
b32b8144 2657 {
1e59de90 2658 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
b32b8144
FG
2659 }
2660};
2661
2662#endif // !defined(GENERATING_DOCUMENTATION)
2663
2664template <typename AsyncReadStream,
92f5a8d4
TL
2665 typename DynamicBuffer_v2,
2666 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
2667 std::size_t)) ReadToken>
2668BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
7c673cae
FG
2669 void (boost::system::error_code, std::size_t))
2670async_read_until(AsyncReadStream& s,
92f5a8d4 2671 DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim,
1e59de90
TL
2672 BOOST_ASIO_MOVE_ARG(ReadToken) token,
2673 typename constraint<
92f5a8d4 2674 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 2675 >::type)
7c673cae 2676{
1e59de90 2677 return async_initiate<ReadToken,
92f5a8d4
TL
2678 void (boost::system::error_code, std::size_t)>(
2679 detail::initiate_async_read_until_delim_string_v2<AsyncReadStream>(s),
1e59de90 2680 token, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
92f5a8d4 2681 static_cast<std::string>(delim));
7c673cae
FG
2682}
2683
b32b8144 2684#if !defined(BOOST_ASIO_NO_EXTENSIONS)
7c673cae
FG
2685#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
2686
2687namespace detail
2688{
92f5a8d4 2689 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae 2690 typename RegEx, typename ReadHandler>
92f5a8d4 2691 class read_until_expr_op_v2
1e59de90 2692 : public base_from_cancellation_state<ReadHandler>
7c673cae
FG
2693 {
2694 public:
b32b8144 2695 template <typename BufferSequence>
92f5a8d4 2696 read_until_expr_op_v2(AsyncReadStream& stream,
b32b8144 2697 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae 2698 const boost::regex& expr, ReadHandler& handler)
1e59de90
TL
2699 : base_from_cancellation_state<ReadHandler>(
2700 handler, enable_partial_cancellation()),
2701 stream_(stream),
b32b8144 2702 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
2703 expr_(expr),
2704 start_(0),
2705 search_position_(0),
92f5a8d4 2706 bytes_to_read_(0),
7c673cae
FG
2707 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
2708 {
2709 }
2710
2711#if defined(BOOST_ASIO_HAS_MOVE)
92f5a8d4 2712 read_until_expr_op_v2(const read_until_expr_op_v2& other)
1e59de90
TL
2713 : base_from_cancellation_state<ReadHandler>(other),
2714 stream_(other.stream_),
b32b8144 2715 buffers_(other.buffers_),
7c673cae
FG
2716 expr_(other.expr_),
2717 start_(other.start_),
2718 search_position_(other.search_position_),
92f5a8d4 2719 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
2720 handler_(other.handler_)
2721 {
2722 }
2723
92f5a8d4 2724 read_until_expr_op_v2(read_until_expr_op_v2&& other)
1e59de90
TL
2725 : base_from_cancellation_state<ReadHandler>(
2726 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
2727 ReadHandler>)(other)),
2728 stream_(other.stream_),
92f5a8d4 2729 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
7c673cae
FG
2730 expr_(other.expr_),
2731 start_(other.start_),
2732 search_position_(other.search_position_),
92f5a8d4 2733 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
2734 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
2735 {
2736 }
2737#endif // defined(BOOST_ASIO_HAS_MOVE)
2738
1e59de90 2739 void operator()(boost::system::error_code ec,
7c673cae
FG
2740 std::size_t bytes_transferred, int start = 0)
2741 {
2742 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
92f5a8d4 2743 std::size_t pos;
7c673cae
FG
2744 switch (start_ = start)
2745 {
2746 case 1:
2747 for (;;)
2748 {
2749 {
2750 // Determine the range of the data to be searched.
92f5a8d4 2751 typedef typename DynamicBuffer_v2::const_buffers_type
b32b8144
FG
2752 buffers_type;
2753 typedef buffers_iterator<buffers_type> iterator;
92f5a8d4
TL
2754 buffers_type data_buffers =
2755 const_cast<const DynamicBuffer_v2&>(buffers_).data(
2756 0, buffers_.size());
b32b8144 2757 iterator begin = iterator::begin(data_buffers);
7c673cae 2758 iterator start_pos = begin + search_position_;
b32b8144 2759 iterator end = iterator::end(data_buffers);
7c673cae
FG
2760
2761 // Look for a match.
2762 boost::match_results<iterator,
2763 typename std::vector<boost::sub_match<iterator> >::allocator_type>
2764 match_results;
2765 bool match = regex_search(start_pos, end, match_results, expr_,
2766 boost::match_default | boost::match_partial);
2767 if (match && match_results[0].matched)
2768 {
2769 // Full match. We're done.
2770 search_position_ = match_results[0].second - begin;
92f5a8d4 2771 bytes_to_read_ = 0;
7c673cae
FG
2772 }
2773
2774 // No match yet. Check if buffer is full.
b32b8144 2775 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
2776 {
2777 search_position_ = not_found;
92f5a8d4 2778 bytes_to_read_ = 0;
7c673cae
FG
2779 }
2780
2781 // Need to read some more data.
2782 else
2783 {
2784 if (match)
2785 {
2786 // Partial match. Next search needs to start from beginning of
2787 // match.
2788 search_position_ = match_results[0].first - begin;
2789 }
2790 else
2791 {
2792 // Next search can start with the new data.
2793 search_position_ = end - begin;
2794 }
2795
92f5a8d4 2796 bytes_to_read_ = std::min<std::size_t>(
b32b8144
FG
2797 std::max<std::size_t>(512,
2798 buffers_.capacity() - buffers_.size()),
2799 std::min<std::size_t>(65536,
2800 buffers_.max_size() - buffers_.size()));
7c673cae
FG
2801 }
2802 }
2803
2804 // Check if we're done.
92f5a8d4 2805 if (!start && bytes_to_read_ == 0)
7c673cae
FG
2806 break;
2807
20effc67 2808 // Start a new asynchronous read operation to obtain more data.
92f5a8d4
TL
2809 pos = buffers_.size();
2810 buffers_.grow(bytes_to_read_);
20effc67
TL
2811 {
2812 BOOST_ASIO_HANDLER_LOCATION((
2813 __FILE__, __LINE__, "async_read_until"));
2814 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
2815 BOOST_ASIO_MOVE_CAST(read_until_expr_op_v2)(*this));
2816 }
7c673cae 2817 return; default:
92f5a8d4 2818 buffers_.shrink(bytes_to_read_ - bytes_transferred);
7c673cae
FG
2819 if (ec || bytes_transferred == 0)
2820 break;
1e59de90
TL
2821 if (this->cancelled() != cancellation_type::none)
2822 {
2823 ec = error::operation_aborted;
2824 break;
2825 }
7c673cae
FG
2826 }
2827
2828 const boost::system::error_code result_ec =
2829 (search_position_ == not_found)
2830 ? error::not_found : ec;
2831
2832 const std::size_t result_n =
2833 (ec || search_position_ == not_found)
2834 ? 0 : search_position_;
2835
1e59de90 2836 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
7c673cae
FG
2837 }
2838 }
2839
2840 //private:
2841 AsyncReadStream& stream_;
92f5a8d4 2842 DynamicBuffer_v2 buffers_;
7c673cae
FG
2843 RegEx expr_;
2844 int start_;
2845 std::size_t search_position_;
92f5a8d4 2846 std::size_t bytes_to_read_;
7c673cae
FG
2847 ReadHandler handler_;
2848 };
2849
92f5a8d4 2850 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae 2851 typename RegEx, typename ReadHandler>
20effc67
TL
2852 inline asio_handler_allocate_is_deprecated
2853 asio_handler_allocate(std::size_t size,
92f5a8d4
TL
2854 read_until_expr_op_v2<AsyncReadStream,
2855 DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
7c673cae 2856 {
20effc67
TL
2857#if defined(BOOST_ASIO_NO_DEPRECATED)
2858 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
2859 return asio_handler_allocate_is_no_longer_used();
2860#else // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2861 return boost_asio_handler_alloc_helpers::allocate(
2862 size, this_handler->handler_);
20effc67 2863#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2864 }
2865
92f5a8d4 2866 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae 2867 typename RegEx, typename ReadHandler>
20effc67
TL
2868 inline asio_handler_deallocate_is_deprecated
2869 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4
TL
2870 read_until_expr_op_v2<AsyncReadStream,
2871 DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
7c673cae
FG
2872 {
2873 boost_asio_handler_alloc_helpers::deallocate(
2874 pointer, size, this_handler->handler_);
20effc67
TL
2875#if defined(BOOST_ASIO_NO_DEPRECATED)
2876 return asio_handler_deallocate_is_no_longer_used();
2877#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2878 }
2879
92f5a8d4 2880 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae
FG
2881 typename RegEx, typename ReadHandler>
2882 inline bool asio_handler_is_continuation(
92f5a8d4
TL
2883 read_until_expr_op_v2<AsyncReadStream,
2884 DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
7c673cae
FG
2885 {
2886 return this_handler->start_ == 0 ? true
2887 : boost_asio_handler_cont_helpers::is_continuation(
2888 this_handler->handler_);
2889 }
2890
b32b8144 2891 template <typename Function, typename AsyncReadStream,
92f5a8d4 2892 typename DynamicBuffer_v2, typename RegEx, typename ReadHandler>
20effc67
TL
2893 inline asio_handler_invoke_is_deprecated
2894 asio_handler_invoke(Function& function,
92f5a8d4
TL
2895 read_until_expr_op_v2<AsyncReadStream,
2896 DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
7c673cae
FG
2897 {
2898 boost_asio_handler_invoke_helpers::invoke(
2899 function, this_handler->handler_);
20effc67
TL
2900#if defined(BOOST_ASIO_NO_DEPRECATED)
2901 return asio_handler_invoke_is_no_longer_used();
2902#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
2903 }
2904
b32b8144 2905 template <typename Function, typename AsyncReadStream,
92f5a8d4 2906 typename DynamicBuffer_v2, typename RegEx, typename ReadHandler>
20effc67
TL
2907 inline asio_handler_invoke_is_deprecated
2908 asio_handler_invoke(const Function& function,
92f5a8d4
TL
2909 read_until_expr_op_v2<AsyncReadStream,
2910 DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)
7c673cae
FG
2911 {
2912 boost_asio_handler_invoke_helpers::invoke(
2913 function, this_handler->handler_);
20effc67
TL
2914#if defined(BOOST_ASIO_NO_DEPRECATED)
2915 return asio_handler_invoke_is_no_longer_used();
2916#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae 2917 }
92f5a8d4
TL
2918
2919 template <typename AsyncReadStream>
2920 class initiate_async_read_until_expr_v2
2921 {
2922 public:
2923 typedef typename AsyncReadStream::executor_type executor_type;
2924
2925 explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream)
2926 : stream_(stream)
2927 {
2928 }
2929
2930 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
2931 {
2932 return stream_.get_executor();
2933 }
2934
2935 template <typename ReadHandler, typename DynamicBuffer_v2, typename RegEx>
2936 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
2937 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
2938 const RegEx& expr) const
2939 {
2940 // If you get an error on the following line it means that your handler
2941 // does not meet the documented type requirements for a ReadHandler.
2942 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
2943
2944 non_const_lvalue<ReadHandler> handler2(handler);
2945 read_until_expr_op_v2<AsyncReadStream,
2946 typename decay<DynamicBuffer_v2>::type,
2947 RegEx, typename decay<ReadHandler>::type>(
2948 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
2949 expr, handler2.value)(boost::system::error_code(), 0, 1);
2950 }
2951
2952 private:
2953 AsyncReadStream& stream_;
2954 };
7c673cae
FG
2955} // namespace detail
2956
b32b8144
FG
2957#if !defined(GENERATING_DOCUMENTATION)
2958
1e59de90
TL
2959template <template <typename, typename> class Associator,
2960 typename AsyncReadStream, typename DynamicBuffer_v2,
2961 typename RegEx, typename ReadHandler, typename DefaultCandidate>
2962struct associator<Associator,
92f5a8d4
TL
2963 detail::read_until_expr_op_v2<AsyncReadStream,
2964 DynamicBuffer_v2, RegEx, ReadHandler>,
1e59de90
TL
2965 DefaultCandidate>
2966 : Associator<ReadHandler, DefaultCandidate>
b32b8144 2967{
1e59de90 2968 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
2969 const detail::read_until_expr_op_v2<AsyncReadStream,
2970 DynamicBuffer_v2, RegEx, ReadHandler>& h,
1e59de90 2971 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
b32b8144 2972 {
1e59de90 2973 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
b32b8144
FG
2974 }
2975};
2976
2977#endif // !defined(GENERATING_DOCUMENTATION)
2978
92f5a8d4
TL
2979template <typename AsyncReadStream, typename DynamicBuffer_v2,
2980 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
2981 std::size_t)) ReadToken>
2982BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
7c673cae 2983 void (boost::system::error_code, std::size_t))
92f5a8d4 2984async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
1e59de90
TL
2985 const boost::regex& expr, BOOST_ASIO_MOVE_ARG(ReadToken) token,
2986 typename constraint<
92f5a8d4 2987 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
1e59de90 2988 >::type)
7c673cae 2989{
1e59de90 2990 return async_initiate<ReadToken,
92f5a8d4
TL
2991 void (boost::system::error_code, std::size_t)>(
2992 detail::initiate_async_read_until_expr_v2<AsyncReadStream>(s),
1e59de90 2993 token, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr);
7c673cae
FG
2994}
2995
2996#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
2997
2998namespace detail
2999{
92f5a8d4 3000 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae 3001 typename MatchCondition, typename ReadHandler>
92f5a8d4 3002 class read_until_match_op_v2
1e59de90 3003 : public base_from_cancellation_state<ReadHandler>
7c673cae
FG
3004 {
3005 public:
b32b8144 3006 template <typename BufferSequence>
92f5a8d4 3007 read_until_match_op_v2(AsyncReadStream& stream,
b32b8144 3008 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae 3009 MatchCondition match_condition, ReadHandler& handler)
1e59de90
TL
3010 : base_from_cancellation_state<ReadHandler>(
3011 handler, enable_partial_cancellation()),
3012 stream_(stream),
b32b8144 3013 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
3014 match_condition_(match_condition),
3015 start_(0),
3016 search_position_(0),
92f5a8d4 3017 bytes_to_read_(0),
7c673cae
FG
3018 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
3019 {
3020 }
3021
3022#if defined(BOOST_ASIO_HAS_MOVE)
92f5a8d4 3023 read_until_match_op_v2(const read_until_match_op_v2& other)
1e59de90
TL
3024 : base_from_cancellation_state<ReadHandler>(other),
3025 stream_(other.stream_),
b32b8144 3026 buffers_(other.buffers_),
7c673cae
FG
3027 match_condition_(other.match_condition_),
3028 start_(other.start_),
3029 search_position_(other.search_position_),
92f5a8d4 3030 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
3031 handler_(other.handler_)
3032 {
3033 }
3034
92f5a8d4 3035 read_until_match_op_v2(read_until_match_op_v2&& other)
1e59de90
TL
3036 : base_from_cancellation_state<ReadHandler>(
3037 BOOST_ASIO_MOVE_CAST(base_from_cancellation_state<
3038 ReadHandler>)(other)),
3039 stream_(other.stream_),
92f5a8d4 3040 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),
7c673cae
FG
3041 match_condition_(other.match_condition_),
3042 start_(other.start_),
3043 search_position_(other.search_position_),
92f5a8d4 3044 bytes_to_read_(other.bytes_to_read_),
7c673cae
FG
3045 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
3046 {
3047 }
3048#endif // defined(BOOST_ASIO_HAS_MOVE)
3049
1e59de90 3050 void operator()(boost::system::error_code ec,
7c673cae
FG
3051 std::size_t bytes_transferred, int start = 0)
3052 {
3053 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
92f5a8d4 3054 std::size_t pos;
7c673cae
FG
3055 switch (start_ = start)
3056 {
3057 case 1:
3058 for (;;)
3059 {
3060 {
3061 // Determine the range of the data to be searched.
92f5a8d4 3062 typedef typename DynamicBuffer_v2::const_buffers_type
b32b8144
FG
3063 buffers_type;
3064 typedef buffers_iterator<buffers_type> iterator;
92f5a8d4
TL
3065 buffers_type data_buffers =
3066 const_cast<const DynamicBuffer_v2&>(buffers_).data(
3067 0, buffers_.size());
b32b8144 3068 iterator begin = iterator::begin(data_buffers);
7c673cae 3069 iterator start_pos = begin + search_position_;
b32b8144 3070 iterator end = iterator::end(data_buffers);
7c673cae
FG
3071
3072 // Look for a match.
3073 std::pair<iterator, bool> result = match_condition_(start_pos, end);
3074 if (result.second)
3075 {
3076 // Full match. We're done.
3077 search_position_ = result.first - begin;
92f5a8d4 3078 bytes_to_read_ = 0;
7c673cae
FG
3079 }
3080
3081 // No match yet. Check if buffer is full.
b32b8144 3082 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
3083 {
3084 search_position_ = not_found;
92f5a8d4 3085 bytes_to_read_ = 0;
7c673cae
FG
3086 }
3087
3088 // Need to read some more data.
3089 else
3090 {
3091 if (result.first != end)
3092 {
3093 // Partial match. Next search needs to start from beginning of
3094 // match.
3095 search_position_ = result.first - begin;
3096 }
3097 else
3098 {
3099 // Next search can start with the new data.
3100 search_position_ = end - begin;
3101 }
3102
92f5a8d4 3103 bytes_to_read_ = std::min<std::size_t>(
b32b8144
FG
3104 std::max<std::size_t>(512,
3105 buffers_.capacity() - buffers_.size()),
3106 std::min<std::size_t>(65536,
3107 buffers_.max_size() - buffers_.size()));
7c673cae
FG
3108 }
3109 }
3110
3111 // Check if we're done.
92f5a8d4 3112 if (!start && bytes_to_read_ == 0)
7c673cae
FG
3113 break;
3114
20effc67 3115 // Start a new asynchronous read operation to obtain more data.
92f5a8d4
TL
3116 pos = buffers_.size();
3117 buffers_.grow(bytes_to_read_);
20effc67
TL
3118 {
3119 BOOST_ASIO_HANDLER_LOCATION((
3120 __FILE__, __LINE__, "async_read_until"));
3121 stream_.async_read_some(buffers_.data(pos, bytes_to_read_),
3122 BOOST_ASIO_MOVE_CAST(read_until_match_op_v2)(*this));
3123 }
7c673cae 3124 return; default:
92f5a8d4 3125 buffers_.shrink(bytes_to_read_ - bytes_transferred);
7c673cae
FG
3126 if (ec || bytes_transferred == 0)
3127 break;
1e59de90
TL
3128 if (this->cancelled() != cancellation_type::none)
3129 {
3130 ec = error::operation_aborted;
3131 break;
3132 }
7c673cae
FG
3133 }
3134
3135 const boost::system::error_code result_ec =
3136 (search_position_ == not_found)
3137 ? error::not_found : ec;
3138
3139 const std::size_t result_n =
3140 (ec || search_position_ == not_found)
3141 ? 0 : search_position_;
3142
1e59de90 3143 BOOST_ASIO_MOVE_OR_LVALUE(ReadHandler)(handler_)(result_ec, result_n);
7c673cae
FG
3144 }
3145 }
3146
3147 //private:
3148 AsyncReadStream& stream_;
92f5a8d4 3149 DynamicBuffer_v2 buffers_;
7c673cae
FG
3150 MatchCondition match_condition_;
3151 int start_;
3152 std::size_t search_position_;
92f5a8d4 3153 std::size_t bytes_to_read_;
7c673cae
FG
3154 ReadHandler handler_;
3155 };
3156
92f5a8d4 3157 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae 3158 typename MatchCondition, typename ReadHandler>
20effc67
TL
3159 inline asio_handler_allocate_is_deprecated
3160 asio_handler_allocate(std::size_t size,
92f5a8d4 3161 read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
b32b8144 3162 MatchCondition, ReadHandler>* this_handler)
7c673cae 3163 {
20effc67
TL
3164#if defined(BOOST_ASIO_NO_DEPRECATED)
3165 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
3166 return asio_handler_allocate_is_no_longer_used();
3167#else // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
3168 return boost_asio_handler_alloc_helpers::allocate(
3169 size, this_handler->handler_);
20effc67 3170#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
3171 }
3172
92f5a8d4 3173 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae 3174 typename MatchCondition, typename ReadHandler>
20effc67
TL
3175 inline asio_handler_deallocate_is_deprecated
3176 asio_handler_deallocate(void* pointer, std::size_t size,
92f5a8d4 3177 read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
b32b8144 3178 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
3179 {
3180 boost_asio_handler_alloc_helpers::deallocate(
3181 pointer, size, this_handler->handler_);
20effc67
TL
3182#if defined(BOOST_ASIO_NO_DEPRECATED)
3183 return asio_handler_deallocate_is_no_longer_used();
3184#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
3185 }
3186
92f5a8d4 3187 template <typename AsyncReadStream, typename DynamicBuffer_v2,
7c673cae
FG
3188 typename MatchCondition, typename ReadHandler>
3189 inline bool asio_handler_is_continuation(
92f5a8d4 3190 read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
b32b8144 3191 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
3192 {
3193 return this_handler->start_ == 0 ? true
3194 : boost_asio_handler_cont_helpers::is_continuation(
3195 this_handler->handler_);
3196 }
3197
b32b8144 3198 template <typename Function, typename AsyncReadStream,
92f5a8d4 3199 typename DynamicBuffer_v2, typename MatchCondition,
b32b8144 3200 typename ReadHandler>
20effc67
TL
3201 inline asio_handler_invoke_is_deprecated
3202 asio_handler_invoke(Function& function,
92f5a8d4 3203 read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
b32b8144 3204 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
3205 {
3206 boost_asio_handler_invoke_helpers::invoke(
3207 function, this_handler->handler_);
20effc67
TL
3208#if defined(BOOST_ASIO_NO_DEPRECATED)
3209 return asio_handler_invoke_is_no_longer_used();
3210#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae
FG
3211 }
3212
b32b8144 3213 template <typename Function, typename AsyncReadStream,
92f5a8d4 3214 typename DynamicBuffer_v2, typename MatchCondition,
b32b8144 3215 typename ReadHandler>
20effc67
TL
3216 inline asio_handler_invoke_is_deprecated
3217 asio_handler_invoke(const Function& function,
92f5a8d4 3218 read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,
b32b8144 3219 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
3220 {
3221 boost_asio_handler_invoke_helpers::invoke(
3222 function, this_handler->handler_);
20effc67
TL
3223#if defined(BOOST_ASIO_NO_DEPRECATED)
3224 return asio_handler_invoke_is_no_longer_used();
3225#endif // defined(BOOST_ASIO_NO_DEPRECATED)
7c673cae 3226 }
92f5a8d4
TL
3227
3228 template <typename AsyncReadStream>
3229 class initiate_async_read_until_match_v2
3230 {
3231 public:
3232 typedef typename AsyncReadStream::executor_type executor_type;
3233
3234 explicit initiate_async_read_until_match_v2(AsyncReadStream& stream)
3235 : stream_(stream)
3236 {
3237 }
3238
3239 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
3240 {
3241 return stream_.get_executor();
3242 }
3243
3244 template <typename ReadHandler,
3245 typename DynamicBuffer_v2, typename MatchCondition>
3246 void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
3247 BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,
3248 MatchCondition match_condition) const
3249 {
3250 // If you get an error on the following line it means that your handler
3251 // does not meet the documented type requirements for a ReadHandler.
3252 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
3253
3254 non_const_lvalue<ReadHandler> handler2(handler);
3255 read_until_match_op_v2<AsyncReadStream,
3256 typename decay<DynamicBuffer_v2>::type,
3257 MatchCondition, typename decay<ReadHandler>::type>(
3258 stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),
3259 match_condition, handler2.value)(boost::system::error_code(), 0, 1);
3260 }
3261
3262 private:
3263 AsyncReadStream& stream_;
3264 };
7c673cae
FG
3265} // namespace detail
3266
b32b8144
FG
3267#if !defined(GENERATING_DOCUMENTATION)
3268
1e59de90
TL
3269template <template <typename, typename> class Associator,
3270 typename AsyncReadStream, typename DynamicBuffer_v2,
3271 typename MatchCondition, typename ReadHandler, typename DefaultCandidate>
3272struct associator<Associator,
92f5a8d4
TL
3273 detail::read_until_match_op_v2<AsyncReadStream,
3274 DynamicBuffer_v2, MatchCondition, ReadHandler>,
1e59de90
TL
3275 DefaultCandidate>
3276 : Associator<ReadHandler, DefaultCandidate>
b32b8144 3277{
1e59de90 3278 static typename Associator<ReadHandler, DefaultCandidate>::type get(
92f5a8d4
TL
3279 const detail::read_until_match_op_v2<AsyncReadStream,
3280 DynamicBuffer_v2, MatchCondition, ReadHandler>& h,
1e59de90 3281 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
b32b8144 3282 {
1e59de90 3283 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
b32b8144
FG
3284 }
3285};
3286
3287#endif // !defined(GENERATING_DOCUMENTATION)
3288
92f5a8d4
TL
3289template <typename AsyncReadStream,
3290 typename DynamicBuffer_v2, typename MatchCondition,
3291 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
1e59de90
TL
3292 std::size_t)) ReadToken>
3293BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
b32b8144 3294 void (boost::system::error_code, std::size_t))
92f5a8d4 3295async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,
1e59de90
TL
3296 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadToken) token,
3297 typename constraint<
92f5a8d4 3298 is_match_condition<MatchCondition>::value
1e59de90
TL
3299 >::type,
3300 typename constraint<
3301 is_dynamic_buffer_v2<DynamicBuffer_v2>::value
3302 >::type)
b32b8144 3303{
1e59de90 3304 return async_initiate<ReadToken,
92f5a8d4 3305 void (boost::system::error_code, std::size_t)>(
1e59de90 3306 detail::initiate_async_read_until_match_v2<AsyncReadStream>(s), token,
92f5a8d4 3307 BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition);
b32b8144
FG
3308}
3309
b32b8144
FG
3310#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
3311
7c673cae
FG
3312} // namespace asio
3313} // namespace boost
3314
3315#include <boost/asio/detail/pop_options.hpp>
3316
3317#endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP