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