GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/buffer.hpp
Date: 2023-01-15 07:18:31
Exec Total Coverage
Lines: 137 154 89.0%
Functions: 55 55 100.0%
Branches: 29 40 72.5%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/CPPAlliance/http_proto
8 //
9
10 #ifndef BOOST_HTTP_PROTO_BUFFER_HPP
11 #define BOOST_HTTP_PROTO_BUFFER_HPP
12
13 #include <boost/http_proto/detail/config.hpp>
14 #include <boost/assert.hpp>
15 #include <boost/config/workaround.hpp>
16 #include <boost/type_traits/make_void.hpp>
17 #include <cstdlib>
18 #include <cstring>
19 #include <type_traits>
20 #include <utility>
21
22 namespace boost {
23 namespace http_proto {
24
25 //------------------------------------------------
26
27 /** Determine if T is a possibly-const buffer.
28 */
29 #if BOOST_HTTP_PROTO_DOCS
30 template<bool isConst, class T>
31 struct is_buffer
32 : std::integral_constant<bool, ...>{};
33 #else
34
35 template<
36 bool isConst, class T,
37 class = void>
38 struct is_buffer : std::false_type {};
39
40 template<
41 bool isConst, class T>
42 struct is_buffer<
43 isConst, T, boost::void_t<decltype(
44 std::declval<std::size_t&>() =
45 std::declval<T const&>().size()
46 ),
47 typename std::enable_if<
48 std::is_same<
49 void*, decltype(
50 std::declval<T const&>().data())
51 >::value || (
52 std::is_same<
53 void const*, decltype(
54 std::declval<T const&>().data())
55 >::value && isConst)
56 >::type
57 >> : std::is_copy_constructible<T>
58 {
59 };
60
61 #endif
62
63 /** Determine if T is a const buffer.
64 */
65 template<class T>
66 using is_const_buffer = is_buffer<true, T>;
67
68 /** Determine if T is a mutable buffer.
69 */
70 template<class T>
71 using is_mutable_buffer = is_buffer<false, T>;
72
73 //------------------------------------------------
74
75 /** Determine if T is a buffer sequence.
76 */
77 #if BOOST_HTTP_PROTO_DOCS
78 template<bool isConst, class T>
79 struct is_buffers
80 : std::integral_constant<bool, ...>{};
81 #else
82
83 template<
84 bool isConst, class T,
85 class = void>
86 struct is_buffers
87 : is_buffer<isConst, T>
88 {
89 };
90
91 template<
92 bool isConst, class T>
93 struct is_buffers<
94 isConst, T, boost::void_t<
95 typename std::enable_if<
96 is_buffer<
97 isConst, decltype(
98 *std::declval<T const&>().begin())
99 >::value &&
100 is_buffer<
101 isConst, decltype(
102 *std::declval<T const&>().end())
103 >::value
104 >::type
105 >> : std::is_move_constructible<T>
106 {
107 };
108
109 #endif
110
111 /** Determine if T is a const buffers.
112 */
113 template<class T>
114 using is_const_buffers = is_buffers<true, T>;
115
116 /** Determine if T is a mutable buffers.
117 */
118 template<class T>
119 using is_mutable_buffers = is_buffers<false, T>;
120
121 //------------------------------------------------
122
123 class mutable_buffer
124 {
125 void* p_ = nullptr;
126 std::size_t n_ = 0;
127
128 public:
129 711 mutable_buffer() = default;
130 mutable_buffer(
131 mutable_buffer const&) = default;
132 mutable_buffer& operator=(
133 mutable_buffer const&) = default;
134
135 12727 mutable_buffer(
136 void* data,
137 std::size_t size) noexcept
138 12727 : p_(data)
139 12727 , n_(size)
140 {
141 12727 }
142
143 template<
144 class MutableBuffer
145 #ifndef BOOST_HTTP_PROTO_DOCS
146 ,class = typename std::enable_if<
147 is_mutable_buffer<MutableBuffer
148 >::value>::type
149 #endif
150 >
151 2 mutable_buffer(
152 MutableBuffer const& b) noexcept
153 : p_(b.data())
154 2 , n_(b.size())
155 {
156 2 }
157
158 void*
159 12288 data() const noexcept
160 {
161 12288 return p_;
162 }
163
164 std::size_t
165 28616 size() const noexcept
166 {
167 28616 return n_;
168 }
169
170 mutable_buffer&
171 2 operator+=(std::size_t n) noexcept
172 {
173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(n >= n_)
174 {
175 p_ = static_cast<
176 char*>(p_) + n_;
177 n_ = 0;
178 return *this;
179 }
180 2 p_ = static_cast<
181 2 char*>(p_) + n;
182 2 n_ -= n;
183 2 return *this;
184 }
185
186 friend
187 mutable_buffer
188 4647 operator+(
189 mutable_buffer const& b,
190 std::size_t n) noexcept
191 {
192
1/2
✓ Branch 1 taken 4647 times.
✗ Branch 2 not taken.
4647 if(n < b.size())
193 return {
194 static_cast<char*>(
195 4647 b.data()) + n,
196 4647 b.size() - n };
197 return {
198 static_cast<char*>(
199 b.data()) + b.size(),
200 0 };
201 }
202
203 friend
204 mutable_buffer
205 1 operator+(
206 std::size_t n,
207 mutable_buffer const& b) noexcept
208 {
209
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(n < b.size())
210 return {
211 static_cast<char*>(
212 1 b.data()) + n,
213 1 b.size() - n };
214 return {
215 static_cast<char*>(
216 b.data()) + b.size(),
217 0 };
218 }
219 };
220
221 //------------------------------------------------
222
223 class const_buffer
224 {
225 void const* p_ = nullptr;
226 std::size_t n_ = 0;
227
228 public:
229 30 const_buffer() = default;
230 const_buffer(
231 const_buffer const&) = default;
232 const_buffer& operator=(
233 const_buffer const&) = default;
234
235 9775 const_buffer(
236 void const* data,
237 std::size_t size) noexcept
238 9775 : p_(data)
239 9775 , n_(size)
240 {
241 9775 }
242
243 template<
244 class ConstBuffer
245 #ifndef BOOST_HTTP_PROTO_DOCS
246 ,class = typename std::enable_if<
247 is_const_buffer<ConstBuffer
248 >::value>::type
249 #endif
250 >
251 29 const_buffer(
252 ConstBuffer const& b) noexcept
253 : p_(b.data())
254 29 , n_(b.size())
255 {
256 29 }
257
258 void const*
259 9306 data() const noexcept
260 {
261 9306 return p_;
262 }
263
264 std::size_t
265 23956 size() const noexcept
266 {
267 23956 return n_;
268 }
269
270 const_buffer&
271 2 operator+=(std::size_t n) noexcept
272 {
273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(n >= n_)
274 {
275 p_ = static_cast<
276 char const*>(p_) + n_;
277 n_ = 0;
278 return *this;
279 }
280 2 p_ = static_cast<
281 2 char const*>(p_) + n;
282 2 n_ -= n;
283 2 return *this;
284 }
285
286 friend
287 const_buffer
288 4647 operator+(
289 const_buffer const& b,
290 std::size_t n) noexcept
291 {
292
1/2
✓ Branch 1 taken 4647 times.
✗ Branch 2 not taken.
4647 if(n < b.size())
293 return {
294 static_cast<char const*>(
295 4647 b.data()) + n,
296 4647 b.size() - n };
297 return {
298 static_cast<char const*>(
299 b.data()) + b.size(),
300 0 };
301 }
302
303 friend
304 const_buffer
305 1 operator+(
306 std::size_t n,
307 const_buffer const& b) noexcept
308 {
309
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(n < b.size())
310 return {
311 static_cast<char const*>(
312 1 b.data()) + n,
313 1 b.size() - n };
314 return {
315 static_cast<char const*>(
316 b.data()) + b.size(),
317 0 };
318 }
319 };
320
321 //------------------------------------------------
322
323 /** A MutableBuffer of length 1
324 */
325 class mutable_buffers_1
326 {
327 mutable_buffer mb_;
328
329 public:
330 using value_type =
331 mutable_buffer;
332
333 using const_iterator =
334 mutable_buffer const*;
335
336 2 mutable_buffers_1() = default;
337
338 explicit
339 15 mutable_buffers_1(
340 mutable_buffer mb) noexcept
341 15 : mb_(mb)
342 {
343 15 }
344
345 mutable_buffers_1&
346 operator=(
347 mutable_buffers_1 const&) = default;
348
349 const_iterator
350 21 begin() const noexcept
351 {
352 21 return &mb_;
353 }
354
355 const_iterator
356 21 end() const noexcept
357 {
358 21 return &mb_ + 1;
359 }
360 };
361
362 /** A ConstBuffer of length 1
363 */
364 class const_buffers_1
365 {
366 const_buffer cb_;
367
368 public:
369 using value_type =
370 const_buffer;
371
372 using const_iterator =
373 const_buffer const*;
374
375 2 const_buffers_1() = default;
376
377 explicit
378 15 const_buffers_1(
379 const_buffer cb) noexcept
380 15 : cb_(cb)
381 {
382 15 }
383
384 const_buffers_1&
385 operator=(const_buffers_1 const&) = default;
386
387 const_iterator
388 21 begin() const noexcept
389 {
390 21 return &cb_;
391 }
392
393 const_iterator
394 21 end() const noexcept
395 {
396 21 return &cb_ + 1;
397 }
398 };
399
400 //------------------------------------------------
401
402 template<
403 class ConstBuffer
404 #ifndef BOOST_HTTP_PROTO_DOCS
405 ,class = typename std::enable_if<
406 is_const_buffer<
407 ConstBuffer>::value &&
408 ! is_mutable_buffer<
409 ConstBuffer>::value
410 >::type
411 #endif
412 >
413 auto
414 15 make_buffers(
415 ConstBuffer const& b) ->
416 const_buffers_1
417 {
418 return const_buffers_1(
419 15 const_buffer(b));
420 }
421
422 template<
423 class MutableBuffer
424 #ifndef BOOST_HTTP_PROTO_DOCS
425 ,class = typename std::enable_if<
426 is_mutable_buffer<
427 MutableBuffer>::value
428 >::type
429 #endif
430 >
431 auto
432 15 make_buffers(
433 MutableBuffer const& b) ->
434 mutable_buffers_1
435 {
436 return mutable_buffers_1(
437 15 mutable_buffer(b));
438 }
439
440 template<
441 class Buffers
442 #ifndef BOOST_HTTP_PROTO_DOCS
443 ,class = typename std::enable_if<
444 ! is_const_buffer<
445 Buffers>::value &&
446 is_const_buffers<
447 Buffers>::value
448 >::type
449 #endif
450 >
451 auto
452 10223 make_buffers(
453 Buffers&& b) ->
454 Buffers&&
455 {
456 return std::forward<
457 10223 Buffers>(b);
458 }
459
460 //------------------------------------------------
461
462 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
463 # pragma warning (push)
464 # pragma warning (disable: 4521) // multiple copy constructors specified
465 # pragma warning (disable: 4522) // multiple assignment operators specified
466 #endif
467
468 template<bool isConst>
469 class buffers_pair
470 {
471 public:
472 // VFALCO: This type is public otherwise
473 // asio::buffers_iterator won't compile.
474 using value_type = typename
475 std::conditional<isConst,
476 const_buffer,
477 mutable_buffer>::type;
478
479 using const_iterator = value_type const*;
480
481 buffers_pair() = default;
482
483 #if defined(BOOST_HTTP_PROTO_DOCS) || ( \
484 ! BOOST_WORKAROUND(BOOST_MSVC, < 1910))
485 buffers_pair(
486 buffers_pair const& other) = default;
487 buffers_pair& operator=(
488 buffers_pair const& other) = default;
489
490 #else
491 buffers_pair(
492 buffers_pair const& other)
493 : buffers_pair(
494 *other.begin(),
495 *(other.begin() + 1))
496 {
497 }
498
499 buffers_pair&
500 operator=(buffers_pair const& other)
501 {
502 b_[0] = other.b_[0];
503 b_[1] = other.b_[1];
504 return *this;
505 }
506 #endif
507
508 // const pair construction
509 // from mutable mutable pair
510 template<
511 bool isConst_ = isConst,
512 class = typename std::enable_if<
513 isConst_>::type>
514 buffers_pair(
515 buffers_pair<false> const& other)
516 : buffers_pair(
517 other.b_[0],
518 other.b_[1])
519 {
520 }
521
522 // const pair assignment
523 // from mutable mutable pair
524 template<
525 bool isConst_ = isConst,
526 class = typename std::enable_if<
527 isConst_>::type>
528 buffers_pair&
529 operator=(
530 buffers_pair<false> const& other)
531 {
532 b_[0] = other.b_[0];
533 b_[1] = other.b_[1];
534 return *this;
535 }
536
537 10172 buffers_pair(
538 value_type b0,
539 value_type b1) noexcept
540 10172 {
541
2/2
✓ Branch 1 taken 4696 times.
✓ Branch 2 taken 390 times.
10172 if(b0.size() > 0)
542 {
543 9392 b_[0] = b0;
544 9392 b_[1] = b1;
545 }
546 else
547 {
548 780 b_[0] = b1;
549 }
550 10172 }
551
552 const_buffer
553 16 operator[](
554 std::size_t i) const noexcept
555 {
556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
16 BOOST_ASSERT(i < 2);
557 16 return b_[i];
558 }
559
560 const_iterator
561 10174 begin() const noexcept
562 {
563 10174 return b_;
564 }
565
566 const_iterator
567 10174 end() const noexcept
568 {
569
2/2
✓ Branch 1 taken 4681 times.
✓ Branch 2 taken 408 times.
10174 if(b_[1].size() > 0)
570 9362 return &b_[2];
571
1/2
✓ Branch 1 taken 408 times.
✗ Branch 2 not taken.
812 if(b_[0].size() > 0)
572 812 return &b_[1];
573 return b_;
574 }
575
576 private:
577 value_type b_[2];
578 };
579
580 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
581 # pragma warning (pop)
582 #endif
583
584 /** A mutable buffers pair
585 */
586 using mutable_buffers_pair =
587 buffers_pair<false>;
588
589 /** A const buffers pair
590 */
591 using const_buffers_pair =
592 buffers_pair<true>;
593
594 //------------------------------------------------
595
596 /** Return the total octets in a buffer sequence
597 */
598 template<
599 class ConstBuffers
600 #ifndef BOOST_HTTP_PROTO_DOCS
601 , class = typename std::enable_if<
602 is_const_buffers<ConstBuffers>::value
603 >::type
604 #endif
605 >
606 std::size_t
607 25 buffer_size(
608 ConstBuffers const& buffers) noexcept
609 {
610 25 std::size_t n = 0;
611
2/2
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 20 times.
61 for(const_buffer b
612 25 : make_buffers(buffers))
613 36 n += b.size();
614 25 return n;
615 }
616
617 //------------------------------------------------
618
619 /** Copy buffer contents
620 */
621 template<
622 class MutableBuffers,
623 class ConstBuffers>
624 std::size_t
625 2557 buffer_copy(
626 MutableBuffers const& to,
627 ConstBuffers const& from,
628 std::size_t at_most =
629 std::size_t(-1)) noexcept
630 {
631 // If you get a compile error here it
632 // means that one or both of your types
633 // do not meet the requirements.
634 static_assert(
635 is_mutable_buffers<MutableBuffers>::value &&
636 is_const_buffers<ConstBuffers>::value,
637 "Type requirements not met");
638
639 2557 std::size_t total = 0;
640 2557 std::size_t pos0 = 0;
641 2557 std::size_t pos1 = 0;
642 2557 auto const& bs0 = (make_buffers)(from);
643 2557 auto const& bs1 = (make_buffers)(to);
644 2557 auto const end0 = bs0.end();
645 2557 auto const end1 = bs1.end();
646 2557 auto it0 = bs0.begin();
647 2557 auto it1 = bs1.begin();
648 4646 while(
649
2/2
✓ Branch 0 taken 4623 times.
✓ Branch 1 taken 176 times.
4837 total < at_most &&
650
3/4
✓ Branch 0 taken 4799 times.
✓ Branch 1 taken 2366 times.
✓ Branch 2 taken 4623 times.
✗ Branch 3 not taken.
11850 it0 != end0 &&
651 it1 != end1)
652 {
653 const_buffer b0 =
654 4646 const_buffer(*it0) + pos0;
655 mutable_buffer b1 =
656 4646 mutable_buffer(*it1) + pos1;
657 std::size_t amount =
658 26688 [&]
659 {
660 4646 std::size_t n = b0.size();
661
3/4
✓ Branch 1 taken 1730 times.
✓ Branch 2 taken 2912 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4646 if( n > b1.size())
662 1730 n = b1.size();
663
3/4
✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 2914 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4646 if( n > at_most - total)
664 1728 n = at_most - total;
665 4646 std::memcpy(
666 b1.data(),
667 b0.data(),
668 n);
669 4646 return n;
670 4646 }();
671 4646 total += amount;
672
2/2
✓ Branch 1 taken 1671 times.
✓ Branch 2 taken 2952 times.
4646 if(amount == b1.size())
673 {
674 1682 ++it1;
675 1682 pos1 = 0;
676 }
677 else
678 {
679 2964 pos1 += amount;
680 }
681
2/2
✓ Branch 1 taken 1671 times.
✓ Branch 2 taken 2952 times.
4646 if(amount == b0.size())
682 {
683 1694 ++it0;
684 1694 pos0 = 0;
685 }
686 else
687 {
688 2952 pos0 += amount;
689 }
690 }
691 2557 return total;
692 }
693
694 //------------------------------------------------
695
696 // VFALCO GARBAGE
697 class mutable_buffers
698 {
699 mutable_buffer const* p_ = nullptr;
700 std::size_t n_ = 0;
701
702 public:
703 using value_type = mutable_buffer;
704
705 using iterator = value_type const*;
706
707 mutable_buffers() = default;
708
709 mutable_buffers(
710 mutable_buffers const&) = default;
711
712 mutable_buffers& operator=(
713 mutable_buffers const&) = default;
714
715 2969 mutable_buffers(
716 value_type const* p,
717 std::size_t n) noexcept
718 2969 : p_(p)
719 2969 , n_(n)
720 {
721 2969 }
722
723 std::size_t
724 size() const noexcept
725 {
726 return n_;
727 }
728
729 iterator
730 2969 begin() const noexcept
731 {
732 2969 return p_;
733 }
734
735 iterator
736 end() const noexcept
737 {
738 return p_ + n_;
739 }
740 };
741
742 } // http_proto
743 } // boost
744
745 #endif
746