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