]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/impl/read_until.hpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / boost / asio / impl / read_until.hpp
CommitLineData
7c673cae
FG
1//
2// impl/read_until.hpp
3// ~~~~~~~~~~~~~~~~~~~
4//
11fdf7f2 5// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7c673cae
FG
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP
12#define BOOST_ASIO_IMPL_READ_UNTIL_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <algorithm>
19#include <string>
20#include <vector>
21#include <utility>
b32b8144
FG
22#include <boost/asio/associated_allocator.hpp>
23#include <boost/asio/associated_executor.hpp>
7c673cae
FG
24#include <boost/asio/buffer.hpp>
25#include <boost/asio/buffers_iterator.hpp>
26#include <boost/asio/detail/bind_handler.hpp>
27#include <boost/asio/detail/handler_alloc_helpers.hpp>
28#include <boost/asio/detail/handler_cont_helpers.hpp>
29#include <boost/asio/detail/handler_invoke_helpers.hpp>
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
36namespace boost {
37namespace asio {
38
b32b8144 39template <typename SyncReadStream, typename DynamicBuffer>
7c673cae 40inline std::size_t read_until(SyncReadStream& s,
b32b8144 41 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim)
7c673cae
FG
42{
43 boost::system::error_code ec;
b32b8144
FG
44 std::size_t bytes_transferred = read_until(s,
45 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec);
7c673cae
FG
46 boost::asio::detail::throw_error(ec, "read_until");
47 return bytes_transferred;
48}
49
b32b8144 50template <typename SyncReadStream, typename DynamicBuffer>
7c673cae 51std::size_t read_until(SyncReadStream& s,
b32b8144
FG
52 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
53 char delim, boost::system::error_code& ec)
7c673cae 54{
b32b8144
FG
55 typename decay<DynamicBuffer>::type b(
56 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
57
7c673cae
FG
58 std::size_t search_position = 0;
59 for (;;)
60 {
61 // Determine the range of the data to be searched.
b32b8144
FG
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);
7c673cae 66 iterator start_pos = begin + search_position;
b32b8144 67 iterator end = iterator::end(data_buffers);
7c673cae
FG
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.
b32b8144
FG
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()));
7c673cae
FG
94 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
95 if (ec)
96 return 0;
97 }
98}
99
b32b8144 100template <typename SyncReadStream, typename DynamicBuffer>
7c673cae 101inline std::size_t read_until(SyncReadStream& s,
b32b8144
FG
102 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
103 BOOST_ASIO_STRING_VIEW_PARAM delim)
7c673cae
FG
104{
105 boost::system::error_code ec;
b32b8144
FG
106 std::size_t bytes_transferred = read_until(s,
107 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec);
7c673cae
FG
108 boost::asio::detail::throw_error(ec, "read_until");
109 return bytes_transferred;
110}
111
112namespace 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
b32b8144 147template <typename SyncReadStream, typename DynamicBuffer>
7c673cae 148std::size_t read_until(SyncReadStream& s,
b32b8144
FG
149 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
150 BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec)
7c673cae 151{
b32b8144
FG
152 typename decay<DynamicBuffer>::type b(
153 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
154
7c673cae
FG
155 std::size_t search_position = 0;
156 for (;;)
157 {
158 // Determine the range of the data to be searched.
b32b8144
FG
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);
7c673cae 163 iterator start_pos = begin + search_position;
b32b8144 164 iterator end = iterator::end(data_buffers);
7c673cae
FG
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.
b32b8144
FG
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()));
7c673cae
FG
200 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
201 if (ec)
202 return 0;
203 }
204}
205
b32b8144 206#if !defined(BOOST_ASIO_NO_EXTENSIONS)
7c673cae
FG
207#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
208
b32b8144 209template <typename SyncReadStream, typename DynamicBuffer>
7c673cae 210inline std::size_t read_until(SyncReadStream& s,
b32b8144
FG
211 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
212 const boost::regex& expr)
7c673cae
FG
213{
214 boost::system::error_code ec;
b32b8144
FG
215 std::size_t bytes_transferred = read_until(s,
216 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), expr, ec);
7c673cae
FG
217 boost::asio::detail::throw_error(ec, "read_until");
218 return bytes_transferred;
219}
220
b32b8144 221template <typename SyncReadStream, typename DynamicBuffer>
7c673cae 222std::size_t read_until(SyncReadStream& s,
b32b8144
FG
223 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
224 const boost::regex& expr, boost::system::error_code& ec)
7c673cae 225{
b32b8144
FG
226 typename decay<DynamicBuffer>::type b(
227 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
228
7c673cae
FG
229 std::size_t search_position = 0;
230 for (;;)
231 {
232 // Determine the range of the data to be searched.
b32b8144
FG
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);
7c673cae 237 iterator start_pos = begin + search_position;
b32b8144 238 iterator end = iterator::end(data_buffers);
7c673cae
FG
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
b32b8144
FG
282template <typename SyncReadStream,
283 typename DynamicBuffer, typename MatchCondition>
284inline 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
297template <typename SyncReadStream,
298 typename DynamicBuffer, typename MatchCondition>
7c673cae 299std::size_t read_until(SyncReadStream& s,
b32b8144 300 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
7c673cae
FG
301 MatchCondition match_condition, boost::system::error_code& ec,
302 typename enable_if<is_match_condition<MatchCondition>::value>::type*)
303{
b32b8144
FG
304 typename decay<DynamicBuffer>::type b(
305 BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers));
306
7c673cae
FG
307 std::size_t search_position = 0;
308 for (;;)
309 {
310 // Determine the range of the data to be searched.
b32b8144
FG
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);
7c673cae 315 iterator start_pos = begin + search_position;
b32b8144 316 iterator end = iterator::end(data_buffers);
7c673cae
FG
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.
b32b8144
FG
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()));
7c673cae
FG
348 b.commit(s.read_some(b.prepare(bytes_to_read), ec));
349 if (ec)
350 return 0;
351 }
352}
353
b32b8144
FG
354#if !defined(BOOST_ASIO_NO_IOSTREAM)
355
356template <typename SyncReadStream, typename Allocator>
357inline 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
363template <typename SyncReadStream, typename Allocator>
364inline 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
371template <typename SyncReadStream, typename Allocator>
372inline 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
379template <typename SyncReadStream, typename Allocator>
380inline 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
389template <typename SyncReadStream, typename Allocator>
390inline 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
396template <typename SyncReadStream, typename Allocator>
397inline 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
7c673cae
FG
406template <typename SyncReadStream, typename Allocator, typename MatchCondition>
407inline 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{
b32b8144
FG
411 return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition);
412}
413
414template <typename SyncReadStream, typename Allocator, typename MatchCondition>
415inline 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);
7c673cae
FG
421}
422
b32b8144
FG
423#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
424#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
425
7c673cae
FG
426namespace detail
427{
b32b8144
FG
428 template <typename AsyncReadStream,
429 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
430 class read_until_delim_op
431 {
432 public:
b32b8144 433 template <typename BufferSequence>
7c673cae 434 read_until_delim_op(AsyncReadStream& stream,
b32b8144 435 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae
FG
436 char delim, ReadHandler& handler)
437 : stream_(stream),
b32b8144 438 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
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_),
b32b8144 449 buffers_(other.buffers_),
7c673cae
FG
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_),
b32b8144 459 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
7c673cae
FG
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.
b32b8144
FG
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);
7c673cae 485 iterator start_pos = begin + search_position_;
b32b8144 486 iterator end = iterator::end(data_buffers);
7c673cae
FG
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.
b32b8144 498 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
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;
b32b8144
FG
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()));
7c673cae
FG
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.
b32b8144 522 stream_.async_read_some(buffers_.prepare(bytes_to_read),
7c673cae
FG
523 BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this));
524 return; default:
b32b8144 525 buffers_.commit(bytes_transferred);
7c673cae
FG
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_;
b32b8144 544 DynamicBuffer buffers_;
7c673cae
FG
545 char delim_;
546 int start_;
547 std::size_t search_position_;
548 ReadHandler handler_;
549 };
550
b32b8144
FG
551 template <typename AsyncReadStream,
552 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
553 inline void* asio_handler_allocate(std::size_t size,
554 read_until_delim_op<AsyncReadStream,
b32b8144 555 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
556 {
557 return boost_asio_handler_alloc_helpers::allocate(
558 size, this_handler->handler_);
559 }
560
b32b8144
FG
561 template <typename AsyncReadStream,
562 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
563 inline void asio_handler_deallocate(void* pointer, std::size_t size,
564 read_until_delim_op<AsyncReadStream,
b32b8144 565 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
566 {
567 boost_asio_handler_alloc_helpers::deallocate(
568 pointer, size, this_handler->handler_);
569 }
570
b32b8144
FG
571 template <typename AsyncReadStream,
572 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
573 inline bool asio_handler_is_continuation(
574 read_until_delim_op<AsyncReadStream,
b32b8144 575 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
576 {
577 return this_handler->start_ == 0 ? true
578 : boost_asio_handler_cont_helpers::is_continuation(
579 this_handler->handler_);
580 }
581
b32b8144
FG
582 template <typename Function, typename AsyncReadStream,
583 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
584 inline void asio_handler_invoke(Function& function,
585 read_until_delim_op<AsyncReadStream,
b32b8144 586 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
587 {
588 boost_asio_handler_invoke_helpers::invoke(
589 function, this_handler->handler_);
590 }
591
b32b8144
FG
592 template <typename Function, typename AsyncReadStream,
593 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
594 inline void asio_handler_invoke(const Function& function,
595 read_until_delim_op<AsyncReadStream,
b32b8144 596 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
597 {
598 boost_asio_handler_invoke_helpers::invoke(
599 function, this_handler->handler_);
600 }
601} // namespace detail
602
b32b8144
FG
603#if !defined(GENERATING_DOCUMENTATION)
604
605template <typename AsyncReadStream, typename DynamicBuffer,
606 typename ReadHandler, typename Allocator>
607struct 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
623template <typename AsyncReadStream, typename DynamicBuffer,
624 typename ReadHandler, typename Executor>
625struct 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
643template <typename AsyncReadStream,
644 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
645BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
646 void (boost::system::error_code, std::size_t))
647async_read_until(AsyncReadStream& s,
b32b8144
FG
648 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
649 char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
7c673cae
FG
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
b32b8144
FG
655 async_completion<ReadHandler,
656 void (boost::system::error_code, std::size_t)> init(handler);
7c673cae
FG
657
658 detail::read_until_delim_op<AsyncReadStream,
b32b8144
FG
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);
7c673cae
FG
664
665 return init.result.get();
666}
667
668namespace detail
669{
b32b8144
FG
670 template <typename AsyncReadStream,
671 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
672 class read_until_delim_string_op
673 {
674 public:
b32b8144 675 template <typename BufferSequence>
7c673cae 676 read_until_delim_string_op(AsyncReadStream& stream,
b32b8144 677 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae
FG
678 const std::string& delim, ReadHandler& handler)
679 : stream_(stream),
b32b8144 680 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
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_),
b32b8144 691 buffers_(other.buffers_),
7c673cae
FG
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_),
b32b8144 701 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
7c673cae
FG
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.
b32b8144
FG
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);
7c673cae 727 iterator start_pos = begin + search_position_;
b32b8144 728 iterator end = iterator::end(data_buffers);
7c673cae
FG
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.
b32b8144 741 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
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
b32b8144
FG
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()));
7c673cae
FG
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.
b32b8144 775 stream_.async_read_some(buffers_.prepare(bytes_to_read),
7c673cae
FG
776 BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this));
777 return; default:
b32b8144 778 buffers_.commit(bytes_transferred);
7c673cae
FG
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_;
b32b8144 797 DynamicBuffer buffers_;
7c673cae
FG
798 std::string delim_;
799 int start_;
800 std::size_t search_position_;
801 ReadHandler handler_;
802 };
803
b32b8144
FG
804 template <typename AsyncReadStream,
805 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
806 inline void* asio_handler_allocate(std::size_t size,
807 read_until_delim_string_op<AsyncReadStream,
b32b8144 808 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
809 {
810 return boost_asio_handler_alloc_helpers::allocate(
811 size, this_handler->handler_);
812 }
813
b32b8144
FG
814 template <typename AsyncReadStream,
815 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
816 inline void asio_handler_deallocate(void* pointer, std::size_t size,
817 read_until_delim_string_op<AsyncReadStream,
b32b8144 818 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
819 {
820 boost_asio_handler_alloc_helpers::deallocate(
821 pointer, size, this_handler->handler_);
822 }
823
b32b8144
FG
824 template <typename AsyncReadStream,
825 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
826 inline bool asio_handler_is_continuation(
827 read_until_delim_string_op<AsyncReadStream,
b32b8144 828 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
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,
b32b8144 836 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
837 inline void asio_handler_invoke(Function& function,
838 read_until_delim_string_op<AsyncReadStream,
b32b8144 839 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
840 {
841 boost_asio_handler_invoke_helpers::invoke(
842 function, this_handler->handler_);
843 }
844
845 template <typename Function, typename AsyncReadStream,
b32b8144 846 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
847 inline void asio_handler_invoke(const Function& function,
848 read_until_delim_string_op<AsyncReadStream,
b32b8144 849 DynamicBuffer, ReadHandler>* this_handler)
7c673cae
FG
850 {
851 boost_asio_handler_invoke_helpers::invoke(
852 function, this_handler->handler_);
853 }
854} // namespace detail
855
b32b8144
FG
856#if !defined(GENERATING_DOCUMENTATION)
857
858template <typename AsyncReadStream, typename DynamicBuffer,
859 typename ReadHandler, typename Allocator>
860struct 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
876template <typename AsyncReadStream, typename DynamicBuffer,
877 typename ReadHandler, typename Executor>
878struct 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
896template <typename AsyncReadStream,
897 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
898BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
899 void (boost::system::error_code, std::size_t))
900async_read_until(AsyncReadStream& s,
b32b8144
FG
901 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
902 BOOST_ASIO_STRING_VIEW_PARAM delim,
7c673cae
FG
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
b32b8144
FG
909 async_completion<ReadHandler,
910 void (boost::system::error_code, std::size_t)> init(handler);
7c673cae
FG
911
912 detail::read_until_delim_string_op<AsyncReadStream,
b32b8144
FG
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);
7c673cae
FG
919
920 return init.result.get();
921}
922
b32b8144 923#if !defined(BOOST_ASIO_NO_EXTENSIONS)
7c673cae
FG
924#if defined(BOOST_ASIO_HAS_BOOST_REGEX)
925
926namespace detail
927{
b32b8144 928 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
929 typename RegEx, typename ReadHandler>
930 class read_until_expr_op
931 {
932 public:
b32b8144 933 template <typename BufferSequence>
7c673cae 934 read_until_expr_op(AsyncReadStream& stream,
b32b8144 935 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae
FG
936 const boost::regex& expr, ReadHandler& handler)
937 : stream_(stream),
b32b8144 938 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
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_),
b32b8144 949 buffers_(other.buffers_),
7c673cae
FG
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_),
b32b8144 959 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
7c673cae
FG
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.
b32b8144
FG
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);
7c673cae 985 iterator start_pos = begin + search_position_;
b32b8144 986 iterator end = iterator::end(data_buffers);
7c673cae
FG
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.
b32b8144 1002 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
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
b32b8144
FG
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()));
7c673cae
FG
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.
b32b8144 1036 stream_.async_read_some(buffers_.prepare(bytes_to_read),
7c673cae
FG
1037 BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this));
1038 return; default:
b32b8144 1039 buffers_.commit(bytes_transferred);
7c673cae
FG
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_;
b32b8144 1058 DynamicBuffer buffers_;
7c673cae
FG
1059 RegEx expr_;
1060 int start_;
1061 std::size_t search_position_;
1062 ReadHandler handler_;
1063 };
1064
b32b8144 1065 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1066 typename RegEx, typename ReadHandler>
1067 inline void* asio_handler_allocate(std::size_t size,
1068 read_until_expr_op<AsyncReadStream,
b32b8144 1069 DynamicBuffer, RegEx, ReadHandler>* this_handler)
7c673cae
FG
1070 {
1071 return boost_asio_handler_alloc_helpers::allocate(
1072 size, this_handler->handler_);
1073 }
1074
b32b8144 1075 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1076 typename RegEx, typename ReadHandler>
1077 inline void asio_handler_deallocate(void* pointer, std::size_t size,
1078 read_until_expr_op<AsyncReadStream,
b32b8144 1079 DynamicBuffer, RegEx, ReadHandler>* this_handler)
7c673cae
FG
1080 {
1081 boost_asio_handler_alloc_helpers::deallocate(
1082 pointer, size, this_handler->handler_);
1083 }
1084
b32b8144 1085 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1086 typename RegEx, typename ReadHandler>
1087 inline bool asio_handler_is_continuation(
1088 read_until_expr_op<AsyncReadStream,
b32b8144 1089 DynamicBuffer, RegEx, ReadHandler>* this_handler)
7c673cae
FG
1090 {
1091 return this_handler->start_ == 0 ? true
1092 : boost_asio_handler_cont_helpers::is_continuation(
1093 this_handler->handler_);
1094 }
1095
b32b8144
FG
1096 template <typename Function, typename AsyncReadStream,
1097 typename DynamicBuffer, typename RegEx, typename ReadHandler>
7c673cae
FG
1098 inline void asio_handler_invoke(Function& function,
1099 read_until_expr_op<AsyncReadStream,
b32b8144 1100 DynamicBuffer, RegEx, ReadHandler>* this_handler)
7c673cae
FG
1101 {
1102 boost_asio_handler_invoke_helpers::invoke(
1103 function, this_handler->handler_);
1104 }
1105
b32b8144
FG
1106 template <typename Function, typename AsyncReadStream,
1107 typename DynamicBuffer, typename RegEx, typename ReadHandler>
7c673cae
FG
1108 inline void asio_handler_invoke(const Function& function,
1109 read_until_expr_op<AsyncReadStream,
b32b8144 1110 DynamicBuffer, RegEx, ReadHandler>* this_handler)
7c673cae
FG
1111 {
1112 boost_asio_handler_invoke_helpers::invoke(
1113 function, this_handler->handler_);
1114 }
1115} // namespace detail
1116
b32b8144
FG
1117#if !defined(GENERATING_DOCUMENTATION)
1118
1119template <typename AsyncReadStream, typename DynamicBuffer,
1120 typename RegEx, typename ReadHandler, typename Allocator>
1121struct 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
1137template <typename AsyncReadStream, typename DynamicBuffer,
1138 typename RegEx, typename ReadHandler, typename Executor>
1139struct 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
1157template <typename AsyncReadStream,
1158 typename DynamicBuffer, typename ReadHandler>
7c673cae
FG
1159BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1160 void (boost::system::error_code, std::size_t))
1161async_read_until(AsyncReadStream& s,
b32b8144
FG
1162 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
1163 const boost::regex& expr,
7c673cae
FG
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
b32b8144
FG
1170 async_completion<ReadHandler,
1171 void (boost::system::error_code, std::size_t)> init(handler);
7c673cae 1172
b32b8144
FG
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);
7c673cae
FG
1179
1180 return init.result.get();
1181}
1182
1183#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX)
1184
1185namespace detail
1186{
b32b8144 1187 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1188 typename MatchCondition, typename ReadHandler>
1189 class read_until_match_op
1190 {
1191 public:
b32b8144 1192 template <typename BufferSequence>
7c673cae 1193 read_until_match_op(AsyncReadStream& stream,
b32b8144 1194 BOOST_ASIO_MOVE_ARG(BufferSequence) buffers,
7c673cae
FG
1195 MatchCondition match_condition, ReadHandler& handler)
1196 : stream_(stream),
b32b8144 1197 buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)),
7c673cae
FG
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_),
b32b8144 1208 buffers_(other.buffers_),
7c673cae
FG
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_),
b32b8144 1218 buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)),
7c673cae
FG
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.
b32b8144
FG
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);
7c673cae 1244 iterator start_pos = begin + search_position_;
b32b8144 1245 iterator end = iterator::end(data_buffers);
7c673cae
FG
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.
b32b8144 1257 else if (buffers_.size() == buffers_.max_size())
7c673cae
FG
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
b32b8144
FG
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()));
7c673cae
FG
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.
b32b8144 1291 stream_.async_read_some(buffers_.prepare(bytes_to_read),
7c673cae
FG
1292 BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this));
1293 return; default:
b32b8144 1294 buffers_.commit(bytes_transferred);
7c673cae
FG
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_;
b32b8144 1313 DynamicBuffer buffers_;
7c673cae
FG
1314 MatchCondition match_condition_;
1315 int start_;
1316 std::size_t search_position_;
1317 ReadHandler handler_;
1318 };
1319
b32b8144 1320 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1321 typename MatchCondition, typename ReadHandler>
1322 inline void* asio_handler_allocate(std::size_t size,
b32b8144
FG
1323 read_until_match_op<AsyncReadStream, DynamicBuffer,
1324 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
1325 {
1326 return boost_asio_handler_alloc_helpers::allocate(
1327 size, this_handler->handler_);
1328 }
1329
b32b8144 1330 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1331 typename MatchCondition, typename ReadHandler>
1332 inline void asio_handler_deallocate(void* pointer, std::size_t size,
b32b8144
FG
1333 read_until_match_op<AsyncReadStream, DynamicBuffer,
1334 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
1335 {
1336 boost_asio_handler_alloc_helpers::deallocate(
1337 pointer, size, this_handler->handler_);
1338 }
1339
b32b8144 1340 template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1341 typename MatchCondition, typename ReadHandler>
1342 inline bool asio_handler_is_continuation(
b32b8144
FG
1343 read_until_match_op<AsyncReadStream, DynamicBuffer,
1344 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
1345 {
1346 return this_handler->start_ == 0 ? true
1347 : boost_asio_handler_cont_helpers::is_continuation(
1348 this_handler->handler_);
1349 }
1350
b32b8144
FG
1351 template <typename Function, typename AsyncReadStream,
1352 typename DynamicBuffer, typename MatchCondition,
1353 typename ReadHandler>
7c673cae 1354 inline void asio_handler_invoke(Function& function,
b32b8144
FG
1355 read_until_match_op<AsyncReadStream, DynamicBuffer,
1356 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
1357 {
1358 boost_asio_handler_invoke_helpers::invoke(
1359 function, this_handler->handler_);
1360 }
1361
b32b8144
FG
1362 template <typename Function, typename AsyncReadStream,
1363 typename DynamicBuffer, typename MatchCondition,
1364 typename ReadHandler>
7c673cae 1365 inline void asio_handler_invoke(const Function& function,
b32b8144
FG
1366 read_until_match_op<AsyncReadStream, DynamicBuffer,
1367 MatchCondition, ReadHandler>* this_handler)
7c673cae
FG
1368 {
1369 boost_asio_handler_invoke_helpers::invoke(
1370 function, this_handler->handler_);
1371 }
1372} // namespace detail
1373
b32b8144
FG
1374#if !defined(GENERATING_DOCUMENTATION)
1375
1376template <typename AsyncReadStream, typename DynamicBuffer,
1377 typename MatchCondition, typename ReadHandler, typename Allocator>
1378struct 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
1394template <typename AsyncReadStream, typename DynamicBuffer,
1395 typename MatchCondition, typename ReadHandler, typename Executor>
1396struct 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
1414template <typename AsyncReadStream, typename DynamicBuffer,
7c673cae
FG
1415 typename MatchCondition, typename ReadHandler>
1416BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1417 void (boost::system::error_code, std::size_t))
1418async_read_until(AsyncReadStream& s,
b32b8144 1419 BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers,
7c673cae
FG
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
b32b8144
FG
1427 async_completion<ReadHandler,
1428 void (boost::system::error_code, std::size_t)> init(handler);
7c673cae 1429
b32b8144
FG
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);
7c673cae
FG
1437
1438 return init.result.get();
1439}
1440
b32b8144
FG
1441#if !defined(BOOST_ASIO_NO_IOSTREAM)
1442
1443template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1444inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1445 void (boost::system::error_code, std::size_t))
1446async_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
1454template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1455inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1456 void (boost::system::error_code, std::size_t))
1457async_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
1468template <typename AsyncReadStream, typename Allocator, typename ReadHandler>
1469inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1470 void (boost::system::error_code, std::size_t))
1471async_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
1481template <typename AsyncReadStream, typename Allocator,
1482 typename MatchCondition, typename ReadHandler>
1483inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
1484 void (boost::system::error_code, std::size_t))
1485async_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
7c673cae
FG
1497} // namespace asio
1498} // namespace boost
1499
1500#include <boost/asio/detail/pop_options.hpp>
1501
1502#endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP