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