GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/buffer.hpp
Date: 2023-01-26 23:44:13
Exec Total Coverage
Lines: 111 129 86.0%
Functions: 36 37 97.3%
Branches: 28 38 73.7%

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 using const_iterator =
130 mutable_buffer const*;
131
132 3023 mutable_buffer() = default;
133 mutable_buffer(
134 mutable_buffer const&) = default;
135 mutable_buffer& operator=(
136 mutable_buffer const&) = default;
137
138 12776 mutable_buffer(
139 void* data,
140 std::size_t size) noexcept
141 12776 : p_(data)
142 12776 , n_(size)
143 {
144 12776 }
145
146 template<
147 class MutableBuffer
148 #ifndef BOOST_HTTP_PROTO_DOCS
149 ,class = typename std::enable_if<
150 is_mutable_buffer<MutableBuffer
151 >::value>::type
152 #endif
153 >
154 2 mutable_buffer(
155 MutableBuffer const& b) noexcept
156 : p_(b.data())
157 2 , n_(b.size())
158 {
159 2 }
160
161 void*
162 12335 data() const noexcept
163 {
164 12335 return p_;
165 }
166
167 std::size_t
168 31673 size() const noexcept
169 {
170 31673 return n_;
171 }
172
173 const_iterator
174 21 begin() const noexcept
175 {
176 21 return this;
177 }
178
179 const_iterator
180 21 end() const noexcept
181 {
182 21 return this + 1;
183 }
184
185 mutable_buffer&
186 3 operator+=(std::size_t n) noexcept
187 {
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(n >= n_)
189 {
190 p_ = static_cast<
191 char*>(p_) + n_;
192 n_ = 0;
193 return *this;
194 }
195 3 p_ = static_cast<
196 3 char*>(p_) + n;
197 3 n_ -= n;
198 3 return *this;
199 }
200
201 friend
202 mutable_buffer
203 4647 operator+(
204 mutable_buffer const& b,
205 std::size_t n) noexcept
206 {
207
1/2
✓ Branch 1 taken 4647 times.
✗ Branch 2 not taken.
4647 if(n < b.size())
208 return {
209 static_cast<char*>(
210 4647 b.data()) + n,
211 4647 b.size() - n };
212 return {
213 static_cast<char*>(
214 b.data()) + b.size(),
215 0 };
216 }
217
218 friend
219 mutable_buffer
220 1 operator+(
221 std::size_t n,
222 mutable_buffer const& b) noexcept
223 {
224
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(n < b.size())
225 return {
226 static_cast<char*>(
227 1 b.data()) + n,
228 1 b.size() - n };
229 return {
230 static_cast<char*>(
231 b.data()) + b.size(),
232 0 };
233 }
234 };
235
236 //------------------------------------------------
237
238 class const_buffer
239 {
240 void const* p_ = nullptr;
241 std::size_t n_ = 0;
242
243 public:
244 using const_iterator =
245 const_buffer const*;
246
247 29 const_buffer() = default;
248 const_buffer(
249 const_buffer const&) = default;
250 const_buffer& operator=(
251 const_buffer const&) = default;
252
253 9769 const_buffer(
254 void const* data,
255 std::size_t size) noexcept
256 9769 : p_(data)
257 9769 , n_(size)
258 {
259 9769 }
260
261 template<
262 class ConstBuffer
263 #ifndef BOOST_HTTP_PROTO_DOCS
264 ,class = typename std::enable_if<
265 is_const_buffer<ConstBuffer
266 >::value>::type
267 #endif
268 >
269 24 const_buffer(
270 ConstBuffer const& b) noexcept
271 : p_(b.data())
272 24 , n_(b.size())
273 {
274 24 }
275
276 void const*
277 9306 data() const noexcept
278 {
279 9306 return p_;
280 }
281
282 std::size_t
283 23972 size() const noexcept
284 {
285 23972 return n_;
286 }
287
288 const_iterator
289 17 begin() const noexcept
290 {
291 17 return this;
292 }
293
294 const_iterator
295 17 end() const noexcept
296 {
297 17 return this + 1;
298 }
299
300 const_buffer&
301 2 operator+=(std::size_t n) noexcept
302 {
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(n >= n_)
304 {
305 p_ = static_cast<
306 char const*>(p_) + n_;
307 n_ = 0;
308 return *this;
309 }
310 2 p_ = static_cast<
311 2 char const*>(p_) + n;
312 2 n_ -= n;
313 2 return *this;
314 }
315
316 friend
317 const_buffer
318 4647 operator+(
319 const_buffer const& b,
320 std::size_t n) noexcept
321 {
322
1/2
✓ Branch 1 taken 4647 times.
✗ Branch 2 not taken.
4647 if(n < b.size())
323 return {
324 static_cast<char const*>(
325 4647 b.data()) + n,
326 4647 b.size() - n };
327 return {
328 static_cast<char const*>(
329 b.data()) + b.size(),
330 0 };
331 }
332
333 friend
334 const_buffer
335 1 operator+(
336 std::size_t n,
337 const_buffer const& b) noexcept
338 {
339
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if(n < b.size())
340 return {
341 static_cast<char const*>(
342 1 b.data()) + n,
343 1 b.size() - n };
344 return {
345 static_cast<char const*>(
346 b.data()) + b.size(),
347 0 };
348 }
349 };
350
351 //------------------------------------------------
352
353 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
354 # pragma warning (push)
355 # pragma warning (disable: 4521) // multiple copy constructors specified
356 # pragma warning (disable: 4522) // multiple assignment operators specified
357 #endif
358
359 template<bool isConst>
360 class buffers_pair
361 {
362 public:
363 // VFALCO: This type is public otherwise
364 // asio::buffers_iterator won't compile.
365 using value_type = typename
366 std::conditional<isConst,
367 const_buffer,
368 mutable_buffer>::type;
369
370 using const_iterator = value_type const*;
371
372 buffers_pair() = default;
373
374 #if defined(BOOST_HTTP_PROTO_DOCS) || ( \
375 ! BOOST_WORKAROUND(BOOST_MSVC, < 1910))
376 buffers_pair(
377 buffers_pair const& other) = default;
378 buffers_pair& operator=(
379 buffers_pair const& other) = default;
380
381 #else
382 buffers_pair(
383 buffers_pair const& other)
384 : buffers_pair(
385 *other.begin(),
386 *(other.begin() + 1))
387 {
388 }
389
390 buffers_pair&
391 operator=(buffers_pair const& other)
392 {
393 b_[0] = other.b_[0];
394 b_[1] = other.b_[1];
395 return *this;
396 }
397 #endif
398
399 // const pair construction
400 // from mutable mutable pair
401 template<
402 bool isConst_ = isConst,
403 class = typename std::enable_if<
404 isConst_>::type>
405 buffers_pair(
406 buffers_pair<false> const& other)
407 : buffers_pair(
408 other.b_[0],
409 other.b_[1])
410 {
411 }
412
413 // const pair assignment
414 // from mutable mutable pair
415 template<
416 bool isConst_ = isConst,
417 class = typename std::enable_if<
418 isConst_>::type>
419 buffers_pair&
420 operator=(
421 buffers_pair<false> const& other)
422 {
423 b_[0] = other.b_[0];
424 b_[1] = other.b_[1];
425 return *this;
426 }
427
428 16206 buffers_pair(
429 value_type b0,
430 value_type b1) noexcept
431 16206 {
432
2/2
✓ Branch 1 taken 7713 times.
✓ Branch 2 taken 390 times.
16206 if(b0.size() > 0)
433 {
434 15426 b_[0] = b0;
435 15426 b_[1] = b1;
436 }
437 else
438 {
439 780 b_[0] = b1;
440 }
441 16206 }
442
443 const_buffer
444 operator[](
445 std::size_t i) const noexcept
446 {
447 BOOST_ASSERT(i < 2);
448 return b_[i];
449 }
450
451 const_iterator
452 13187 begin() const noexcept
453 {
454 13187 return b_;
455 }
456
457 const_iterator
458 10166 end() const noexcept
459 {
460
2/2
✓ Branch 1 taken 4681 times.
✓ Branch 2 taken 404 times.
10166 if(b_[1].size() > 0)
461 9362 return &b_[2];
462
1/2
✓ Branch 1 taken 404 times.
✗ Branch 2 not taken.
804 if(b_[0].size() > 0)
463 804 return &b_[1];
464 return b_;
465 }
466
467 private:
468 value_type b_[2];
469 };
470
471 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
472 # pragma warning (pop)
473 #endif
474
475 /** A mutable buffers pair
476 */
477 using mutable_buffers_pair =
478 buffers_pair<false>;
479
480 /** A const buffers pair
481 */
482 using const_buffers_pair =
483 buffers_pair<true>;
484
485 //------------------------------------------------
486
487 /** Return the total octets in a buffer sequence
488 */
489 template<
490 class ConstBuffers
491 #ifndef BOOST_HTTP_PROTO_DOCS
492 , class = typename std::enable_if<
493 is_const_buffers<ConstBuffers>::value
494 >::type
495 #endif
496 >
497 std::size_t
498 30 buffer_size(
499 ConstBuffers const& buffers) noexcept
500 {
501 30 std::size_t n = 0;
502
2/2
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 21 times.
74 for(const_buffer b : buffers)
503 44 n += b.size();
504 30 return n;
505 }
506
507 //------------------------------------------------
508
509 /** Copy buffer contents
510 */
511 template<
512 class MutableBuffers,
513 class ConstBuffers>
514 std::size_t
515 2557 buffer_copy(
516 MutableBuffers const& to,
517 ConstBuffers const& from,
518 std::size_t at_most =
519 std::size_t(-1)) noexcept
520 {
521 // If you get a compile error here it
522 // means that one or both of your types
523 // do not meet the requirements.
524 static_assert(
525 is_mutable_buffers<MutableBuffers>::value &&
526 is_const_buffers<ConstBuffers>::value,
527 "Type requirements not met");
528
529 2557 std::size_t total = 0;
530 2557 std::size_t pos0 = 0;
531 2557 std::size_t pos1 = 0;
532 2557 auto const end0 = from.end();
533 2557 auto const end1 = to.end();
534 2557 auto it0 = from.begin();
535 2557 auto it1 = to.begin();
536 4646 while(
537
2/2
✓ Branch 0 taken 4616 times.
✓ Branch 1 taken 169 times.
4837 total < at_most &&
538
3/4
✓ Branch 0 taken 4785 times.
✓ Branch 1 taken 2366 times.
✓ Branch 2 taken 4616 times.
✗ Branch 3 not taken.
11854 it0 != end0 &&
539 it1 != end1)
540 {
541 const_buffer b0 =
542 4646 const_buffer(*it0) + pos0;
543 mutable_buffer b1 =
544 4646 mutable_buffer(*it1) + pos1;
545 std::size_t amount =
546 26688 [&]
547 {
548 4646 std::size_t n = b0.size();
549
3/4
✓ Branch 1 taken 1730 times.
✓ Branch 2 taken 2909 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
4646 if( n > b1.size())
550 1730 n = b1.size();
551
3/4
✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 2911 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
4646 if( n > at_most - total)
552 1728 n = at_most - total;
553 4646 std::memcpy(
554 b1.data(),
555 b0.data(),
556 n);
557 4646 return n;
558 4646 }();
559 4646 total += amount;
560
2/2
✓ Branch 1 taken 1664 times.
✓ Branch 2 taken 2952 times.
4646 if(amount == b1.size())
561 {
562 1682 ++it1;
563 1682 pos1 = 0;
564 }
565 else
566 {
567 2964 pos1 += amount;
568 }
569
2/2
✓ Branch 1 taken 1664 times.
✓ Branch 2 taken 2952 times.
4646 if(amount == b0.size())
570 {
571 1694 ++it0;
572 1694 pos0 = 0;
573 }
574 else
575 {
576 2952 pos0 += amount;
577 }
578 }
579 2557 return total;
580 }
581
582 } // http_proto
583 } // boost
584
585 #endif
586