multi_buffer.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_IMPL_MULTI_BUFFER_HPP
  10. #define BOOST_BEAST_IMPL_MULTI_BUFFER_HPP
  11. #include <boost/beast/core/buffer_traits.hpp>
  12. #include <boost/config/workaround.hpp>
  13. #include <boost/core/exchange.hpp>
  14. #include <boost/assert.hpp>
  15. #include <boost/throw_exception.hpp>
  16. #include <algorithm>
  17. #include <exception>
  18. #include <iterator>
  19. #include <sstream>
  20. #include <string>
  21. #include <type_traits>
  22. #include <utility>
  23. namespace boost {
  24. namespace beast {
  25. /* These diagrams illustrate the layout and state variables.
  26. 1 Input and output contained entirely in one element:
  27. 0 out_
  28. |<------+-----------+--------------------------------+----->|
  29. in_pos_ out_pos_ out_end_
  30. 2 Output contained in first and second elements:
  31. out_
  32. |<------+-----------+------>| |<-------------------+----->|
  33. in_pos_ out_pos_ out_end_
  34. 3 Output contained in the second element:
  35. out_
  36. |<------+------------------>| |<----+--------------+----->|
  37. in_pos_ out_pos_ out_end_
  38. 4 Output contained in second and third elements:
  39. out_
  40. |<------+------->| |<-------+------>| |<---------+----->|
  41. in_pos_ out_pos_ out_end_
  42. 5 Input sequence is empty:
  43. out_
  44. |<------+------------------>| |<-------------------+----->|
  45. out_pos_ out_end_
  46. in_pos_
  47. 6 Output sequence is empty:
  48. out_
  49. |<------+------------------>| |<------+------------------>|
  50. in_pos_ out_pos_
  51. out_end_
  52. 7 The end of output can point to the end of an element.
  53. But out_pos_ should never point to the end:
  54. out_
  55. |<------+------------------>| |<------+------------------>|
  56. in_pos_ out_pos_ out_end_
  57. 8 When the input sequence entirely fills the last element and
  58. the output sequence is empty, out_ will point to the end of
  59. the list of buffers, and out_pos_ and out_end_ will be 0:
  60. |<------+------------------>| out_ == list_.end()
  61. in_pos_ out_pos_ == 0
  62. out_end_ == 0
  63. */
  64. //------------------------------------------------------------------------------
  65. #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
  66. # pragma warning (push)
  67. # pragma warning (disable: 4521) // multiple copy constructors specified
  68. # pragma warning (disable: 4522) // multiple assignment operators specified
  69. #endif
  70. template<class Allocator>
  71. template<bool isMutable>
  72. class basic_multi_buffer<Allocator>::subrange
  73. {
  74. basic_multi_buffer const* b_;
  75. const_iter begin_;
  76. const_iter end_;
  77. size_type begin_pos_; // offset in begin_
  78. size_type last_pos_; // offset in std::prev(end_)
  79. friend class basic_multi_buffer;
  80. subrange(
  81. basic_multi_buffer const& b,
  82. size_type pos,
  83. size_type n) noexcept
  84. : b_(&b)
  85. {
  86. auto const set_empty = [&]
  87. {
  88. begin_ = b_->list_.end();
  89. end_ = b_->list_.end();
  90. begin_pos_ = 0;
  91. last_pos_ = 0;
  92. };
  93. // VFALCO Handle this trivial case of
  94. // pos larger than total size, otherwise
  95. // the addition to pos can overflow.
  96. //if(pos >= b_->in_size_)
  97. // skip unused prefix
  98. pos = pos + b_->in_pos_;
  99. // iterate the buffers
  100. auto it = b_->list_.begin();
  101. // is the list empty?
  102. if(it == b_->list_.end())
  103. {
  104. set_empty();
  105. return;
  106. }
  107. // is the requested size zero?
  108. if(n == 0)
  109. {
  110. set_empty();
  111. return;
  112. }
  113. // get last buffer and its size
  114. auto const last =
  115. std::prev(b_->list_.end());
  116. auto const last_end =
  117. [&]
  118. {
  119. if(b_->out_end_ == 0)
  120. return last->size();
  121. return b_->out_end_;
  122. }();
  123. // only one buffer in list?
  124. if(it == last)
  125. {
  126. if(pos >= last_end)
  127. {
  128. set_empty();
  129. return;
  130. }
  131. begin_ = it;
  132. begin_pos_ = pos;
  133. end_ = std::next(it);
  134. if(n > last_end - pos)
  135. last_pos_ = last_end;
  136. else
  137. last_pos_ = pos + n;
  138. return;
  139. }
  140. for(;;)
  141. {
  142. // is pos in this buffer?
  143. if(pos < it->size())
  144. {
  145. begin_ = it;
  146. begin_pos_ = pos;
  147. // does this buffer satisfy n?
  148. auto const avail =
  149. it->size() - pos;
  150. if(n <= avail)
  151. {
  152. end_ = ++it;
  153. last_pos_ = pos + n;
  154. return;
  155. }
  156. n -= avail;
  157. ++it;
  158. break;
  159. }
  160. pos -= it->size();
  161. ++it;
  162. // did we reach the last buffer?
  163. if(it == last)
  164. {
  165. // is pos past the end?
  166. if(pos >= last_end)
  167. {
  168. set_empty();
  169. return;
  170. }
  171. // satisfy the request
  172. begin_ = it;
  173. begin_pos_ = pos;
  174. end_ = std::next(it);
  175. if(n < last_end - pos)
  176. last_pos_ = pos + n;
  177. else
  178. last_pos_ = last_end;
  179. return;
  180. }
  181. }
  182. // find pos+n
  183. for(;;)
  184. {
  185. if(it == last)
  186. {
  187. end_ = ++it;
  188. if(n >= last_end)
  189. last_pos_ = last_end;
  190. else
  191. last_pos_ = n;
  192. return;
  193. }
  194. if(n <= it->size())
  195. {
  196. end_ = ++it;
  197. last_pos_ = n;
  198. return;
  199. }
  200. n -= it->size();
  201. ++it;
  202. }
  203. }
  204. public:
  205. using value_type = typename
  206. std::conditional<
  207. isMutable,
  208. net::mutable_buffer,
  209. net::const_buffer>::type;
  210. class const_iterator;
  211. subrange() = delete;
  212. #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
  213. subrange(subrange const& other)
  214. : b_(other.b_)
  215. , begin_(other.begin_)
  216. , end_(other.end_)
  217. , begin_pos_(other.begin_pos_)
  218. , last_pos_(other.last_pos_)
  219. {
  220. }
  221. subrange& operator=(subrange const& other)
  222. {
  223. b_ = other.b_;
  224. begin_ = other.begin_;
  225. end_ = other.end_;
  226. begin_pos_ = other.begin_pos_;
  227. last_pos_ = other.last_pos_;
  228. return *this;
  229. }
  230. #else
  231. subrange(subrange const&) = default;
  232. subrange& operator=(subrange const&) = default;
  233. #endif
  234. template<
  235. bool isMutable_ = isMutable,
  236. class = typename std::enable_if<! isMutable_>::type>
  237. subrange(
  238. subrange<true> const& other) noexcept
  239. : b_(other.b_)
  240. , begin_(other.begin_)
  241. , end_(other.end_)
  242. , begin_pos_(other.begin_pos_)
  243. , last_pos_(other.last_pos_)
  244. {
  245. }
  246. template<
  247. bool isMutable_ = isMutable,
  248. class = typename std::enable_if<! isMutable_>::type>
  249. subrange& operator=(
  250. subrange<true> const& other) noexcept
  251. {
  252. b_ = other.b_;
  253. begin_ = other.begin_;
  254. end_ = other.end_;
  255. begin_pos_ = other.begin_pos_;
  256. last_pos_ = other.last_pos_;
  257. return *this;
  258. }
  259. const_iterator begin() const noexcept;
  260. const_iterator end() const noexcept;
  261. std::size_t
  262. buffer_bytes() const noexcept
  263. {
  264. return b_->size();
  265. }
  266. };
  267. #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
  268. # pragma warning (pop)
  269. #endif
  270. //------------------------------------------------------------------------------
  271. template<class Allocator>
  272. template<bool isMutable>
  273. class
  274. basic_multi_buffer<Allocator>::
  275. subrange<isMutable>::
  276. const_iterator
  277. {
  278. friend class subrange;
  279. subrange const* sr_ = nullptr;
  280. typename list_type::const_iterator it_;
  281. const_iterator(
  282. subrange const& sr, typename
  283. list_type::const_iterator const& it) noexcept
  284. : sr_(&sr)
  285. , it_(it)
  286. {
  287. }
  288. public:
  289. using value_type =
  290. typename subrange::value_type;
  291. using pointer = value_type const*;
  292. using reference = value_type;
  293. using difference_type = std::ptrdiff_t;
  294. using iterator_category =
  295. std::bidirectional_iterator_tag;
  296. const_iterator() = default;
  297. const_iterator(
  298. const_iterator const& other) = default;
  299. const_iterator& operator=(
  300. const_iterator const& other) = default;
  301. bool
  302. operator==(
  303. const_iterator const& other) const noexcept
  304. {
  305. return sr_ == other.sr_ && it_ == other.it_;
  306. }
  307. bool
  308. operator!=(
  309. const_iterator const& other) const noexcept
  310. {
  311. return !(*this == other);
  312. }
  313. reference
  314. operator*() const noexcept
  315. {
  316. value_type result;
  317. BOOST_ASSERT(sr_->last_pos_ != 0);
  318. if(it_ == std::prev(sr_->end_))
  319. result = {
  320. it_->data(), sr_->last_pos_ };
  321. else
  322. result = {
  323. it_->data(), it_->size() };
  324. if(it_ == sr_->begin_)
  325. result += sr_->begin_pos_;
  326. return result;
  327. }
  328. pointer
  329. operator->() const = delete;
  330. const_iterator&
  331. operator++() noexcept
  332. {
  333. ++it_;
  334. return *this;
  335. }
  336. const_iterator
  337. operator++(int) noexcept
  338. {
  339. auto temp = *this;
  340. ++(*this);
  341. return temp;
  342. }
  343. const_iterator&
  344. operator--() noexcept
  345. {
  346. --it_;
  347. return *this;
  348. }
  349. const_iterator
  350. operator--(int) noexcept
  351. {
  352. auto temp = *this;
  353. --(*this);
  354. return temp;
  355. }
  356. };
  357. //------------------------------------------------------------------------------
  358. template<class Allocator>
  359. template<bool isMutable>
  360. auto
  361. basic_multi_buffer<Allocator>::
  362. subrange<isMutable>::
  363. begin() const noexcept ->
  364. const_iterator
  365. {
  366. return const_iterator(
  367. *this, begin_);
  368. }
  369. template<class Allocator>
  370. template<bool isMutable>
  371. auto
  372. basic_multi_buffer<Allocator>::
  373. subrange<isMutable>::
  374. end() const noexcept ->
  375. const_iterator
  376. {
  377. return const_iterator(
  378. *this, end_);
  379. }
  380. //------------------------------------------------------------------------------
  381. template<class Allocator>
  382. basic_multi_buffer<Allocator>::
  383. ~basic_multi_buffer()
  384. {
  385. destroy(list_);
  386. }
  387. template<class Allocator>
  388. basic_multi_buffer<Allocator>::
  389. basic_multi_buffer() noexcept(default_nothrow)
  390. : max_(alloc_traits::max_size(this->get()))
  391. , out_(list_.end())
  392. {
  393. }
  394. template<class Allocator>
  395. basic_multi_buffer<Allocator>::
  396. basic_multi_buffer(
  397. std::size_t limit) noexcept(default_nothrow)
  398. : max_(limit)
  399. , out_(list_.end())
  400. {
  401. }
  402. template<class Allocator>
  403. basic_multi_buffer<Allocator>::
  404. basic_multi_buffer(
  405. Allocator const& alloc) noexcept
  406. : boost::empty_value<Allocator>(
  407. boost::empty_init_t(), alloc)
  408. , max_(alloc_traits::max_size(this->get()))
  409. , out_(list_.end())
  410. {
  411. }
  412. template<class Allocator>
  413. basic_multi_buffer<Allocator>::
  414. basic_multi_buffer(
  415. std::size_t limit,
  416. Allocator const& alloc) noexcept
  417. : boost::empty_value<Allocator>(
  418. boost::empty_init_t(), alloc)
  419. , max_(limit)
  420. , out_(list_.end())
  421. {
  422. }
  423. template<class Allocator>
  424. basic_multi_buffer<Allocator>::
  425. basic_multi_buffer(
  426. basic_multi_buffer&& other) noexcept
  427. : boost::empty_value<Allocator>(
  428. boost::empty_init_t(), std::move(other.get()))
  429. , max_(other.max_)
  430. , in_size_(boost::exchange(other.in_size_, 0))
  431. , in_pos_(boost::exchange(other.in_pos_, 0))
  432. , out_pos_(boost::exchange(other.out_pos_, 0))
  433. , out_end_(boost::exchange(other.out_end_, 0))
  434. {
  435. auto const at_end =
  436. other.out_ == other.list_.end();
  437. list_ = std::move(other.list_);
  438. out_ = at_end ? list_.end() : other.out_;
  439. other.out_ = other.list_.end();
  440. }
  441. template<class Allocator>
  442. basic_multi_buffer<Allocator>::
  443. basic_multi_buffer(
  444. basic_multi_buffer&& other,
  445. Allocator const& alloc)
  446. : boost::empty_value<Allocator>(
  447. boost::empty_init_t(), alloc)
  448. , max_(other.max_)
  449. {
  450. if(this->get() != other.get())
  451. {
  452. out_ = list_.end();
  453. copy_from(other);
  454. return;
  455. }
  456. auto const at_end =
  457. other.out_ == other.list_.end();
  458. list_ = std::move(other.list_);
  459. out_ = at_end ? list_.end() : other.out_;
  460. in_size_ = other.in_size_;
  461. in_pos_ = other.in_pos_;
  462. out_pos_ = other.out_pos_;
  463. out_end_ = other.out_end_;
  464. other.in_size_ = 0;
  465. other.out_ = other.list_.end();
  466. other.in_pos_ = 0;
  467. other.out_pos_ = 0;
  468. other.out_end_ = 0;
  469. }
  470. template<class Allocator>
  471. basic_multi_buffer<Allocator>::
  472. basic_multi_buffer(
  473. basic_multi_buffer const& other)
  474. : boost::empty_value<Allocator>(
  475. boost::empty_init_t(), alloc_traits::
  476. select_on_container_copy_construction(
  477. other.get()))
  478. , max_(other.max_)
  479. , out_(list_.end())
  480. {
  481. copy_from(other);
  482. }
  483. template<class Allocator>
  484. basic_multi_buffer<Allocator>::
  485. basic_multi_buffer(
  486. basic_multi_buffer const& other,
  487. Allocator const& alloc)
  488. : boost::empty_value<Allocator>(
  489. boost::empty_init_t(), alloc)
  490. , max_(other.max_)
  491. , out_(list_.end())
  492. {
  493. copy_from(other);
  494. }
  495. template<class Allocator>
  496. template<class OtherAlloc>
  497. basic_multi_buffer<Allocator>::
  498. basic_multi_buffer(
  499. basic_multi_buffer<OtherAlloc> const& other)
  500. : out_(list_.end())
  501. {
  502. copy_from(other);
  503. }
  504. template<class Allocator>
  505. template<class OtherAlloc>
  506. basic_multi_buffer<Allocator>::
  507. basic_multi_buffer(
  508. basic_multi_buffer<OtherAlloc> const& other,
  509. allocator_type const& alloc)
  510. : boost::empty_value<Allocator>(
  511. boost::empty_init_t(), alloc)
  512. , max_(other.max_)
  513. , out_(list_.end())
  514. {
  515. copy_from(other);
  516. }
  517. template<class Allocator>
  518. auto
  519. basic_multi_buffer<Allocator>::
  520. operator=(basic_multi_buffer&& other) ->
  521. basic_multi_buffer&
  522. {
  523. if(this == &other)
  524. return *this;
  525. clear();
  526. max_ = other.max_;
  527. move_assign(other, pocma{});
  528. return *this;
  529. }
  530. template<class Allocator>
  531. auto
  532. basic_multi_buffer<Allocator>::
  533. operator=(basic_multi_buffer const& other) ->
  534. basic_multi_buffer&
  535. {
  536. if(this == &other)
  537. return *this;
  538. copy_assign(other, pocca{});
  539. return *this;
  540. }
  541. template<class Allocator>
  542. template<class OtherAlloc>
  543. auto
  544. basic_multi_buffer<Allocator>::
  545. operator=(
  546. basic_multi_buffer<OtherAlloc> const& other) ->
  547. basic_multi_buffer&
  548. {
  549. copy_from(other);
  550. return *this;
  551. }
  552. //------------------------------------------------------------------------------
  553. template<class Allocator>
  554. std::size_t
  555. basic_multi_buffer<Allocator>::
  556. capacity() const noexcept
  557. {
  558. auto pos = out_;
  559. if(pos == list_.end())
  560. return in_size_;
  561. auto n = pos->size() - out_pos_;
  562. while(++pos != list_.end())
  563. n += pos->size();
  564. return in_size_ + n;
  565. }
  566. template<class Allocator>
  567. auto
  568. basic_multi_buffer<Allocator>::
  569. data() const noexcept ->
  570. const_buffers_type
  571. {
  572. return const_buffers_type(
  573. *this, 0, in_size_);
  574. }
  575. template<class Allocator>
  576. auto
  577. basic_multi_buffer<Allocator>::
  578. data() noexcept ->
  579. mutable_buffers_type
  580. {
  581. return mutable_buffers_type(
  582. *this, 0, in_size_);
  583. }
  584. template<class Allocator>
  585. void
  586. basic_multi_buffer<Allocator>::
  587. reserve(std::size_t n)
  588. {
  589. // VFALCO The amount needs to be adjusted for
  590. // the sizeof(element) plus padding
  591. if(n > alloc_traits::max_size(this->get()))
  592. BOOST_THROW_EXCEPTION(std::length_error(
  593. "A basic_multi_buffer exceeded the allocator's maximum size"));
  594. std::size_t total = in_size_;
  595. if(n <= total)
  596. return;
  597. if(out_ != list_.end())
  598. {
  599. total += out_->size() - out_pos_;
  600. if(n <= total)
  601. return;
  602. for(auto it = out_;;)
  603. {
  604. if(++it == list_.end())
  605. break;
  606. total += it->size();
  607. if(n <= total)
  608. return;
  609. }
  610. }
  611. BOOST_ASSERT(n > total);
  612. (void)prepare(n - size());
  613. }
  614. template<class Allocator>
  615. void
  616. basic_multi_buffer<Allocator>::
  617. shrink_to_fit()
  618. {
  619. // empty list
  620. if(list_.empty())
  621. return;
  622. // zero readable bytes
  623. if(in_size_ == 0)
  624. {
  625. destroy(list_);
  626. list_.clear();
  627. out_ = list_.end();
  628. in_size_ = 0;
  629. in_pos_ = 0;
  630. out_pos_ = 0;
  631. out_end_ = 0;
  632. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  633. debug_check();
  634. #endif
  635. return;
  636. }
  637. // one or more unused output buffers
  638. if(out_ != list_.end())
  639. {
  640. if(out_ != list_.iterator_to(list_.back()))
  641. {
  642. // unused list
  643. list_type extra;
  644. extra.splice(
  645. extra.end(),
  646. list_,
  647. std::next(out_),
  648. list_.end());
  649. destroy(extra);
  650. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  651. debug_check();
  652. #endif
  653. }
  654. // unused out_
  655. BOOST_ASSERT(out_ ==
  656. list_.iterator_to(list_.back()));
  657. if(out_pos_ == 0)
  658. {
  659. BOOST_ASSERT(out_ != list_.begin());
  660. auto& e = *out_;
  661. list_.erase(out_);
  662. out_ = list_.end();
  663. destroy(e);
  664. out_end_ = 0;
  665. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  666. debug_check();
  667. #endif
  668. }
  669. }
  670. auto const replace =
  671. [&](iter pos, element& e)
  672. {
  673. auto it =
  674. list_.insert(pos, e);
  675. auto& e0 = *pos;
  676. list_.erase(pos);
  677. destroy(e0);
  678. return it;
  679. };
  680. // partial last buffer
  681. if(out_ != list_.begin() && out_ != list_.end())
  682. {
  683. BOOST_ASSERT(out_ ==
  684. list_.iterator_to(list_.back()));
  685. BOOST_ASSERT(out_pos_ != 0);
  686. auto& e = alloc(out_pos_);
  687. std::memcpy(
  688. e.data(),
  689. out_->data(),
  690. out_pos_);
  691. replace(out_, e);
  692. out_ = list_.end();
  693. out_pos_ = 0;
  694. out_end_ = 0;
  695. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  696. debug_check();
  697. #endif
  698. }
  699. // partial first buffer
  700. if(in_pos_ != 0)
  701. {
  702. if(out_ != list_.begin())
  703. {
  704. auto const n =
  705. list_.front().size() - in_pos_;
  706. auto& e = alloc(n);
  707. std::memcpy(
  708. e.data(),
  709. list_.front().data() + in_pos_,
  710. n);
  711. replace(list_.begin(), e);
  712. in_pos_ = 0;
  713. }
  714. else
  715. {
  716. BOOST_ASSERT(out_ ==
  717. list_.iterator_to(list_.back()));
  718. BOOST_ASSERT(out_pos_ > in_pos_);
  719. auto const n = out_pos_ - in_pos_;
  720. auto& e = alloc(n);
  721. std::memcpy(
  722. e.data(),
  723. list_.front().data() + in_pos_,
  724. n);
  725. replace(list_.begin(), e);
  726. in_pos_ = 0;
  727. out_ = list_.end();
  728. }
  729. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  730. debug_check();
  731. #endif
  732. }
  733. }
  734. template<class Allocator>
  735. void
  736. basic_multi_buffer<Allocator>::
  737. clear() noexcept
  738. {
  739. out_ = list_.begin();
  740. in_size_ = 0;
  741. in_pos_ = 0;
  742. out_pos_ = 0;
  743. out_end_ = 0;
  744. }
  745. template<class Allocator>
  746. auto
  747. basic_multi_buffer<Allocator>::
  748. prepare(size_type n) ->
  749. mutable_buffers_type
  750. {
  751. auto const n0 = n;
  752. if(in_size_ > max_ || n > (max_ - in_size_))
  753. BOOST_THROW_EXCEPTION(std::length_error{
  754. "basic_multi_buffer too long"});
  755. list_type reuse;
  756. std::size_t total = in_size_;
  757. // put all empty buffers on reuse list
  758. if(out_ != list_.end())
  759. {
  760. total += out_->size() - out_pos_;
  761. if(out_ != list_.iterator_to(list_.back()))
  762. {
  763. out_end_ = out_->size();
  764. reuse.splice(reuse.end(), list_,
  765. std::next(out_), list_.end());
  766. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  767. debug_check();
  768. #endif
  769. }
  770. auto const avail = out_->size() - out_pos_;
  771. if(n > avail)
  772. {
  773. out_end_ = out_->size();
  774. n -= avail;
  775. }
  776. else
  777. {
  778. out_end_ = out_pos_ + n;
  779. n = 0;
  780. }
  781. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  782. debug_check();
  783. #endif
  784. }
  785. // get space from reuse buffers
  786. while(n > 0 && ! reuse.empty())
  787. {
  788. auto& e = reuse.front();
  789. reuse.erase(reuse.iterator_to(e));
  790. list_.push_back(e);
  791. total += e.size();
  792. if(n > e.size())
  793. {
  794. out_end_ = e.size();
  795. n -= e.size();
  796. }
  797. else
  798. {
  799. out_end_ = n;
  800. n = 0;
  801. }
  802. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  803. debug_check();
  804. #endif
  805. }
  806. BOOST_ASSERT(total <= max_);
  807. if(! reuse.empty() || n > 0)
  808. {
  809. destroy(reuse);
  810. if(n > 0)
  811. {
  812. std::size_t const growth_factor = 2;
  813. std::size_t altn = in_size_ * growth_factor;
  814. // Overflow detection:
  815. if(in_size_ > altn)
  816. altn = (std::numeric_limits<std::size_t>::max)();
  817. else
  818. altn = (std::max<std::size_t>)(512, altn);
  819. auto const size =
  820. (std::min<std::size_t>)(
  821. max_ - total,
  822. (std::max<std::size_t>)(n, altn));
  823. auto& e = alloc(size);
  824. list_.push_back(e);
  825. if(out_ == list_.end())
  826. out_ = list_.iterator_to(e);
  827. out_end_ = n;
  828. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  829. debug_check();
  830. #endif
  831. }
  832. }
  833. auto const result =
  834. mutable_buffers_type(
  835. *this, in_size_, n0);
  836. BOOST_ASSERT(
  837. net::buffer_size(result) == n0);
  838. return result;
  839. }
  840. template<class Allocator>
  841. void
  842. basic_multi_buffer<Allocator>::
  843. commit(size_type n) noexcept
  844. {
  845. if(list_.empty())
  846. return;
  847. if(out_ == list_.end())
  848. return;
  849. auto const back =
  850. list_.iterator_to(list_.back());
  851. while(out_ != back)
  852. {
  853. auto const avail =
  854. out_->size() - out_pos_;
  855. if(n < avail)
  856. {
  857. out_pos_ += n;
  858. in_size_ += n;
  859. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  860. debug_check();
  861. #endif
  862. return;
  863. }
  864. ++out_;
  865. n -= avail;
  866. out_pos_ = 0;
  867. in_size_ += avail;
  868. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  869. debug_check();
  870. #endif
  871. }
  872. n = (std::min)(n, out_end_ - out_pos_);
  873. out_pos_ += n;
  874. in_size_ += n;
  875. if(out_pos_ == out_->size())
  876. {
  877. ++out_;
  878. out_pos_ = 0;
  879. out_end_ = 0;
  880. }
  881. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  882. debug_check();
  883. #endif
  884. }
  885. template<class Allocator>
  886. void
  887. basic_multi_buffer<Allocator>::
  888. consume(size_type n) noexcept
  889. {
  890. if(list_.empty())
  891. return;
  892. for(;;)
  893. {
  894. if(list_.begin() != out_)
  895. {
  896. auto const avail =
  897. list_.front().size() - in_pos_;
  898. if(n < avail)
  899. {
  900. in_size_ -= n;
  901. in_pos_ += n;
  902. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  903. debug_check();
  904. #endif
  905. break;
  906. }
  907. n -= avail;
  908. in_size_ -= avail;
  909. in_pos_ = 0;
  910. auto& e = list_.front();
  911. list_.erase(list_.iterator_to(e));
  912. destroy(e);
  913. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  914. debug_check();
  915. #endif
  916. }
  917. else
  918. {
  919. auto const avail = out_pos_ - in_pos_;
  920. if(n < avail)
  921. {
  922. in_size_ -= n;
  923. in_pos_ += n;
  924. }
  925. else
  926. {
  927. in_size_ = 0;
  928. if(out_ != list_.iterator_to(list_.back()) ||
  929. out_pos_ != out_end_)
  930. {
  931. in_pos_ = out_pos_;
  932. }
  933. else
  934. {
  935. // Input and output sequences are empty, reuse buffer.
  936. // Alternatively we could deallocate it.
  937. in_pos_ = 0;
  938. out_pos_ = 0;
  939. out_end_ = 0;
  940. }
  941. }
  942. #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
  943. debug_check();
  944. #endif
  945. break;
  946. }
  947. }
  948. }
  949. template<class Allocator>
  950. template<class OtherAlloc>
  951. void
  952. basic_multi_buffer<Allocator>::
  953. copy_from(basic_multi_buffer<OtherAlloc> const& other)
  954. {
  955. clear();
  956. max_ = other.max_;
  957. if(other.size() == 0)
  958. return;
  959. commit(net::buffer_copy(
  960. prepare(other.size()), other.data()));
  961. }
  962. template<class Allocator>
  963. void
  964. basic_multi_buffer<Allocator>::
  965. move_assign(basic_multi_buffer& other, std::true_type) noexcept
  966. {
  967. this->get() = std::move(other.get());
  968. auto const at_end =
  969. other.out_ == other.list_.end();
  970. list_ = std::move(other.list_);
  971. out_ = at_end ? list_.end() : other.out_;
  972. in_size_ = other.in_size_;
  973. in_pos_ = other.in_pos_;
  974. out_pos_ = other.out_pos_;
  975. out_end_ = other.out_end_;
  976. max_ = other.max_;
  977. other.in_size_ = 0;
  978. other.out_ = other.list_.end();
  979. other.in_pos_ = 0;
  980. other.out_pos_ = 0;
  981. other.out_end_ = 0;
  982. }
  983. template<class Allocator>
  984. void
  985. basic_multi_buffer<Allocator>::
  986. move_assign(basic_multi_buffer& other, std::false_type)
  987. {
  988. if(this->get() != other.get())
  989. {
  990. copy_from(other);
  991. }
  992. else
  993. {
  994. move_assign(other, std::true_type{});
  995. }
  996. }
  997. template<class Allocator>
  998. void
  999. basic_multi_buffer<Allocator>::
  1000. copy_assign(
  1001. basic_multi_buffer const& other, std::false_type)
  1002. {
  1003. copy_from(other);
  1004. }
  1005. template<class Allocator>
  1006. void
  1007. basic_multi_buffer<Allocator>::
  1008. copy_assign(
  1009. basic_multi_buffer const& other, std::true_type)
  1010. {
  1011. clear();
  1012. this->get() = other.get();
  1013. copy_from(other);
  1014. }
  1015. template<class Allocator>
  1016. void
  1017. basic_multi_buffer<Allocator>::
  1018. swap(basic_multi_buffer& other) noexcept
  1019. {
  1020. swap(other, typename
  1021. alloc_traits::propagate_on_container_swap{});
  1022. }
  1023. template<class Allocator>
  1024. void
  1025. basic_multi_buffer<Allocator>::
  1026. swap(basic_multi_buffer& other, std::true_type) noexcept
  1027. {
  1028. using std::swap;
  1029. auto const at_end0 =
  1030. out_ == list_.end();
  1031. auto const at_end1 =
  1032. other.out_ == other.list_.end();
  1033. swap(this->get(), other.get());
  1034. swap(list_, other.list_);
  1035. swap(out_, other.out_);
  1036. if(at_end1)
  1037. out_ = list_.end();
  1038. if(at_end0)
  1039. other.out_ = other.list_.end();
  1040. swap(in_size_, other.in_size_);
  1041. swap(in_pos_, other.in_pos_);
  1042. swap(out_pos_, other.out_pos_);
  1043. swap(out_end_, other.out_end_);
  1044. }
  1045. template<class Allocator>
  1046. void
  1047. basic_multi_buffer<Allocator>::
  1048. swap(basic_multi_buffer& other, std::false_type) noexcept
  1049. {
  1050. BOOST_ASSERT(this->get() == other.get());
  1051. using std::swap;
  1052. auto const at_end0 =
  1053. out_ == list_.end();
  1054. auto const at_end1 =
  1055. other.out_ == other.list_.end();
  1056. swap(list_, other.list_);
  1057. swap(out_, other.out_);
  1058. if(at_end1)
  1059. out_ = list_.end();
  1060. if(at_end0)
  1061. other.out_ = other.list_.end();
  1062. swap(in_size_, other.in_size_);
  1063. swap(in_pos_, other.in_pos_);
  1064. swap(out_pos_, other.out_pos_);
  1065. swap(out_end_, other.out_end_);
  1066. }
  1067. template<class Allocator>
  1068. void
  1069. swap(
  1070. basic_multi_buffer<Allocator>& lhs,
  1071. basic_multi_buffer<Allocator>& rhs) noexcept
  1072. {
  1073. lhs.swap(rhs);
  1074. }
  1075. template<class Allocator>
  1076. void
  1077. basic_multi_buffer<Allocator>::
  1078. destroy(list_type& list) noexcept
  1079. {
  1080. for(auto it = list.begin();
  1081. it != list.end();)
  1082. destroy(*it++);
  1083. }
  1084. template<class Allocator>
  1085. void
  1086. basic_multi_buffer<Allocator>::
  1087. destroy(element& e)
  1088. {
  1089. auto a = rebind_type{this->get()};
  1090. auto const n =
  1091. (sizeof(element) + e.size() +
  1092. sizeof(align_type) - 1) /
  1093. sizeof(align_type);
  1094. e.~element();
  1095. alloc_traits::deallocate(a,
  1096. reinterpret_cast<align_type*>(&e), n);
  1097. }
  1098. template<class Allocator>
  1099. auto
  1100. basic_multi_buffer<Allocator>::
  1101. alloc(std::size_t size) ->
  1102. element&
  1103. {
  1104. if(size > alloc_traits::max_size(this->get()))
  1105. BOOST_THROW_EXCEPTION(std::length_error(
  1106. "A basic_multi_buffer exceeded the allocator's maximum size"));
  1107. auto a = rebind_type{this->get()};
  1108. auto const p = alloc_traits::allocate(a,
  1109. (sizeof(element) + size + sizeof(align_type) - 1) /
  1110. sizeof(align_type));
  1111. return *(::new(p) element(size));
  1112. }
  1113. template<class Allocator>
  1114. void
  1115. basic_multi_buffer<Allocator>::
  1116. debug_check() const
  1117. {
  1118. #ifndef NDEBUG
  1119. BOOST_ASSERT(buffer_bytes(data()) == in_size_);
  1120. if(list_.empty())
  1121. {
  1122. BOOST_ASSERT(in_pos_ == 0);
  1123. BOOST_ASSERT(in_size_ == 0);
  1124. BOOST_ASSERT(out_pos_ == 0);
  1125. BOOST_ASSERT(out_end_ == 0);
  1126. BOOST_ASSERT(out_ == list_.end());
  1127. return;
  1128. }
  1129. auto const& front = list_.front();
  1130. BOOST_ASSERT(in_pos_ < front.size());
  1131. if(out_ == list_.end())
  1132. {
  1133. BOOST_ASSERT(out_pos_ == 0);
  1134. BOOST_ASSERT(out_end_ == 0);
  1135. }
  1136. else
  1137. {
  1138. auto const& out = *out_;
  1139. auto const& back = list_.back();
  1140. BOOST_ASSERT(out_end_ <= back.size());
  1141. BOOST_ASSERT(out_pos_ < out.size());
  1142. BOOST_ASSERT(&out != &front || out_pos_ >= in_pos_);
  1143. BOOST_ASSERT(&out != &front || out_pos_ - in_pos_ == in_size_);
  1144. BOOST_ASSERT(&out != &back || out_pos_ <= out_end_);
  1145. }
  1146. #endif
  1147. }
  1148. } // beast
  1149. } // boost
  1150. #endif