multi_buffer.hpp 29 KB

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