GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/impl/fields_base.ipp
Date: 2023-01-09 16:11:13
Exec Total Coverage
Lines: 370 392 94.4%
Functions: 28 30 93.3%
Branches: 120 166 72.3%

Line Branch Exec Source
1 //
2 // Copyright (c) 2021 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/CPPAlliance/http_proto
8 //
9
10 #ifndef BOOST_HTTP_PROTO_IMPL_FIELDS_BASE_IPP
11 #define BOOST_HTTP_PROTO_IMPL_FIELDS_BASE_IPP
12
13 #include <boost/http_proto/fields.hpp>
14 #include <boost/http_proto/field.hpp>
15 #include <boost/http_proto/detail/copied_strings.hpp>
16 #include <boost/http_proto/detail/except.hpp>
17 #include <boost/http_proto/detail/number_string.hpp>
18 #include <boost/http_proto/detail/move_chars.hpp>
19 #include <boost/assert.hpp>
20 #include <boost/assert/source_location.hpp>
21 #include <string>
22
23 namespace boost {
24 namespace http_proto {
25
26 class fields_base::
27 op_t
28 {
29 fields_base& self_;
30 string_view* s0_;
31 string_view* s1_;
32 char* buf_ = nullptr;
33 char const* cbuf_ = nullptr;
34 std::size_t cap_ = 0;
35
36 public:
37 explicit
38 861 op_t(
39 fields_base& self,
40 string_view* s0 = nullptr,
41 string_view* s1 = nullptr) noexcept
42 861 : self_(self)
43 , s0_(s0)
44 861 , s1_(s1)
45 {
46 861 }
47
48 861 ~op_t()
49 861 {
50
2/2
✓ Branch 0 taken 651 times.
✓ Branch 1 taken 210 times.
861 if(buf_)
51
1/2
✓ Branch 0 taken 651 times.
✗ Branch 1 not taken.
651 delete[] buf_;
52 861 }
53
54 char const*
55 6 buf() const noexcept
56 {
57 6 return buf_;
58 }
59
60 char const*
61 1420 cbuf() const noexcept
62 {
63 1420 return cbuf_;
64 }
65
66 char*
67 9 end() const noexcept
68 {
69 9 return buf_ + cap_;
70 }
71
72 table
73 3 tab() const noexcept
74 {
75 3 return table(end());
76 }
77
78 static
79 std::size_t
80 growth(
81 std::size_t n0,
82 std::size_t m) noexcept;
83
84 bool
85 reserve(std::size_t bytes);
86
87 bool
88 grow(
89 std::size_t extra_char,
90 std::size_t extra_field);
91
92 void
93 copy_prefix(
94 std::size_t n,
95 std::size_t i) noexcept;
96
97 void
98 move_chars(
99 char* dest,
100 char const* src,
101 std::size_t n) const noexcept;
102 };
103
104 /* Growth functions for containers
105
106 N1 = g( N0, M );
107
108 g = growth function
109 M = minimum capacity
110 N0 = old size
111 N1 = new size
112 */
113 std::size_t
114 1649 fields_base::
115 op_t::
116 growth(
117 std::size_t n0,
118 std::size_t m) noexcept
119 {
120 1649 auto const E = alignof(entry);
121 1649 auto const m1 =
122 1649 E * ((m + E - 1) / E);
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1649 times.
1649 BOOST_ASSERT(m1 >= m);
124
2/2
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 1365 times.
1649 if(n0 == 0)
125 {
126 // exact
127 284 return m1;
128 }
129
2/2
✓ Branch 0 taken 1295 times.
✓ Branch 1 taken 70 times.
1365 if(m1 > n0)
130 1295 return m1;
131 70 return n0;
132 }
133
134 bool
135 845 fields_base::
136 op_t::
137 reserve(
138 std::size_t bytes)
139 {
140
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 844 times.
845 if(bytes > max_capacity_in_bytes())
141 {
142 // max capacity exceeded
143 1 detail::throw_length_error();
144 }
145 844 auto n = growth(
146 844 self_.h_.cap, bytes);
147
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 796 times.
844 if(n <= self_.h_.cap)
148 48 return false;
149 796 auto buf = new char[n];
150 796 buf_ = self_.h_.buf;
151 796 cbuf_ = self_.h_.cbuf;
152 796 cap_ = self_.h_.cap;
153 796 self_.h_.buf = buf;
154 796 self_.h_.cbuf = buf;
155 796 self_.h_.cap = n;
156 796 return true;
157 }
158
159 bool
160 807 fields_base::
161 op_t::
162 grow(
163 std::size_t extra_char,
164 std::size_t extra_field)
165 {
166 // extra_field is naturally limited
167 // by max_off_t, since each field
168 // is at least 4 bytes
169
2/4
✓ Branch 0 taken 807 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 807 times.
✗ Branch 3 not taken.
807 BOOST_ASSERT(
170 extra_field <= max_off_t &&
171 extra_field <= static_cast<
172 std::size_t>(
173 max_off_t - self_.h_.count));
174
2/2
✓ Branch 0 taken 805 times.
✓ Branch 1 taken 2 times.
807 if( extra_char > max_off_t ||
175 805 extra_char > static_cast<std::size_t>(
176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 805 times.
805 max_off_t - self_.h_.size))
177 2 detail::throw_length_error();
178 1610 auto n1 = growth(
179 805 self_.h_.cap,
180 detail::header::bytes_needed(
181 805 self_.h_.size + extra_char,
182 805 self_.h_.count + extra_field));
183 805 return reserve(n1);
184 }
185
186 void
187 fields_base::
188 op_t::
189 copy_prefix(
190 std::size_t n,
191 std::size_t i) noexcept
192 {
193 // copy first n chars
194 std::memcpy(
195 self_.h_.buf,
196 cbuf_,
197 n);
198 // copy first i entries
199 if(i > 0)
200 std::memcpy(
201 self_.h_.tab_() - i,
202 reinterpret_cast<entry*>(
203 buf_ + cap_) - i,
204 i * sizeof(entry));
205 }
206
207 void
208 37 fields_base::
209 op_t::
210 move_chars(
211 char* dest,
212 char const* src,
213 std::size_t n) const noexcept
214 {
215 37 detail::move_chars(
216 37 dest, src, n, s0_, s1_);
217 37 }
218
219 //------------------------------------------------
220
221 878 fields_base::
222 fields_base(
223 detail::kind k) noexcept
224 : fields_view_base(&h_)
225 878 , h_(k)
226 {
227 }
228
229 // construct a complete copy of h
230 36 fields_base::
231 fields_base(
232 24 detail::header const& h)
233 24 : fields_view_base(&h_)
234 36 , h_(h.kind)
235 {
236
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 12 times.
36 if(h.is_default())
237 {
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 BOOST_ASSERT(h.cap == 0);
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 BOOST_ASSERT(h.buf == nullptr);
240 12 h_ = h;
241 12 return;
242 }
243
244 // allocate and copy the buffer
245 48 op_t op(*this);
246
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 op.grow(h.size, h.count);
247 24 h.assign_to(h_);
248 24 std::memcpy(
249 24 h_.buf, h.cbuf, h.size);
250 24 h.copy_table(h_.buf + h_.cap);
251 }
252
253 //------------------------------------------------
254
255 914 fields_base::
256 938 ~fields_base()
257 {
258
2/2
✓ Branch 0 taken 395 times.
✓ Branch 1 taken 62 times.
914 if(h_.buf)
259
1/2
✓ Branch 0 taken 395 times.
✗ Branch 1 not taken.
790 delete[] h_.buf;
260 914 }
261
262 //------------------------------------------------
263 //
264 // Capacity
265 //
266 //------------------------------------------------
267
268 void
269 8 fields_base::
270 clear() noexcept
271 {
272
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if(! h_.buf)
273 4 return;
274 using H =
275 detail::header;
276 auto const& h =
277 4 *H::get_default(
278 4 h_.kind);
279 4 h.assign_to(h_);
280 4 std::memcpy(
281 4 h_.buf,
282 4 h.cbuf,
283 4 h_.size);
284 }
285
286 void
287 40 fields_base::
288 reserve_bytes(
289 std::size_t n)
290 {
291 41 op_t op(*this);
292
4/4
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 14 times.
40 if(! op.reserve(n))
293 25 return;
294 28 std::memcpy(
295 14 h_.buf, op.cbuf(), h_.size);
296 14 auto const nt =
297 14 sizeof(entry) * h_.count;
298
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8 times.
14 if(nt > 0)
299 6 std::memcpy(
300 6 h_.buf + h_.cap - nt,
301 6 op.end() - nt,
302 nt);
303 }
304
305 void
306 7 fields_base::
307 shrink_to_fit() noexcept
308 {
309 14 if(detail::header::bytes_needed(
310 7 h_.size, h_.count) >=
311
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 h_.cap)
312 3 return;
313 8 fields_base tmp(h_);
314 4 tmp.h_.swap(h_);
315 }
316
317 //------------------------------------------------
318 //
319 // Modifiers
320 //
321 //------------------------------------------------
322
323 std::size_t
324 24 fields_base::
325 erase(
326 field id) noexcept
327 {
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 BOOST_ASSERT(
329 id != field::unknown);
330 #if 1
331 24 auto const end_ = end();
332 24 auto it = find_last(end_, id);
333
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 21 times.
24 if(it == end_)
334 3 return 0;
335 21 std::size_t n = 1;
336 21 auto const begin_ = begin();
337 21 raw_erase(it.i_);
338
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 21 times.
57 while(it != begin_)
339 {
340 36 --it;
341
2/2
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 11 times.
36 if(it->id == id)
342 {
343 25 raw_erase(it.i_);
344 25 ++n;
345 }
346 }
347 21 h_.on_erase_all(id);
348 21 return n;
349 #else
350 std::size_t n = 0;
351 auto it0 = find(id);
352 auto const end_ = end();
353 if(it0 != end_)
354 {
355 auto it1 = it0;
356 std::size_t total = 0;
357 std::size_t size = 0;
358 // [it0, it1) run of id
359 for(;;)
360 {
361 size += length(it1.i_);
362 ++it1;
363 if(it1 == end_)
364 goto finish;
365 if(it1->id != id)
366 break;
367 }
368 std::memmove(
369 h_.buf + offset(it0.i_),
370 h_.buf + offset(it1.i_),
371 h_.size - offset(it2.i_));
372
373 finish:
374 h_.size -= size;
375 h_.count -= n;
376 }
377 return n;
378 #endif
379 }
380
381 std::size_t
382 18 fields_base::
383 erase(
384 string_view name) noexcept
385 {
386 18 auto it0 = find(name);
387 18 auto const end_ = end();
388
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 15 times.
18 if(it0 == end_)
389 3 return 0;
390 15 auto it = end_;
391 15 std::size_t n = 1;
392 15 auto const id = it0->id;
393
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
15 if(id == field::unknown)
394 {
395 // fix self-intersection
396 6 name = it0->name;
397
398 for(;;)
399 {
400 24 --it;
401
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 18 times.
24 if(it == it0)
402 6 break;
403 18 if(grammar::ci_is_equal(
404
2/2
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 9 times.
36 it->name, name))
405 {
406 9 raw_erase(it.i_);
407 9 ++n;
408 }
409 }
410 6 raw_erase(it.i_);
411 }
412 else
413 {
414 for(;;)
415 {
416 21 --it;
417
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 12 times.
21 if(it == it0)
418 9 break;
419
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
12 if(it->id == id)
420 {
421 6 raw_erase(it.i_);
422 6 ++n;
423 }
424 }
425 9 raw_erase(it.i_);
426 9 h_.on_erase_all(id);
427 }
428 15 return n;
429 }
430
431 //------------------------------------------------
432
433 void
434 17 fields_base::
435 set(
436 iterator it,
437 string_view value)
438 {
439 17 auto const i = it.i_;
440 17 auto const& e0 = h_.tab()[i];
441 17 auto const pos0 = offset(i);
442 17 auto const pos1 = offset(i + 1 );
443 std::ptrdiff_t dn =
444 17 value.size() -
445 17 it->value.size();
446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if( value.empty() &&
447
1/4
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
17 ! it->value.empty())
448 --dn; // remove SP
449 17 else if(
450
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
17 it->value.empty() &&
451 ! value.empty())
452 ++dn; // add SP
453
454 34 op_t op(*this, &value);
455
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14 times.
20 if( dn > 0 &&
456
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 op.grow(value.size() -
457
2/2
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 14 times.
20 it->value.size(), 0))
458 {
459 // reallocated
460 3 auto dest = h_.buf +
461 3 pos0 + e0.nn + 1;
462 6 std::memcpy(
463 3 h_.buf,
464 3 op.buf(),
465 3 dest - h_.buf);
466
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if(! value.empty())
467 {
468 3 *dest++ = ' ';
469
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 value.copy(
470 dest,
471 value.size());
472 3 dest += value.size();
473 }
474 3 *dest++ = '\r';
475 3 *dest++ = '\n';
476 6 std::memcpy(
477 3 h_.buf + pos1 + dn,
478 6 op.buf() + pos1,
479 3 h_.size - pos1);
480 6 std::memcpy(
481 3 h_.buf + h_.cap -
482 3 sizeof(entry) * h_.count,
483 3 &op.tab()[h_.count - 1],
484 3 sizeof(entry) * h_.count);
485 }
486 else
487 {
488 // copy the value first
489 28 auto dest = h_.buf + pos0 +
490 14 it->name.size() + 1;
491
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 if(! value.empty())
492 {
493 14 *dest++ = ' ';
494
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 value.copy(
495 dest,
496 value.size());
497 14 dest += value.size();
498 }
499 14 op.move_chars(
500 14 h_.buf + pos1 + dn,
501 14 h_.buf + pos1,
502 14 h_.size - pos1);
503 14 *dest++ = '\r';
504 14 *dest++ = '\n';
505 }
506 {
507 // update tab
508 17 auto ft = h_.tab();
509 22 for(std::size_t j = h_.count - 1;
510
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 17 times.
22 j > i; --j)
511 5 ft[j] = ft[j] + dn;
512 17 auto& e = ft[i];
513 34 e.vp = e.np + e.nn +
514 17 1 + ! value.empty();
515 17 e.vn = static_cast<
516 17 off_t>(value.size());
517 17 h_.size = static_cast<
518 17 off_t>(h_.size + dn);
519 }
520 17 auto const id = it->id;
521
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 10 times.
17 if(h_.is_special(id))
522 {
523 // replace first char of name
524 // with null to hide metadata
525 7 char saved = h_.buf[pos0];
526 7 auto& e = h_.tab()[i];
527 7 e.id = field::unknown;
528 7 h_.buf[pos0] = '\0';
529
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 h_.on_erase(id);
530 7 h_.buf[pos0] = saved;
531 7 e.id = id;
532
1/2
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
7 h_.on_insert(id, it->value);
533 }
534 17 }
535
536 // erase existing fields with id
537 // and then add the field with value
538 void
539 18 fields_base::
540 set(
541 field id,
542 string_view value)
543 {
544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 BOOST_ASSERT(
545 id != field::unknown);
546 18 auto const i0 = h_.find(id);
547
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 if(i0 != h_.count)
548 {
549 // field exists
550 12 auto const ft = h_.tab();
551 {
552 // provide strong guarantee
553 auto const n0 =
554 12 h_.size - length(i0);
555 auto const n =
556 12 ft[i0].nn + 2 +
557 12 value.size() + 2;
558 // VFALCO missing overflow check
559
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 reserve_bytes(n0 + n);
560 }
561 12 erase_all_impl(i0, id);
562 }
563 18 insert_impl(id, to_string(id),
564 18 value, h_.count);
565 18 }
566
567 // erase existing fields with name
568 // and then add the field with value
569 void
570 13 fields_base::
571 set(
572 string_view name,
573 string_view value)
574 {
575 13 auto const i0 = h_.find(name);
576
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 4 times.
13 if(i0 != h_.count)
577 {
578 // field exists
579 9 auto const ft = h_.tab();
580 9 auto const id = ft[i0].id;
581 {
582 // provide strong guarantee
583 auto const n0 =
584 9 h_.size - length(i0);
585 auto const n =
586 9 ft[i0].nn + 2 +
587 9 value.size() + 2;
588 // VFALCO missing overflow check
589
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 reserve_bytes(n0 + n);
590 }
591 // VFALCO simple algorithm but
592 // costs one extra memmove
593 9 erase_all_impl(i0, id);
594 }
595 13 insert_impl(
596 string_to_field(name),
597 13 name, value, h_.count);
598 12 }
599
600 //------------------------------------------------
601 //
602 // (implementation)
603 //
604 //------------------------------------------------
605
606 // copy start line and fields
607 void
608 9 fields_base::
609 copy_impl(
610 detail::header const& h)
611 {
612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 BOOST_ASSERT(
613 h.kind == ph_->kind);
614
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
9 if(! h.is_default())
615 {
616 auto const n =
617 6 detail::header::bytes_needed(
618 6 h.size, h.count);
619
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if(n <= h_.cap)
620 {
621 // no realloc
622 1 h.assign_to(h_);
623 1 h.copy_table(
624 1 h_.buf + h_.cap);
625 1 std::memcpy(
626 1 h_.buf,
627 1 h.cbuf,
628 1 h.size);
629 1 return;
630 }
631 }
632
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
16 fields_base tmp(h);
633 8 tmp.h_.swap(h_);
634 }
635
636 void
637 792 fields_base::
638 insert_impl(
639 field id,
640 string_view name,
641 string_view value,
642 std::size_t before)
643 {
644 792 auto const tab0 = h_.tab_();
645 792 auto const pos = offset(before);
646 auto const n =
647 792 name.size() + // name
648 792 1 + // ':'
649 792 ! value.empty() + // [SP]
650 792 value.size() + // value
651 792 2; // CRLF
652
653 1584 op_t op(*this, &name, &value);
654
4/4
✓ Branch 1 taken 790 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 767 times.
✓ Branch 4 taken 23 times.
792 if(op.grow(n, 1))
655 {
656 // reallocated
657
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 128 times.
767 if(pos > 0)
658 639 std::memcpy(
659 639 h_.buf,
660 639 op.cbuf(),
661 pos);
662
2/2
✓ Branch 0 taken 407 times.
✓ Branch 1 taken 360 times.
767 if(before > 0)
663 814 std::memcpy(
664 407 h_.tab_() - before,
665 407 tab0 - before,
666 before * sizeof(entry));
667 1534 std::memcpy(
668 767 h_.buf + pos + n,
669 767 op.cbuf() + pos,
670 767 h_.size - pos);
671 }
672 else
673 {
674 23 op.move_chars(
675 23 h_.buf + pos + n,
676 23 h_.buf + pos,
677 23 h_.size - pos);
678 }
679
680 // serialize
681 {
682 790 auto dest = h_.buf + pos;
683
1/2
✓ Branch 2 taken 790 times.
✗ Branch 3 not taken.
790 name.copy(dest, name.size());
684 790 dest += name.size();
685 790 *dest++ = ':';
686
2/2
✓ Branch 1 taken 723 times.
✓ Branch 2 taken 67 times.
790 if(! value.empty())
687 {
688 723 *dest++ = ' ';
689
1/2
✓ Branch 2 taken 723 times.
✗ Branch 3 not taken.
723 value.copy(
690 dest, value.size());
691 723 dest += value.size();
692 }
693 790 *dest++ = '\r';
694 790 *dest = '\n';
695 }
696
697 // update table
698 790 auto const tab = h_.tab_();
699 {
700 790 auto i = h_.count - before;
701
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 772 times.
790 if(i > 0)
702 {
703 18 auto p0 = tab0 - h_.count;
704 18 auto p = tab - h_.count - 1;
705 18 do
706 {
707 36 *p++ = *p0++ + n;
708 }
709
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 while(--i);
710 }
711 }
712 790 auto& e = tab[0 - before - 1];
713 790 e.np = static_cast<off_t>(
714 790 pos - h_.prefix);
715 790 e.nn = static_cast<
716 790 off_t>(name.size());
717 790 e.vp = static_cast<off_t>(
718 1580 pos - h_.prefix +
719 790 name.size() + 1 +
720 790 ! value.empty());
721 790 e.vn = static_cast<
722 790 off_t>(value.size());
723 790 e.id = id;
724
725 // update container
726 790 h_.count++;
727 790 h_.size = static_cast<
728 790 off_t>(h_.size + n);
729
2/2
✓ Branch 0 taken 614 times.
✓ Branch 1 taken 176 times.
790 if( id != field::unknown)
730
1/2
✓ Branch 1 taken 614 times.
✗ Branch 2 not taken.
614 h_.on_insert(id, value);
731 790 }
732
733 // erase i and update metadata
734 void
735 31 fields_base::
736 erase_impl(
737 std::size_t i,
738 field id) noexcept
739 {
740 31 raw_erase(i);
741
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 if(id != field::unknown)
742 31 h_.on_erase(id);
743 31 }
744
745 //------------------------------------------------
746
747 void
748 141 fields_base::
749 raw_erase(
750 std::size_t i) noexcept
751 {
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 BOOST_ASSERT(i < h_.count);
753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 BOOST_ASSERT(h_.buf != nullptr);
754 141 auto const p0 = offset(i);
755 141 auto const p1 = offset(i + 1);
756 141 std::memmove(
757 141 h_.buf + p0,
758 141 h_.buf + p1,
759 141 h_.size - p1);
760 141 auto const n = p1 - p0;
761 141 --h_.count;
762 141 auto ft = h_.tab();
763
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 141 times.
216 for(;i < h_.count; ++i)
764 75 ft[i] = ft[i + 1] - n;
765 141 h_.size = static_cast<
766 141 off_t>(h_.size - n);
767 141 }
768
769 //------------------------------------------------
770
771 // erase all fields with id
772 // and update metadata
773 std::size_t
774 21 fields_base::
775 erase_all_impl(
776 std::size_t i0,
777 field id) noexcept
778 {
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 BOOST_ASSERT(
780 id != field::unknown);
781 21 std::size_t n = 1;
782 21 std::size_t i = h_.count - 1;
783 21 auto const ft = h_.tab();
784
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 21 times.
46 while(i > i0)
785 {
786
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 12 times.
25 if(ft[i].id == id)
787 {
788 13 raw_erase(i);
789 13 ++n;
790 }
791 // go backwards to
792 // reduce memmoves
793 25 --i;
794 }
795 21 raw_erase(i0);
796 21 h_.on_erase_all(id);
797 21 return n;
798 }
799
800 // return i-th field absolute offset
801 std::size_t
802 1150 fields_base::
803 offset(
804 std::size_t i) const noexcept
805 {
806
2/2
✓ Branch 0 taken 464 times.
✓ Branch 1 taken 686 times.
1150 if(i == 0)
807 464 return h_.prefix;
808
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 512 times.
686 if(i < h_.count)
809 348 return h_.prefix +
810 174 h_.tab_()[0-(i + 1)].np;
811 // make final CRLF the last "field"
812 //BOOST_ASSERT(i == h_.count);
813 512 return h_.size - 2;
814 }
815
816 // return i-th field absolute length
817 std::size_t
818 21 fields_base::
819 length(
820 std::size_t i) const noexcept
821 {
822 return
823 21 offset(i + 1) -
824 21 offset(i);
825 }
826
827 //------------------------------------------------
828
829 // erase n fields matching id
830 // without updating metadata
831 void
832 fields_base::
833 raw_erase_n(
834 field id,
835 std::size_t n) noexcept
836 {
837 // iterate in reverse
838 auto e = &h_.tab()[h_.count];
839 auto const e0 = &h_.tab()[0];
840 while(n > 0)
841 {
842 BOOST_ASSERT(e != e0);
843 ++e; // decrement
844 if(e->id == id)
845 {
846 raw_erase(e0 - e);
847 --n;
848 }
849 }
850 }
851
852 } // http_proto
853 } // boost
854
855 #endif
856