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