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-02-25 21:00:01 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        2323 : segments_iter_impl::
      25                 : segments_iter_impl(
      26            2323 :     detail::path_ref const& ref_) noexcept
      27            2323 :     : ref(ref_)
      28                 : {
      29            2323 :     pos = path_prefix(ref.buffer());
      30                 :     // begin() starts after any malleable prefix but remembers decoded chars skipped
      31            2323 :     decoded_prefix = pos;
      32            2323 :     update();
      33            2323 : }
      34                 : 
      35                 : // end
      36                 : inline
      37            1882 : segments_iter_impl::
      38                 : segments_iter_impl(
      39                 :     detail::path_ref const& ref_,
      40            1882 :     int) noexcept
      41            1882 :     : ref(ref_)
      42            1882 :     , pos(ref.size())
      43            1882 :     , next(ref.size())
      44            1882 :     , index(ref.nseg())
      45                 : {
      46                 :     // end() carries the total decoded length for O(1) range math
      47            1882 :     decoded_prefix = ref.decoded_size();
      48            1882 : }
      49                 : 
      50                 : inline
      51             596 : segments_iter_impl::
      52                 : segments_iter_impl(
      53                 :     url_impl const& u_,
      54                 :     std::size_t pos_,
      55             596 :     std::size_t index_) noexcept
      56             596 :     : ref(u_)
      57             596 :     , pos(pos_)
      58             596 :     , index(index_)
      59                 : {
      60             596 :     auto const total = ref.nseg();
      61             596 :     if(index >= total)
      62                 :     {
      63             158 :         pos = ref.size();
      64             158 :         next = ref.size();
      65             158 :         decoded_prefix = ref.decoded_size();
      66                 :         // iterator equal to end: nothing to decode
      67             158 :         dn = 0;
      68             158 :         return;
      69                 :     }
      70                 : 
      71             438 :     if(index == 0)
      72                 :     {
      73             239 :         pos = path_prefix(ref.buffer());
      74                 :         // first segment inherits the prefix size (including leading '/')
      75             239 :         decoded_prefix = pos;
      76             239 :         update();
      77             239 :         return;
      78                 :     }
      79                 : 
      80             199 :     BOOST_ASSERT(pos <= ref.size());
      81                 :     // compute decoded prefix by scanning once up to the encoded offset
      82             199 :     decoded_prefix = detail::decode_bytes_unsafe(
      83                 :         core::string_view(ref.data(), pos));
      84             199 :     if(pos != ref.size())
      85                 :     {
      86             199 :         BOOST_ASSERT(
      87                 :             ref.data()[pos] == '/');
      88             199 :         ++pos; // skip '/'
      89             199 :         update();
      90             199 :         --pos;
      91             199 :         return;
      92                 :     }
      93                 : 
      94 MIS           0 :     update();
      95                 : }
      96                 : 
      97                 : inline
      98                 : void
      99 HIT        2761 : segments_iter_impl::
     100                 : update() noexcept
     101                 : {
     102            2761 :     auto const end = ref.end();
     103                 :     char const* const p0 =
     104            2761 :         ref.data() + pos;
     105            2761 :     dn = 0;
     106            2761 :     auto p = p0;
     107           10654 :     while(p != end)
     108                 :     {
     109            9517 :         if(*p == '/')
     110            1624 :             break;
     111            7893 :         if(*p != '%')
     112                 :         {
     113            7525 :             ++p;
     114            7525 :             continue;
     115                 :         }
     116             368 :         p += 3;
     117             368 :         dn += 2;
     118                 :     }
     119            2761 :     next = p - ref.data();
     120            2761 :     dn = p - p0 - dn;
     121            2761 :     s_ = make_pct_string_view_unsafe(
     122            2761 :         p0, p - p0, dn);
     123            2761 : }
     124                 : 
     125                 : inline
     126                 : void
     127            2862 : segments_iter_impl::
     128                 : increment() noexcept
     129                 : {
     130            2862 :     BOOST_ASSERT(
     131                 :         index != ref.nseg());
     132            2862 :     auto const old_index = index;
     133            2862 :     auto const old_dn = dn;
     134                 :     // add decoded length of previous segment
     135            2862 :     decoded_prefix += old_dn;
     136            2862 :     if(old_index > 0)
     137                 :         // account for the '/' separator we just crossed
     138            1634 :         ++decoded_prefix;
     139            2862 :     ++index;
     140            2862 :     pos = next;
     141            2862 :     if(index == ref.nseg())
     142            1162 :         return;
     143                 :     // "/" segment
     144            1700 :     auto const end = ref.end();
     145            1700 :     auto p = ref.data() + pos;
     146            1700 :     BOOST_ASSERT(p != end);
     147            1700 :     BOOST_ASSERT(*p == '/');
     148            1700 :     dn = 0;
     149            1700 :     ++p; // skip '/'
     150            1700 :     auto const p0 = p;
     151            7535 :     while(p != end)
     152                 :     {
     153            6811 :         if(*p == '/')
     154             976 :             break;
     155            5835 :         if(*p != '%')
     156                 :         {
     157            5707 :             ++p;
     158            5707 :             continue;
     159                 :         }
     160             128 :         p += 3;
     161             128 :         dn += 2;
     162                 :     }
     163            1700 :     next = p - ref.data();
     164            1700 :     dn = p - p0 - dn;
     165            1700 :     s_ = make_pct_string_view_unsafe(
     166            1700 :         p0, p - p0, dn);
     167                 : }
     168                 : 
     169                 : inline
     170                 : void
     171            1584 : segments_iter_impl::
     172                 : decrement() noexcept
     173                 : {
     174            1584 :     BOOST_ASSERT(index != 0);
     175            1584 :     auto const current_dn = dn;
     176            1584 :     auto const current_index = index;
     177                 :     // remove the decoded length of the segment we're leaving
     178            1584 :     decoded_prefix -= current_dn;
     179            1584 :     if(current_index > 0 && decoded_prefix > 0)
     180                 :         // drop the '/' separator when stepping left of it
     181            1584 :         --decoded_prefix;
     182            1584 :     --index;
     183            1584 :     if(index == 0)
     184                 :     {
     185             549 :         next = pos;
     186             549 :         pos = path_prefix(ref.buffer());
     187             549 :         decoded_prefix = pos;
     188             549 :         s_ = core::string_view(
     189             549 :             ref.data() + pos,
     190             549 :             next - pos);
     191             549 :         BOOST_ASSERT(! s_.ends_with('/'));
     192             549 :         return;
     193                 :     }
     194            1035 :     auto const begin = ref.data() +
     195            1035 :         path_prefix(ref.buffer());
     196            1035 :     next = pos;
     197            1035 :     auto p = ref.data() + next;
     198            1035 :     auto const p1 = p;
     199            1035 :     BOOST_ASSERT(p != begin);
     200            1035 :     dn = 0;
     201            3188 :     while(p != begin)
     202                 :     {
     203            3188 :         --p;
     204            3188 :         if(*p == '/')
     205                 :         {
     206            1035 :             ++dn;
     207            1035 :             break;
     208                 :         }
     209            2153 :         if(*p == '%')
     210              28 :             dn += 2;
     211                 :     }
     212            1035 :     dn = p1 - p - dn;
     213            1035 :     pos = p - ref.data();
     214                 :     // keep decoded_prefix consistent with new pos
     215                 :     // (already adjusted above)
     216            1035 :     s_ = make_pct_string_view_unsafe(
     217            1035 :         p + 1, p1 - p - 1, dn);
     218                 : }
     219                 : 
     220                 : } // detail
     221                 : } // urls
     222                 : } // boost
     223                 : 
     224                 : #endif
        

Generated by: LCOV version 2.3