read_until.hpp 99 KB

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