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