LCOV - code coverage report
Current view: top level - http_proto/impl - fields_base.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 387 416 93.0 %
Date: 2023-02-10 23:49:12 Functions: 31 35 88.6 %

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

Generated by: LCOV version 1.15