LCOV - code coverage report
Current view: top level - url/detail/impl - segments_iter_impl.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 99.2 % 124 123 1
Test Date: 2026-03-02 22:26:03 Functions: 100.0 % 6 6

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
       4                 : //
       5                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       6                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       7                 : //
       8                 : // Official repository: https://github.com/boostorg/url
       9                 : //
      10                 : 
      11                 : #ifndef BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP
      12                 : #define BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_HPP
      13                 : 
      14                 : #include <boost/url/detail/decode.hpp>
      15                 : #include <boost/url/detail/path.hpp>
      16                 : #include <boost/assert.hpp>
      17                 : 
      18                 : namespace boost {
      19                 : namespace urls {
      20                 : namespace detail {
      21                 : 
      22                 : // begin
      23                 : inline
      24 HIT        9351 : segments_iter_impl::
      25                 : segments_iter_impl(
      26            9351 :     detail::path_ref const& ref_) noexcept
      27            9351 :     : ref(ref_)
      28                 : {
      29            9351 :     pos = path_prefix(ref.buffer());
      30                 :     // begin() starts after any malleable prefix but remembers decoded chars skipped
      31            9351 :     decoded_prefix = pos;
      32            9351 :     update();
      33            9351 : }
      34                 : 
      35                 : // end
      36                 : inline
      37           16403 : segments_iter_impl::
      38                 : segments_iter_impl(
      39                 :     detail::path_ref const& ref_,
      40           16403 :     int) noexcept
      41           16403 :     : ref(ref_)
      42           16403 :     , pos(ref.size())
      43           16403 :     , next(ref.size())
      44           16403 :     , index(ref.nseg())
      45                 : {
      46                 :     // end() carries the total decoded length for O(1) range math
      47           16403 :     decoded_prefix = ref.decoded_size();
      48           16403 : }
      49                 : 
      50                 : inline
      51            2313 : segments_iter_impl::
      52                 : segments_iter_impl(
      53                 :     url_impl const& u_,
      54                 :     std::size_t pos_,
      55            2313 :     std::size_t index_) noexcept
      56            2313 :     : ref(u_)
      57            2313 :     , pos(pos_)
      58            2313 :     , index(index_)
      59                 : {
      60            2313 :     auto const total = ref.nseg();
      61            2313 :     if(index >= total)
      62                 :     {
      63             961 :         pos = ref.size();
      64             961 :         next = ref.size();
      65             961 :         decoded_prefix = ref.decoded_size();
      66                 :         // iterator equal to end: nothing to decode
      67             961 :         dn = 0;
      68             961 :         return;
      69                 :     }
      70                 : 
      71            1352 :     if(index == 0)
      72                 :     {
      73             763 :         pos = path_prefix(ref.buffer());
      74                 :         // first segment inherits the prefix size (including leading '/')
      75             763 :         decoded_prefix = pos;
      76             763 :         update();
      77             763 :         return;
      78                 :     }
      79                 : 
      80             589 :     BOOST_ASSERT(pos <= ref.size());
      81                 :     // compute decoded prefix by scanning once up to the encoded offset
      82             589 :     decoded_prefix = detail::decode_bytes_unsafe(
      83                 :         core::string_view(ref.data(), pos));
      84             589 :     if(pos != ref.size())
      85                 :     {
      86             589 :         BOOST_ASSERT(
      87                 :             ref.data()[pos] == '/');
      88             589 :         ++pos; // skip '/'
      89             589 :         update();
      90             589 :         --pos;
      91             589 :         return;
      92                 :     }
      93                 : 
      94 MIS           0 :     update();
      95                 : }
      96                 : 
      97                 : inline
      98                 : void
      99 HIT       10703 : segments_iter_impl::
     100                 : update() noexcept
     101                 : {
     102           10703 :     auto const end = ref.end();
     103                 :     char const* const p0 =
     104           10703 :         ref.data() + pos;
     105           10703 :     dn = 0;
     106           10703 :     auto p = p0;
     107           48039 :     while(p != end)
     108                 :     {
     109           41759 :         if(*p == '/')
     110            4423 :             break;
     111           37336 :         if(*p != '%')
     112                 :         {
     113           33536 :             ++p;
     114           33536 :             continue;
     115                 :         }
     116            3800 :         p += 3;
     117            3800 :         dn += 2;
     118                 :     }
     119           10703 :     next = p - ref.data();
     120           10703 :     dn = p - p0 - dn;
     121           10703 :     s_ = make_pct_string_view_unsafe(
     122           10703 :         p0, p - p0, dn);
     123           10703 : }
     124                 : 
     125                 : inline
     126                 : void
     127           10843 : segments_iter_impl::
     128                 : increment() noexcept
     129                 : {
     130           10843 :     BOOST_ASSERT(
     131                 :         index != ref.nseg());
     132           10843 :     auto const old_index = index;
     133           10843 :     auto const old_dn = dn;
     134                 :     // add decoded length of previous segment
     135           10843 :     decoded_prefix += old_dn;
     136           10843 :     if(old_index > 0)
     137                 :         // account for the '/' separator we just crossed
     138            5998 :         ++decoded_prefix;
     139           10843 :     ++index;
     140           10843 :     pos = next;
     141           10843 :     if(index == ref.nseg())
     142            4761 :         return;
     143                 :     // "/" segment
     144            6082 :     auto const end = ref.end();
     145            6082 :     auto p = ref.data() + pos;
     146            6082 :     BOOST_ASSERT(p != end);
     147            6082 :     BOOST_ASSERT(*p == '/');
     148            6082 :     dn = 0;
     149            6082 :     ++p; // skip '/'
     150            6082 :     auto const p0 = p;
     151           31756 :     while(p != end)
     152                 :     {
     153           28656 :         if(*p == '/')
     154            2982 :             break;
     155           25674 :         if(*p != '%')
     156                 :         {
     157           24639 :             ++p;
     158           24639 :             continue;
     159                 :         }
     160            1035 :         p += 3;
     161            1035 :         dn += 2;
     162                 :     }
     163            6082 :     next = p - ref.data();
     164            6082 :     dn = p - p0 - dn;
     165            6082 :     s_ = make_pct_string_view_unsafe(
     166            6082 :         p0, p - p0, dn);
     167                 : }
     168                 : 
     169                 : inline
     170                 : void
     171            1957 : segments_iter_impl::
     172                 : decrement() noexcept
     173                 : {
     174            1957 :     BOOST_ASSERT(index != 0);
     175            1957 :     auto const current_dn = dn;
     176            1957 :     auto const current_index = index;
     177                 :     // remove the decoded length of the segment we're leaving
     178            1957 :     decoded_prefix -= current_dn;
     179            1957 :     if(current_index > 0 && decoded_prefix > 0)
     180                 :         // drop the '/' separator when stepping left of it
     181            1957 :         --decoded_prefix;
     182            1957 :     --index;
     183            1957 :     if(index == 0)
     184                 :     {
     185             788 :         next = pos;
     186             788 :         pos = path_prefix(ref.buffer());
     187             788 :         decoded_prefix = pos;
     188             788 :         s_ = core::string_view(
     189             788 :             ref.data() + pos,
     190             788 :             next - pos);
     191             788 :         BOOST_ASSERT(! s_.ends_with('/'));
     192             788 :         return;
     193                 :     }
     194            1169 :     auto const begin = ref.data() +
     195            1169 :         path_prefix(ref.buffer());
     196            1169 :     next = pos;
     197            1169 :     auto p = ref.data() + next;
     198            1169 :     auto const p1 = p;
     199            1169 :     BOOST_ASSERT(p != begin);
     200            1169 :     dn = 0;
     201            4697 :     while(p != begin)
     202                 :     {
     203            4697 :         --p;
     204            4697 :         if(*p == '/')
     205                 :         {
     206            1169 :             ++dn;
     207            1169 :             break;
     208                 :         }
     209            3528 :         if(*p == '%')
     210             168 :             dn += 2;
     211                 :     }
     212            1169 :     dn = p1 - p - dn;
     213            1169 :     pos = p - ref.data();
     214                 :     // keep decoded_prefix consistent with new pos
     215                 :     // (already adjusted above)
     216            1169 :     s_ = make_pct_string_view_unsafe(
     217            1169 :         p + 1, p1 - p - 1, dn);
     218                 : }
     219                 : 
     220                 : } // detail
     221                 : } // urls
     222                 : } // boost
     223                 : 
     224                 : #endif
        

Generated by: LCOV version 2.3