LCOV - code coverage report
Current view: top level - http_proto/impl - fields_base.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 371 395 93.9 %
Date: 2023-01-09 16:11:12 Functions: 30 33 90.9 %

          Line data    Source code
       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         861 :         if(buf_)
      51         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        1649 :     BOOST_ASSERT(m1 >= m);
     124        1649 :     if(n0 == 0)
     125             :     {
     126             :         // exact
     127         284 :         return m1;
     128             :     }
     129        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         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         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         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         807 :     if( extra_char > max_off_t ||
     175         805 :         extra_char > static_cast<std::size_t>(
     176         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           0 : 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           0 :     std::memcpy(
     195           0 :         self_.h_.buf,
     196           0 :         cbuf_,
     197             :         n);
     198             :     // copy first i entries
     199           0 :     if(i > 0)
     200           0 :         std::memcpy(
     201           0 :             self_.h_.tab_() - i,
     202             :             reinterpret_cast<entry*>(
     203           0 :                 buf_ + cap_) - i,
     204             :             i * sizeof(entry));
     205           0 : }
     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         439 : fields_base::
     222             : fields_base(
     223           0 :     detail::kind k) noexcept
     224           0 :     : fields_view_base(&h_)
     225         439 :     , h_(k)
     226             : {
     227         439 : }
     228             : 
     229             : // construct a complete copy of h
     230          18 : fields_base::
     231             : fields_base(
     232          12 :     detail::header const& h)
     233          12 :     : fields_view_base(&h_)
     234          18 :     , h_(h.kind)
     235             : {
     236          18 :     if(h.is_default())
     237             :     {
     238           6 :         BOOST_ASSERT(h.cap == 0);
     239           6 :         BOOST_ASSERT(h.buf == nullptr);
     240           6 :         h_ = h;
     241           6 :         return;
     242             :     }
     243             : 
     244             :     // allocate and copy the buffer
     245          24 :     op_t op(*this);
     246          12 :     op.grow(h.size, h.count);
     247          12 :     h.assign_to(h_);
     248          12 :     std::memcpy(
     249          12 :         h_.buf, h.cbuf, h.size);
     250          12 :     h.copy_table(h_.buf + h_.cap);
     251             : }
     252             : 
     253             : //------------------------------------------------
     254             : 
     255         457 : fields_base::
     256         469 : ~fields_base()
     257             : {
     258         457 :     if(h_.buf)
     259         395 :         delete[] h_.buf;
     260         457 : }
     261             : 
     262             : //------------------------------------------------
     263             : //
     264             : // Capacity
     265             : //
     266             : //------------------------------------------------
     267             : 
     268             : void
     269           8 : fields_base::
     270             : clear() noexcept
     271             : {
     272           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          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          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           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          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          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          57 :     while(it != begin_)
     339             :     {
     340          36 :         --it;
     341          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          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          15 :     if(id == field::unknown)
     394             :     {
     395             :         // fix self-intersection
     396           6 :         name = it0->name;
     397             : 
     398             :         for(;;)
     399             :         {
     400          24 :             --it;
     401          24 :             if(it == it0)
     402           6 :                 break;
     403          18 :             if(grammar::ci_is_equal(
     404          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          21 :             if(it == it0)
     418           9 :                 break;
     419          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          17 :     if( value.empty() &&
     447          17 :         ! it->value.empty())
     448           0 :         --dn; // remove SP
     449          17 :     else if(
     450          17 :         it->value.empty() &&
     451           0 :         ! value.empty())
     452           0 :         ++dn; // add SP
     453             : 
     454          34 :     op_t op(*this, &value);
     455          20 :     if( dn > 0 &&
     456           6 :         op.grow(value.size() -
     457          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           3 :         if(! value.empty())
     467             :         {
     468           3 :             *dest++ = ' ';
     469           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          14 :         if(! value.empty())
     492             :         {
     493          14 :             *dest++ = ' ';
     494          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          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          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           7 :         h_.on_erase(id);
     530           7 :         h_.buf[pos0] = saved;
     531           7 :         e.id = id;
     532           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          18 :     BOOST_ASSERT(
     545             :         id != field::unknown);
     546          18 :     auto const i0 = h_.find(id);
     547          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          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          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           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           9 :     BOOST_ASSERT(
     613             :         h.kind == ph_->kind);
     614           9 :     if(! h.is_default())
     615             :     {
     616             :         auto const n =
     617           6 :             detail::header::bytes_needed(
     618           6 :                 h.size, h.count);
     619           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          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         792 :     if(op.grow(n, 1))
     655             :     {
     656             :         // reallocated
     657         767 :         if(pos > 0)
     658         639 :             std::memcpy(
     659         639 :                 h_.buf,
     660         639 :                 op.cbuf(),
     661             :                 pos);
     662         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         790 :         name.copy(dest, name.size());
     684         790 :         dest += name.size();
     685         790 :         *dest++ = ':';
     686         790 :         if(! value.empty())
     687             :         {
     688         723 :             *dest++ = ' ';
     689         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         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          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         790 :     if( id != field::unknown)
     730         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          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         141 :     BOOST_ASSERT(i < h_.count);
     753         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         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          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          46 :     while(i > i0)
     785             :     {
     786          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        1150 :     if(i == 0)
     807         464 :         return h_.prefix;
     808         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           0 : fields_base::
     833             : raw_erase_n(
     834             :     field id,
     835             :     std::size_t n) noexcept
     836             : {
     837             :     // iterate in reverse
     838           0 :     auto e = &h_.tab()[h_.count];
     839           0 :     auto const e0 = &h_.tab()[0];
     840           0 :     while(n > 0)
     841             :     {
     842           0 :         BOOST_ASSERT(e != e0);
     843           0 :         ++e; // decrement
     844           0 :         if(e->id == id)
     845             :         {
     846           0 :             raw_erase(e0 - e);
     847           0 :             --n;
     848             :         }
     849             :     }
     850           0 : }
     851             : 
     852             : } // http_proto
     853             : } // boost
     854             : 
     855             : #endif

Generated by: LCOV version 1.15