]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/asio/impl/read_until.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / asio / impl / read_until.hpp
1 //
2 // impl/read_until.hpp
3 // ~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 #ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
12 #define BOOST_ASIO_IMPL_READ_UNTIL_HPP
13
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21 #include <utility>
22 #include <boost/asio/associated_allocator.hpp>
23 #include <boost/asio/associated_executor.hpp>
24 #include <boost/asio/buffer.hpp>
25 #include <boost/asio/buffers_iterator.hpp>
26 #include <boost/asio/detail/bind_handler.hpp>
27 #include <boost/asio/detail/handler_alloc_helpers.hpp>
28 #include <boost/asio/detail/handler_cont_helpers.hpp>
29 #include <boost/asio/detail/handler_invoke_helpers.hpp>
30 #include <boost/asio/detail/handler_type_requirements.hpp>
31 #include <boost/asio/detail/limits.hpp>
32 #include <boost/asio/detail/throw_error.hpp>
33
34 #include <boost/asio/detail/push_options.hpp>
35
36 namespace boost {
37 namespace asio {
38
39 template <typename SyncReadStream, typename DynamicBuffer>
40 inline std::size_t read_until(SyncReadStream& s,
41 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim)
42 {
43 boost::system::error_code ec;
44 std::size_t bytes_transferred = read_until(s,
45 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec);
46 boost::asio::detail::throw_error(ec, "read_until");
47 return bytes_transferred;
48 }
49
50 template <typename SyncReadStream, typename DynamicBuffer>
51 std::size_t read_until(SyncReadStream& s,
52 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
53 char delim, boost::system::error_code& ec)
54 {
55 typename decay<DynamicBuffer>::type b(
56 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
57
58 std::size_t search_position = 0;
59 for (;;)
60 {
61 // Determine the range of the data to be searched.
62 typedef typename DynamicBuffer::const_buffers_type buffers_type;
63 typedef buffers_iterator<buffers_type> iterator;
64 buffers_type data_buffers = b.data();
65 iterator begin = iterator::begin(data_buffers);
66 iterator start_pos = begin + search_position;
67 iterator end = iterator::end(data_buffers);
68
69 // Look for a match.
70 iterator iter = std::find(start_pos, end, delim);
71 if (iter != end)
72 {
73 // Found a match. We're done.
74 ec = boost::system::error_code();
75 return iter - begin + 1;
76 }
77 else
78 {
79 // No match. Next search can start with the new data.
80 search_position = end - begin;
81 }
82
83 // Check if buffer is full.
84 if (b.size() == b.max_size())
85 {
86 ec = error::not_found;
87 return 0;
88 }
89
90 // Need more data.
91 std::size_t bytes_to_read = std::min<std::size_t>(
92 std::max<std::size_t>(512, b.capacity() - b.size()),
93 std::min<std::size_t>(65536, b.max_size() - b.size()));
94 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
95 if (ec)
96 return 0;
97 }
98 }
99
100 template <typename SyncReadStream, typename DynamicBuffer>
101 inline std::size_t read_until(SyncReadStream& s,
102 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
103 BOOST_ASIO_STRING_VIEW_PARAM delim)
104 {
105 boost::system::error_code ec;
106 std::size_t bytes_transferred = read_until(s,
107 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec);
108 boost::asio::detail::throw_error(ec, "read_until");
109 return bytes_transferred;
110 }
111
112 namespace detail
113 {
114 // Algorithm that finds a subsequence of equal values in a sequence. Returns
115 // (iterator,true) if a full match was found, in which case the iterator
116 // points to the beginning of the match. Returns (iterator,false) if a
117 // partial match was found at the end of the first sequence, in which case
118 // the iterator points to the beginning of the partial match. Returns
119 // (last1,false) if no full or partial match was found.
120 template <typename Iterator1, typename Iterator2>
121 std::pair<Iterator1, bool> partial_search(
122 Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
123 {
124 for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)
125 {
126 Iterator1 test_iter1 = iter1;
127 Iterator2 test_iter2 = first2;
128 for (;; ++test_iter1, ++test_iter2)
129 {
130 if (test_iter2 == last2)
131 return std::make_pair(iter1, true);
132 if (test_iter1 == last1)
133 {
134 if (test_iter2 != first2)
135 return std::make_pair(iter1, false);
136 else
137 break;
138 }
139 if (*test_iter1 != *test_iter2)
140 break;
141 }
142 }
143 return std::make_pair(last1, false);
144 }
145 } // namespace detail
146
147 template <typename SyncReadStream, typename DynamicBuffer>
148 std::size_t read_until(SyncReadStream& s,
149 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
150 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec)
151 {
152 typename decay<DynamicBuffer>::type b(
153 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
154
155 std::size_t search_position = 0;
156 for (;;)
157 {
158 // Determine the range of the data to be searched.
159 typedef typename DynamicBuffer::const_buffers_type buffers_type;
160 typedef buffers_iterator<buffers_type> iterator;
161 buffers_type data_buffers = b.data();
162 iterator begin = iterator::begin(data_buffers);
163 iterator start_pos = begin + search_position;
164 iterator end = iterator::end(data_buffers);
165
166 // Look for a match.
167 std::pair<iterator, bool> result = detail::partial_search(
168 start_pos, end, delim.begin(), delim.end());
169 if (result.first != end)
170 {
171 if (result.second)
172 {
173 // Full match. We're done.
174 ec = boost::system::error_code();
175 return result.first - begin + delim.length();
176 }
177 else
178 {
179 // Partial match. Next search needs to start from beginning of match.
180 search_position = result.first - begin;
181 }
182 }
183 else
184 {
185 // No match. Next search can start with the new data.
186 search_position = end - begin;
187 }
188
189 // Check if buffer is full.
190 if (b.size() == b.max_size())
191 {
192 ec = error::not_found;
193 return 0;
194 }
195
196 // Need more data.
197 std::size_t bytes_to_read = std::min<std::size_t>(
198 std::max<std::size_t>(512, b.capacity() - b.size()),
199 std::min<std::size_t>(65536, b.max_size() - b.size()));
200 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
201 if (ec)
202 return 0;
203 }
204 }
205
206 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
207 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
208
209 template <typename SyncReadStream, typename DynamicBuffer>
210 inline std::size_t read_until(SyncReadStream& s,
211 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
212 const boost::regex& expr)
213 {
214 boost::system::error_code ec;
215 std::size_t bytes_transferred = read_until(s,
216 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), expr, ec);
217 boost::asio::detail::throw_error(ec, "read_until");
218 return bytes_transferred;
219 }
220
221 template <typename SyncReadStream, typename DynamicBuffer>
222 std::size_t read_until(SyncReadStream& s,
223 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
224 const boost::regex& expr, boost::system::error_code& ec)
225 {
226 typename decay<DynamicBuffer>::type b(
227 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
228
229 std::size_t search_position = 0;
230 for (;;)
231 {
232 // Determine the range of the data to be searched.
233 typedef typename DynamicBuffer::const_buffers_type buffers_type;
234 typedef buffers_iterator<buffers_type> iterator;
235 buffers_type data_buffers = b.data();
236 iterator begin = iterator::begin(data_buffers);
237 iterator start_pos = begin + search_position;
238 iterator end = iterator::end(data_buffers);
239
240 // Look for a match.
241 boost::match_results<iterator,
242 typename std::vector<boost::sub_match<iterator> >::allocator_type>
243 match_results;
244 if (regex_search(start_pos, end, match_results, expr,
245 boost::match_default | boost::match_partial))
246 {
247 if (match_results[0].matched)
248 {
249 // Full match. We're done.
250 ec = boost::system::error_code();
251 return match_results[0].second - begin;
252 }
253 else
254 {
255 // Partial match. Next search needs to start from beginning of match.
256 search_position = match_results[0].first - begin;
257 }
258 }
259 else
260 {
261 // No match. Next search can start with the new data.
262 search_position = end - begin;
263 }
264
265 // Check if buffer is full.
266 if (b.size() == b.max_size())
267 {
268 ec = error::not_found;
269 return 0;
270 }
271
272 // Need more data.
273 std::size_t bytes_to_read = read_size_helper(b, 65536);
274 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
275 if (ec)
276 return 0;
277 }
278 }
279
280 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
281
282 template <typename SyncReadStream,
283 typename DynamicBuffer, typename MatchCondition>
284 inline std::size_t read_until(SyncReadStream& s,
285 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
286 MatchCondition match_condition,
287 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
288 {
289 boost::system::error_code ec;
290 std::size_t bytes_transferred = read_until(s,
291 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
292 match_condition, ec);
293 boost::asio::detail::throw_error(ec, "read_until");
294 return bytes_transferred;
295 }
296
297 template <typename SyncReadStream,
298 typename DynamicBuffer, typename MatchCondition>
299 std::size_t read_until(SyncReadStream& s,
300 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
301 MatchCondition match_condition, boost::system::error_code& ec,
302 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
303 {
304 typename decay<DynamicBuffer>::type b(
305 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
306
307 std::size_t search_position = 0;
308 for (;;)
309 {
310 // Determine the range of the data to be searched.
311 typedef typename DynamicBuffer::const_buffers_type buffers_type;
312 typedef buffers_iterator<buffers_type> iterator;
313 buffers_type data_buffers = b.data();
314 iterator begin = iterator::begin(data_buffers);
315 iterator start_pos = begin + search_position;
316 iterator end = iterator::end(data_buffers);
317
318 // Look for a match.
319 std::pair<iterator, bool> result = match_condition(start_pos, end);
320 if (result.second)
321 {
322 // Full match. We're done.
323 ec = boost::system::error_code();
324 return result.first - begin;
325 }
326 else if (result.first != end)
327 {
328 // Partial match. Next search needs to start from beginning of match.
329 search_position = result.first - begin;
330 }
331 else
332 {
333 // No match. Next search can start with the new data.
334 search_position = end - begin;
335 }
336
337 // Check if buffer is full.
338 if (b.size() == b.max_size())
339 {
340 ec = error::not_found;
341 return 0;
342 }
343
344 // Need more data.
345 std::size_t bytes_to_read = std::min<std::size_t>(
346 std::max<std::size_t>(512, b.capacity() - b.size()),
347 std::min<std::size_t>(65536, b.max_size() - b.size()));
348 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
349 if (ec)
350 return 0;
351 }
352 }
353
354 #if !defined(BOOST_ASIO_NO_IOSTREAM)
355
356 template <typename SyncReadStream, typename Allocator>
357 inline std::size_t read_until(SyncReadStream& s,
358 boost::asio::basic_streambuf<Allocator>& b, char delim)
359 {
360 return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
361 }
362
363 template <typename SyncReadStream, typename Allocator>
364 inline std::size_t read_until(SyncReadStream& s,
365 boost::asio::basic_streambuf<Allocator>& b, char delim,
366 boost::system::error_code& ec)
367 {
368 return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
369 }
370
371 template <typename SyncReadStream, typename Allocator>
372 inline std::size_t read_until(SyncReadStream& s,
373 boost::asio::basic_streambuf<Allocator>& b,
374 BOOST_ASIO_STRING_VIEW_PARAM delim)
375 {
376 return read_until(s, basic_streambuf_ref<Allocator>(b), delim);
377 }
378
379 template <typename SyncReadStream, typename Allocator>
380 inline std::size_t read_until(SyncReadStream& s,
381 boost::asio::basic_streambuf<Allocator>& b,
382 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec)
383 {
384 return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);
385 }
386
387 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
388
389 template <typename SyncReadStream, typename Allocator>
390 inline std::size_t read_until(SyncReadStream& s,
391 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr)
392 {
393 return read_until(s, basic_streambuf_ref<Allocator>(b), expr);
394 }
395
396 template <typename SyncReadStream, typename Allocator>
397 inline std::size_t read_until(SyncReadStream& s,
398 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
399 boost::system::error_code& ec)
400 {
401 return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec);
402 }
403
404 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
405
406 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
407 inline std::size_t read_until(SyncReadStream& s,
408 boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,
409 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
410 {
411 return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition);
412 }
413
414 template <typename SyncReadStream, typename Allocator, typename MatchCondition>
415 inline std::size_t read_until(SyncReadStream& s,
416 boost::asio::basic_streambuf<Allocator>& b,
417 MatchCondition match_condition, boost::system::error_code& ec,
418 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
419 {
420 return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec);
421 }
422
423 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
424 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
425
426 namespace detail
427 {
428 template <typename AsyncReadStream,
429 typename DynamicBuffer, typename ReadHandler>
430 class read_until_delim_op
431 {
432 public:
433 template <typename BufferSequence>
434 read_until_delim_op(AsyncReadStream& stream,
435 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
436 char delim, ReadHandler& handler)
437 : stream_(stream),
438 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
439 delim_(delim),
440 start_(0),
441 search_position_(0),
442 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
443 {
444 }
445
446 #if defined(BOOST_ASIO_HAS_MOVE)
447 read_until_delim_op(const read_until_delim_op& other)
448 : stream_(other.stream_),
449 buffers_(other.buffers_),
450 delim_(other.delim_),
451 start_(other.start_),
452 search_position_(other.search_position_),
453 handler_(other.handler_)
454 {
455 }
456
457 read_until_delim_op(read_until_delim_op&& other)
458 : stream_(other.stream_),
459 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
460 delim_(other.delim_),
461 start_(other.start_),
462 search_position_(other.search_position_),
463 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
464 {
465 }
466 #endif // defined(BOOST_ASIO_HAS_MOVE)
467
468 void operator()(const boost::system::error_code& ec,
469 std::size_t bytes_transferred, int start = 0)
470 {
471 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
472 std::size_t bytes_to_read;
473 switch (start_ = start)
474 {
475 case 1:
476 for (;;)
477 {
478 {
479 // Determine the range of the data to be searched.
480 typedef typename DynamicBuffer::const_buffers_type
481 buffers_type;
482 typedef buffers_iterator<buffers_type> iterator;
483 buffers_type data_buffers = buffers_.data();
484 iterator begin = iterator::begin(data_buffers);
485 iterator start_pos = begin + search_position_;
486 iterator end = iterator::end(data_buffers);
487
488 // Look for a match.
489 iterator iter = std::find(start_pos, end, delim_);
490 if (iter != end)
491 {
492 // Found a match. We're done.
493 search_position_ = iter - begin + 1;
494 bytes_to_read = 0;
495 }
496
497 // No match yet. Check if buffer is full.
498 else if (buffers_.size() == buffers_.max_size())
499 {
500 search_position_ = not_found;
501 bytes_to_read = 0;
502 }
503
504 // Need to read some more data.
505 else
506 {
507 // Next search can start with the new data.
508 search_position_ = end - begin;
509 bytes_to_read = std::min<std::size_t>(
510 std::max<std::size_t>(512,
511 buffers_.capacity() - buffers_.size()),
512 std::min<std::size_t>(65536,
513 buffers_.max_size() - buffers_.size()));
514 }
515 }
516
517 // Check if we're done.
518 if (!start && bytes_to_read == 0)
519 break;
520
521 // Start a new asynchronous read operation to obtain more data.
522 stream_.async_read_some(buffers_.prepare(bytes_to_read),
523 BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this));
524 return; default:
525 buffers_.commit(bytes_transferred);
526 if (ec || bytes_transferred == 0)
527 break;
528 }
529
530 const boost::system::error_code result_ec =
531 (search_position_ == not_found)
532 ? error::not_found : ec;
533
534 const std::size_t result_n =
535 (ec || search_position_ == not_found)
536 ? 0 : search_position_;
537
538 handler_(result_ec, result_n);
539 }
540 }
541
542 //private:
543 AsyncReadStream& stream_;
544 DynamicBuffer buffers_;
545 char delim_;
546 int start_;
547 std::size_t search_position_;
548 ReadHandler handler_;
549 };
550
551 template <typename AsyncReadStream,
552 typename DynamicBuffer, typename ReadHandler>
553 inline void* asio_handler_allocate(std::size_t size,
554 read_until_delim_op<AsyncReadStream,
555 DynamicBuffer, ReadHandler>* this_handler)
556 {
557 return boost_asio_handler_alloc_helpers::allocate(
558 size, this_handler->handler_);
559 }
560
561 template <typename AsyncReadStream,
562 typename DynamicBuffer, typename ReadHandler>
563 inline void asio_handler_deallocate(void* pointer, std::size_t size,
564 read_until_delim_op<AsyncReadStream,
565 DynamicBuffer, ReadHandler>* this_handler)
566 {
567 boost_asio_handler_alloc_helpers::deallocate(
568 pointer, size, this_handler->handler_);
569 }
570
571 template <typename AsyncReadStream,
572 typename DynamicBuffer, typename ReadHandler>
573 inline bool asio_handler_is_continuation(
574 read_until_delim_op<AsyncReadStream,
575 DynamicBuffer, ReadHandler>* this_handler)
576 {
577 return this_handler->start_ == 0 ? true
578 : boost_asio_handler_cont_helpers::is_continuation(
579 this_handler->handler_);
580 }
581
582 template <typename Function, typename AsyncReadStream,
583 typename DynamicBuffer, typename ReadHandler>
584 inline void asio_handler_invoke(Function& function,
585 read_until_delim_op<AsyncReadStream,
586 DynamicBuffer, ReadHandler>* this_handler)
587 {
588 boost_asio_handler_invoke_helpers::invoke(
589 function, this_handler->handler_);
590 }
591
592 template <typename Function, typename AsyncReadStream,
593 typename DynamicBuffer, typename ReadHandler>
594 inline void asio_handler_invoke(const Function& function,
595 read_until_delim_op<AsyncReadStream,
596 DynamicBuffer, ReadHandler>* this_handler)
597 {
598 boost_asio_handler_invoke_helpers::invoke(
599 function, this_handler->handler_);
600 }
601 } // namespace detail
602
603 #if !defined(GENERATING_DOCUMENTATION)
604
605 template <typename AsyncReadStream, typename DynamicBuffer,
606 typename ReadHandler, typename Allocator>
607 struct associated_allocator<
608 detail::read_until_delim_op<AsyncReadStream,
609 DynamicBuffer, ReadHandler>,
610 Allocator>
611 {
612 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
613
614 static type get(
615 const detail::read_until_delim_op<AsyncReadStream,
616 DynamicBuffer, ReadHandler>& h,
617 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
618 {
619 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
620 }
621 };
622
623 template <typename AsyncReadStream, typename DynamicBuffer,
624 typename ReadHandler, typename Executor>
625 struct associated_executor<
626 detail::read_until_delim_op<AsyncReadStream,
627 DynamicBuffer, ReadHandler>,
628 Executor>
629 {
630 typedef typename associated_executor<ReadHandler, Executor>::type type;
631
632 static type get(
633 const detail::read_until_delim_op<AsyncReadStream,
634 DynamicBuffer, ReadHandler>& h,
635 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
636 {
637 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
638 }
639 };
640
641 #endif // !defined(GENERATING_DOCUMENTATION)
642
643 template <typename AsyncReadStream,
644 typename DynamicBuffer, typename ReadHandler>
645 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
646 void (boost::system::error_code, std::size_t))
647 async_read_until(AsyncReadStream& s,
648 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
649 char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
650 {
651 // If you get an error on the following line it means that your handler does
652 // not meet the documented type requirements for a ReadHandler.
653 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
654
655 async_completion<ReadHandler,
656 void (boost::system::error_code, std::size_t)> init(handler);
657
658 detail::read_until_delim_op<AsyncReadStream,
659 typename decay<DynamicBuffer>::type,
660 BOOST_ASIO_HANDLER_TYPE(ReadHandler,
661 void (boost::system::error_code, std::size_t))>(
662 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
663 delim, init.completion_handler)(boost::system::error_code(), 0, 1);
664
665 return init.result.get();
666 }
667
668 namespace detail
669 {
670 template <typename AsyncReadStream,
671 typename DynamicBuffer, typename ReadHandler>
672 class read_until_delim_string_op
673 {
674 public:
675 template <typename BufferSequence>
676 read_until_delim_string_op(AsyncReadStream& stream,
677 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
678 const std::string& delim, ReadHandler& handler)
679 : stream_(stream),
680 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
681 delim_(delim),
682 start_(0),
683 search_position_(0),
684 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
685 {
686 }
687
688 #if defined(BOOST_ASIO_HAS_MOVE)
689 read_until_delim_string_op(const read_until_delim_string_op& other)
690 : stream_(other.stream_),
691 buffers_(other.buffers_),
692 delim_(other.delim_),
693 start_(other.start_),
694 search_position_(other.search_position_),
695 handler_(other.handler_)
696 {
697 }
698
699 read_until_delim_string_op(read_until_delim_string_op&& other)
700 : stream_(other.stream_),
701 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
702 delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)),
703 start_(other.start_),
704 search_position_(other.search_position_),
705 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
706 {
707 }
708 #endif // defined(BOOST_ASIO_HAS_MOVE)
709
710 void operator()(const boost::system::error_code& ec,
711 std::size_t bytes_transferred, int start = 0)
712 {
713 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
714 std::size_t bytes_to_read;
715 switch (start_ = start)
716 {
717 case 1:
718 for (;;)
719 {
720 {
721 // Determine the range of the data to be searched.
722 typedef typename DynamicBuffer::const_buffers_type
723 buffers_type;
724 typedef buffers_iterator<buffers_type> iterator;
725 buffers_type data_buffers = buffers_.data();
726 iterator begin = iterator::begin(data_buffers);
727 iterator start_pos = begin + search_position_;
728 iterator end = iterator::end(data_buffers);
729
730 // Look for a match.
731 std::pair<iterator, bool> result = detail::partial_search(
732 start_pos, end, delim_.begin(), delim_.end());
733 if (result.first != end && result.second)
734 {
735 // Full match. We're done.
736 search_position_ = result.first - begin + delim_.length();
737 bytes_to_read = 0;
738 }
739
740 // No match yet. Check if buffer is full.
741 else if (buffers_.size() == buffers_.max_size())
742 {
743 search_position_ = not_found;
744 bytes_to_read = 0;
745 }
746
747 // Need to read some more data.
748 else
749 {
750 if (result.first != end)
751 {
752 // Partial match. Next search needs to start from beginning of
753 // match.
754 search_position_ = result.first - begin;
755 }
756 else
757 {
758 // Next search can start with the new data.
759 search_position_ = end - begin;
760 }
761
762 bytes_to_read = std::min<std::size_t>(
763 std::max<std::size_t>(512,
764 buffers_.capacity() - buffers_.size()),
765 std::min<std::size_t>(65536,
766 buffers_.max_size() - buffers_.size()));
767 }
768 }
769
770 // Check if we're done.
771 if (!start && bytes_to_read == 0)
772 break;
773
774 // Start a new asynchronous read operation to obtain more data.
775 stream_.async_read_some(buffers_.prepare(bytes_to_read),
776 BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this));
777 return; default:
778 buffers_.commit(bytes_transferred);
779 if (ec || bytes_transferred == 0)
780 break;
781 }
782
783 const boost::system::error_code result_ec =
784 (search_position_ == not_found)
785 ? error::not_found : ec;
786
787 const std::size_t result_n =
788 (ec || search_position_ == not_found)
789 ? 0 : search_position_;
790
791 handler_(result_ec, result_n);
792 }
793 }
794
795 //private:
796 AsyncReadStream& stream_;
797 DynamicBuffer buffers_;
798 std::string delim_;
799 int start_;
800 std::size_t search_position_;
801 ReadHandler handler_;
802 };
803
804 template <typename AsyncReadStream,
805 typename DynamicBuffer, typename ReadHandler>
806 inline void* asio_handler_allocate(std::size_t size,
807 read_until_delim_string_op<AsyncReadStream,
808 DynamicBuffer, ReadHandler>* this_handler)
809 {
810 return boost_asio_handler_alloc_helpers::allocate(
811 size, this_handler->handler_);
812 }
813
814 template <typename AsyncReadStream,
815 typename DynamicBuffer, typename ReadHandler>
816 inline void asio_handler_deallocate(void* pointer, std::size_t size,
817 read_until_delim_string_op<AsyncReadStream,
818 DynamicBuffer, ReadHandler>* this_handler)
819 {
820 boost_asio_handler_alloc_helpers::deallocate(
821 pointer, size, this_handler->handler_);
822 }
823
824 template <typename AsyncReadStream,
825 typename DynamicBuffer, typename ReadHandler>
826 inline bool asio_handler_is_continuation(
827 read_until_delim_string_op<AsyncReadStream,
828 DynamicBuffer, ReadHandler>* this_handler)
829 {
830 return this_handler->start_ == 0 ? true
831 : boost_asio_handler_cont_helpers::is_continuation(
832 this_handler->handler_);
833 }
834
835 template <typename Function, typename AsyncReadStream,
836 typename DynamicBuffer, typename ReadHandler>
837 inline void asio_handler_invoke(Function& function,
838 read_until_delim_string_op<AsyncReadStream,
839 DynamicBuffer, ReadHandler>* this_handler)
840 {
841 boost_asio_handler_invoke_helpers::invoke(
842 function, this_handler->handler_);
843 }
844
845 template <typename Function, typename AsyncReadStream,
846 typename DynamicBuffer, typename ReadHandler>
847 inline void asio_handler_invoke(const Function& function,
848 read_until_delim_string_op<AsyncReadStream,
849 DynamicBuffer, ReadHandler>* this_handler)
850 {
851 boost_asio_handler_invoke_helpers::invoke(
852 function, this_handler->handler_);
853 }
854 } // namespace detail
855
856 #if !defined(GENERATING_DOCUMENTATION)
857
858 template <typename AsyncReadStream, typename DynamicBuffer,
859 typename ReadHandler, typename Allocator>
860 struct associated_allocator<
861 detail::read_until_delim_string_op<AsyncReadStream,
862 DynamicBuffer, ReadHandler>,
863 Allocator>
864 {
865 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
866
867 static type get(
868 const detail::read_until_delim_string_op<AsyncReadStream,
869 DynamicBuffer, ReadHandler>& h,
870 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
871 {
872 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
873 }
874 };
875
876 template <typename AsyncReadStream, typename DynamicBuffer,
877 typename ReadHandler, typename Executor>
878 struct associated_executor<
879 detail::read_until_delim_string_op<AsyncReadStream,
880 DynamicBuffer, ReadHandler>,
881 Executor>
882 {
883 typedef typename associated_executor<ReadHandler, Executor>::type type;
884
885 static type get(
886 const detail::read_until_delim_string_op<AsyncReadStream,
887 DynamicBuffer, ReadHandler>& h,
888 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
889 {
890 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
891 }
892 };
893
894 #endif // !defined(GENERATING_DOCUMENTATION)
895
896 template <typename AsyncReadStream,
897 typename DynamicBuffer, typename ReadHandler>
898 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
899 void (boost::system::error_code, std::size_t))
900 async_read_until(AsyncReadStream& s,
901 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
902 BOOST_ASIO_STRING_VIEW_PARAM delim,
903 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
904 {
905 // If you get an error on the following line it means that your handler does
906 // not meet the documented type requirements for a ReadHandler.
907 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
908
909 async_completion<ReadHandler,
910 void (boost::system::error_code, std::size_t)> init(handler);
911
912 detail::read_until_delim_string_op<AsyncReadStream,
913 typename decay<DynamicBuffer>::type,
914 BOOST_ASIO_HANDLER_TYPE(ReadHandler,
915 void (boost::system::error_code, std::size_t))>(
916 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
917 static_cast<std::string>(delim),
918 init.completion_handler)(boost::system::error_code(), 0, 1);
919
920 return init.result.get();
921 }
922
923 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
924 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
925
926 namespace detail
927 {
928 template <typename AsyncReadStream, typename DynamicBuffer,
929 typename RegEx, typename ReadHandler>
930 class read_until_expr_op
931 {
932 public:
933 template <typename BufferSequence>
934 read_until_expr_op(AsyncReadStream& stream,
935 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
936 const boost::regex& expr, ReadHandler& handler)
937 : stream_(stream),
938 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
939 expr_(expr),
940 start_(0),
941 search_position_(0),
942 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
943 {
944 }
945
946 #if defined(BOOST_ASIO_HAS_MOVE)
947 read_until_expr_op(const read_until_expr_op& other)
948 : stream_(other.stream_),
949 buffers_(other.buffers_),
950 expr_(other.expr_),
951 start_(other.start_),
952 search_position_(other.search_position_),
953 handler_(other.handler_)
954 {
955 }
956
957 read_until_expr_op(read_until_expr_op&& other)
958 : stream_(other.stream_),
959 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
960 expr_(other.expr_),
961 start_(other.start_),
962 search_position_(other.search_position_),
963 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
964 {
965 }
966 #endif // defined(BOOST_ASIO_HAS_MOVE)
967
968 void operator()(const boost::system::error_code& ec,
969 std::size_t bytes_transferred, int start = 0)
970 {
971 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
972 std::size_t bytes_to_read;
973 switch (start_ = start)
974 {
975 case 1:
976 for (;;)
977 {
978 {
979 // Determine the range of the data to be searched.
980 typedef typename DynamicBuffer::const_buffers_type
981 buffers_type;
982 typedef buffers_iterator<buffers_type> iterator;
983 buffers_type data_buffers = buffers_.data();
984 iterator begin = iterator::begin(data_buffers);
985 iterator start_pos = begin + search_position_;
986 iterator end = iterator::end(data_buffers);
987
988 // Look for a match.
989 boost::match_results<iterator,
990 typename std::vector<boost::sub_match<iterator> >::allocator_type>
991 match_results;
992 bool match = regex_search(start_pos, end, match_results, expr_,
993 boost::match_default | boost::match_partial);
994 if (match && match_results[0].matched)
995 {
996 // Full match. We're done.
997 search_position_ = match_results[0].second - begin;
998 bytes_to_read = 0;
999 }
1000
1001 // No match yet. Check if buffer is full.
1002 else if (buffers_.size() == buffers_.max_size())
1003 {
1004 search_position_ = not_found;
1005 bytes_to_read = 0;
1006 }
1007
1008 // Need to read some more data.
1009 else
1010 {
1011 if (match)
1012 {
1013 // Partial match. Next search needs to start from beginning of
1014 // match.
1015 search_position_ = match_results[0].first - begin;
1016 }
1017 else
1018 {
1019 // Next search can start with the new data.
1020 search_position_ = end - begin;
1021 }
1022
1023 bytes_to_read = std::min<std::size_t>(
1024 std::max<std::size_t>(512,
1025 buffers_.capacity() - buffers_.size()),
1026 std::min<std::size_t>(65536,
1027 buffers_.max_size() - buffers_.size()));
1028 }
1029 }
1030
1031 // Check if we're done.
1032 if (!start && bytes_to_read == 0)
1033 break;
1034
1035 // Start a new asynchronous read operation to obtain more data.
1036 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1037 BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this));
1038 return; default:
1039 buffers_.commit(bytes_transferred);
1040 if (ec || bytes_transferred == 0)
1041 break;
1042 }
1043
1044 const boost::system::error_code result_ec =
1045 (search_position_ == not_found)
1046 ? error::not_found : ec;
1047
1048 const std::size_t result_n =
1049 (ec || search_position_ == not_found)
1050 ? 0 : search_position_;
1051
1052 handler_(result_ec, result_n);
1053 }
1054 }
1055
1056 //private:
1057 AsyncReadStream& stream_;
1058 DynamicBuffer buffers_;
1059 RegEx expr_;
1060 int start_;
1061 std::size_t search_position_;
1062 ReadHandler handler_;
1063 };
1064
1065 template <typename AsyncReadStream, typename DynamicBuffer,
1066 typename RegEx, typename ReadHandler>
1067 inline void* asio_handler_allocate(std::size_t size,
1068 read_until_expr_op<AsyncReadStream,
1069 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1070 {
1071 return boost_asio_handler_alloc_helpers::allocate(
1072 size, this_handler->handler_);
1073 }
1074
1075 template <typename AsyncReadStream, typename DynamicBuffer,
1076 typename RegEx, typename ReadHandler>
1077 inline void asio_handler_deallocate(void* pointer, std::size_t size,
1078 read_until_expr_op<AsyncReadStream,
1079 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1080 {
1081 boost_asio_handler_alloc_helpers::deallocate(
1082 pointer, size, this_handler->handler_);
1083 }
1084
1085 template <typename AsyncReadStream, typename DynamicBuffer,
1086 typename RegEx, typename ReadHandler>
1087 inline bool asio_handler_is_continuation(
1088 read_until_expr_op<AsyncReadStream,
1089 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1090 {
1091 return this_handler->start_ == 0 ? true
1092 : boost_asio_handler_cont_helpers::is_continuation(
1093 this_handler->handler_);
1094 }
1095
1096 template <typename Function, typename AsyncReadStream,
1097 typename DynamicBuffer, typename RegEx, typename ReadHandler>
1098 inline void asio_handler_invoke(Function& function,
1099 read_until_expr_op<AsyncReadStream,
1100 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1101 {
1102 boost_asio_handler_invoke_helpers::invoke(
1103 function, this_handler->handler_);
1104 }
1105
1106 template <typename Function, typename AsyncReadStream,
1107 typename DynamicBuffer, typename RegEx, typename ReadHandler>
1108 inline void asio_handler_invoke(const Function& function,
1109 read_until_expr_op<AsyncReadStream,
1110 DynamicBuffer, RegEx, ReadHandler>* this_handler)
1111 {
1112 boost_asio_handler_invoke_helpers::invoke(
1113 function, this_handler->handler_);
1114 }
1115 } // namespace detail
1116
1117 #if !defined(GENERATING_DOCUMENTATION)
1118
1119 template <typename AsyncReadStream, typename DynamicBuffer,
1120 typename RegEx, typename ReadHandler, typename Allocator>
1121 struct associated_allocator<
1122 detail::read_until_expr_op<AsyncReadStream,
1123 DynamicBuffer, RegEx, ReadHandler>,
1124 Allocator>
1125 {
1126 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
1127
1128 static type get(
1129 const detail::read_until_expr_op<AsyncReadStream,
1130 DynamicBuffer, RegEx, ReadHandler>& h,
1131 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
1132 {
1133 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
1134 }
1135 };
1136
1137 template <typename AsyncReadStream, typename DynamicBuffer,
1138 typename RegEx, typename ReadHandler, typename Executor>
1139 struct associated_executor<
1140 detail::read_until_expr_op<AsyncReadStream,
1141 DynamicBuffer, RegEx, ReadHandler>,
1142 Executor>
1143 {
1144 typedef typename associated_executor<ReadHandler, Executor>::type type;
1145
1146 static type get(
1147 const detail::read_until_expr_op<AsyncReadStream,
1148 DynamicBuffer, RegEx, ReadHandler>& h,
1149 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
1150 {
1151 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
1152 }
1153 };
1154
1155 #endif // !defined(GENERATING_DOCUMENTATION)
1156
1157 template <typename AsyncReadStream,
1158 typename DynamicBuffer, typename ReadHandler>
1159 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1160 void (boost::system::error_code, std::size_t))
1161 async_read_until(AsyncReadStream& s,
1162 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
1163 const boost::regex& expr,
1164 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1165 {
1166 // If you get an error on the following line it means that your handler does
1167 // not meet the documented type requirements for a ReadHandler.
1168 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1169
1170 async_completion<ReadHandler,
1171 void (boost::system::error_code, std::size_t)> init(handler);
1172
1173 detail::read_until_expr_op<AsyncReadStream,
1174 typename decay<DynamicBuffer>::type,
1175 boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
1176 void (boost::system::error_code, std::size_t))>(
1177 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
1178 expr, init.completion_handler)(boost::system::error_code(), 0, 1);
1179
1180 return init.result.get();
1181 }
1182
1183 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1184
1185 namespace detail
1186 {
1187 template <typename AsyncReadStream, typename DynamicBuffer,
1188 typename MatchCondition, typename ReadHandler>
1189 class read_until_match_op
1190 {
1191 public:
1192 template <typename BufferSequence>
1193 read_until_match_op(AsyncReadStream& stream,
1194 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
1195 MatchCondition match_condition, ReadHandler& handler)
1196 : stream_(stream),
1197 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
1198 match_condition_(match_condition),
1199 start_(0),
1200 search_position_(0),
1201 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
1202 {
1203 }
1204
1205 #if defined(BOOST_ASIO_HAS_MOVE)
1206 read_until_match_op(const read_until_match_op& other)
1207 : stream_(other.stream_),
1208 buffers_(other.buffers_),
1209 match_condition_(other.match_condition_),
1210 start_(other.start_),
1211 search_position_(other.search_position_),
1212 handler_(other.handler_)
1213 {
1214 }
1215
1216 read_until_match_op(read_until_match_op&& other)
1217 : stream_(other.stream_),
1218 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
1219 match_condition_(other.match_condition_),
1220 start_(other.start_),
1221 search_position_(other.search_position_),
1222 handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
1223 {
1224 }
1225 #endif // defined(BOOST_ASIO_HAS_MOVE)
1226
1227 void operator()(const boost::system::error_code& ec,
1228 std::size_t bytes_transferred, int start = 0)
1229 {
1230 const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();
1231 std::size_t bytes_to_read;
1232 switch (start_ = start)
1233 {
1234 case 1:
1235 for (;;)
1236 {
1237 {
1238 // Determine the range of the data to be searched.
1239 typedef typename DynamicBuffer::const_buffers_type
1240 buffers_type;
1241 typedef buffers_iterator<buffers_type> iterator;
1242 buffers_type data_buffers = buffers_.data();
1243 iterator begin = iterator::begin(data_buffers);
1244 iterator start_pos = begin + search_position_;
1245 iterator end = iterator::end(data_buffers);
1246
1247 // Look for a match.
1248 std::pair<iterator, bool> result = match_condition_(start_pos, end);
1249 if (result.second)
1250 {
1251 // Full match. We're done.
1252 search_position_ = result.first - begin;
1253 bytes_to_read = 0;
1254 }
1255
1256 // No match yet. Check if buffer is full.
1257 else if (buffers_.size() == buffers_.max_size())
1258 {
1259 search_position_ = not_found;
1260 bytes_to_read = 0;
1261 }
1262
1263 // Need to read some more data.
1264 else
1265 {
1266 if (result.first != end)
1267 {
1268 // Partial match. Next search needs to start from beginning of
1269 // match.
1270 search_position_ = result.first - begin;
1271 }
1272 else
1273 {
1274 // Next search can start with the new data.
1275 search_position_ = end - begin;
1276 }
1277
1278 bytes_to_read = std::min<std::size_t>(
1279 std::max<std::size_t>(512,
1280 buffers_.capacity() - buffers_.size()),
1281 std::min<std::size_t>(65536,
1282 buffers_.max_size() - buffers_.size()));
1283 }
1284 }
1285
1286 // Check if we're done.
1287 if (!start && bytes_to_read == 0)
1288 break;
1289
1290 // Start a new asynchronous read operation to obtain more data.
1291 stream_.async_read_some(buffers_.prepare(bytes_to_read),
1292 BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this));
1293 return; default:
1294 buffers_.commit(bytes_transferred);
1295 if (ec || bytes_transferred == 0)
1296 break;
1297 }
1298
1299 const boost::system::error_code result_ec =
1300 (search_position_ == not_found)
1301 ? error::not_found : ec;
1302
1303 const std::size_t result_n =
1304 (ec || search_position_ == not_found)
1305 ? 0 : search_position_;
1306
1307 handler_(result_ec, result_n);
1308 }
1309 }
1310
1311 //private:
1312 AsyncReadStream& stream_;
1313 DynamicBuffer buffers_;
1314 MatchCondition match_condition_;
1315 int start_;
1316 std::size_t search_position_;
1317 ReadHandler handler_;
1318 };
1319
1320 template <typename AsyncReadStream, typename DynamicBuffer,
1321 typename MatchCondition, typename ReadHandler>
1322 inline void* asio_handler_allocate(std::size_t size,
1323 read_until_match_op<AsyncReadStream, DynamicBuffer,
1324 MatchCondition, ReadHandler>* this_handler)
1325 {
1326 return boost_asio_handler_alloc_helpers::allocate(
1327 size, this_handler->handler_);
1328 }
1329
1330 template <typename AsyncReadStream, typename DynamicBuffer,
1331 typename MatchCondition, typename ReadHandler>
1332 inline void asio_handler_deallocate(void* pointer, std::size_t size,
1333 read_until_match_op<AsyncReadStream, DynamicBuffer,
1334 MatchCondition, ReadHandler>* this_handler)
1335 {
1336 boost_asio_handler_alloc_helpers::deallocate(
1337 pointer, size, this_handler->handler_);
1338 }
1339
1340 template <typename AsyncReadStream, typename DynamicBuffer,
1341 typename MatchCondition, typename ReadHandler>
1342 inline bool asio_handler_is_continuation(
1343 read_until_match_op<AsyncReadStream, DynamicBuffer,
1344 MatchCondition, ReadHandler>* this_handler)
1345 {
1346 return this_handler->start_ == 0 ? true
1347 : boost_asio_handler_cont_helpers::is_continuation(
1348 this_handler->handler_);
1349 }
1350
1351 template <typename Function, typename AsyncReadStream,
1352 typename DynamicBuffer, typename MatchCondition,
1353 typename ReadHandler>
1354 inline void asio_handler_invoke(Function& function,
1355 read_until_match_op<AsyncReadStream, DynamicBuffer,
1356 MatchCondition, ReadHandler>* this_handler)
1357 {
1358 boost_asio_handler_invoke_helpers::invoke(
1359 function, this_handler->handler_);
1360 }
1361
1362 template <typename Function, typename AsyncReadStream,
1363 typename DynamicBuffer, typename MatchCondition,
1364 typename ReadHandler>
1365 inline void asio_handler_invoke(const Function& function,
1366 read_until_match_op<AsyncReadStream, DynamicBuffer,
1367 MatchCondition, ReadHandler>* this_handler)
1368 {
1369 boost_asio_handler_invoke_helpers::invoke(
1370 function, this_handler->handler_);
1371 }
1372 } // namespace detail
1373
1374 #if !defined(GENERATING_DOCUMENTATION)
1375
1376 template <typename AsyncReadStream, typename DynamicBuffer,
1377 typename MatchCondition, typename ReadHandler, typename Allocator>
1378 struct associated_allocator<
1379 detail::read_until_match_op<AsyncReadStream,
1380 DynamicBuffer, MatchCondition, ReadHandler>,
1381 Allocator>
1382 {
1383 typedef typename associated_allocator<ReadHandler, Allocator>::type type;
1384
1385 static type get(
1386 const detail::read_until_match_op<AsyncReadStream,
1387 DynamicBuffer, MatchCondition, ReadHandler>& h,
1388 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
1389 {
1390 return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
1391 }
1392 };
1393
1394 template <typename AsyncReadStream, typename DynamicBuffer,
1395 typename MatchCondition, typename ReadHandler, typename Executor>
1396 struct associated_executor<
1397 detail::read_until_match_op<AsyncReadStream,
1398 DynamicBuffer, MatchCondition, ReadHandler>,
1399 Executor>
1400 {
1401 typedef typename associated_executor<ReadHandler, Executor>::type type;
1402
1403 static type get(
1404 const detail::read_until_match_op<AsyncReadStream,
1405 DynamicBuffer, MatchCondition, ReadHandler>& h,
1406 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
1407 {
1408 return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
1409 }
1410 };
1411
1412 #endif // !defined(GENERATING_DOCUMENTATION)
1413
1414 template <typename AsyncReadStream, typename DynamicBuffer,
1415 typename MatchCondition, typename ReadHandler>
1416 BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1417 void (boost::system::error_code, std::size_t))
1418 async_read_until(AsyncReadStream& s,
1419 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
1420 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1421 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
1422 {
1423 // If you get an error on the following line it means that your handler does
1424 // not meet the documented type requirements for a ReadHandler.
1425 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
1426
1427 async_completion<ReadHandler,
1428 void (boost::system::error_code, std::size_t)> init(handler);
1429
1430 detail::read_until_match_op<AsyncReadStream,
1431 typename decay<DynamicBuffer>::type,
1432 MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler,
1433 void (boost::system::error_code, std::size_t))>(
1434 s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers),
1435 match_condition, init.completion_handler)(
1436 boost::system::error_code(), 0, 1);
1437
1438 return init.result.get();
1439 }
1440
1441 #if !defined(BOOST_ASIO_NO_IOSTREAM)
1442
1443 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1444 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1445 void (boost::system::error_code, std::size_t))
1446 async_read_until(AsyncReadStream& s,
1447 boost::asio::basic_streambuf<Allocator>& b,
1448 char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1449 {
1450 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1451 delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1452 }
1453
1454 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1455 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1456 void (boost::system::error_code, std::size_t))
1457 async_read_until(AsyncReadStream& s,
1458 boost::asio::basic_streambuf<Allocator>& b,
1459 BOOST_ASIO_STRING_VIEW_PARAM delim,
1460 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1461 {
1462 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1463 delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1464 }
1465
1466 #if defined(BOOST_ASIO_HAS_BOOST_REGEX)
1467
1468 template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1469 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1470 void (boost::system::error_code, std::size_t))
1471 async_read_until(AsyncReadStream& s,
1472 boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr,
1473 BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
1474 {
1475 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1476 expr, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1477 }
1478
1479 #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1480
1481 template <typename AsyncReadStream, typename Allocator,
1482 typename MatchCondition, typename ReadHandler>
1483 inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1484 void (boost::system::error_code, std::size_t))
1485 async_read_until(AsyncReadStream& s,
1486 boost::asio::basic_streambuf<Allocator>& b,
1487 MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
1488 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
1489 {
1490 return async_read_until(s, basic_streambuf_ref<Allocator>(b),
1491 match_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
1492 }
1493
1494 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
1495 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
1496
1497 } // namespace asio
1498 } // namespace boost
1499
1500 #include <boost/asio/detail/pop_options.hpp>
1501
1502 #endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP