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