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-12-11 14:11:20 Functions: 31 35 88.6 %

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

Generated by: LCOV version 1.15