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.1 % 115 114 1
Test Date: 2026-04-15 15:11:35 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        9364 : segments_iter_impl::
      25                 : segments_iter_impl(
      26            9364 :     detail::path_ref const& ref_) noexcept
      27            9364 :     : ref(ref_)
      28                 : {
      29            9364 :     pos = path_prefix(ref.buffer());
      30                 :     // begin() starts after any malleable prefix but remembers decoded chars skipped
      31            9364 :     decoded_prefix = pos;
      32            9364 :     update();
      33            9364 : }
      34                 : 
      35                 : // end
      36                 : inline
      37           16416 : segments_iter_impl::
      38                 : segments_iter_impl(
      39                 :     detail::path_ref const& ref_,
      40           16416 :     int) noexcept
      41           16416 :     : ref(ref_)
      42           16416 :     , pos(ref.size())
      43           16416 :     , next(ref.size())
      44           16416 :     , index(ref.nseg())
      45                 : {
      46                 :     // end() carries the total decoded length for O(1) range math
      47           16416 :     decoded_prefix = ref.decoded_size();
      48           16416 : }
      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       12695 : segments_iter_impl::
     100                 : update() noexcept
     101                 : {
     102           12695 :     BOOST_ASSERT(
     103                 :         pos == 0 ||
     104                 :         ref.data()[pos - 1] == '/');
     105           12695 :     auto const end = ref.end();
     106                 :     char const* const p0 =
     107           12695 :         ref.data() + pos;
     108           12695 :     dn = 0;
     109           12695 :     auto p = p0;
     110           56663 :     while(p != end)
     111                 :     {
     112           49262 :         if(*p == '/')
     113            5294 :             break;
     114           43968 :         if(*p != '%')
     115                 :         {
     116           39695 :             ++p;
     117           39695 :             continue;
     118                 :         }
     119            4273 :         p += 3;
     120            4273 :         dn += 2;
     121                 :     }
     122           12695 :     next = p - ref.data();
     123           12695 :     dn = p - p0 - dn;
     124           12695 :     s_ = make_pct_string_view_unsafe(
     125           12695 :         p0, p - p0, dn);
     126           12695 : }
     127                 : 
     128                 : inline
     129                 : void
     130           10857 : segments_iter_impl::
     131                 : increment() noexcept
     132                 : {
     133           10857 :     BOOST_ASSERT(
     134                 :         index != ref.nseg());
     135           10857 :     auto const old_index = index;
     136           10857 :     auto const old_dn = dn;
     137                 :     // add decoded length of previous segment
     138           10857 :     decoded_prefix += old_dn;
     139           10857 :     if(old_index > 0)
     140                 :         // account for the '/' separator we just crossed
     141            6005 :         ++decoded_prefix;
     142           10857 :     ++index;
     143           10857 :     pos = next;
     144           10857 :     if(index == ref.nseg())
     145            4765 :         return;
     146                 :     // "/" segment
     147            6092 :     auto const end = ref.end();
     148            6092 :     auto p = ref.data() + pos;
     149            6092 :     BOOST_ASSERT(p != end);
     150            6092 :     BOOST_ASSERT(*p == '/');
     151            6092 :     dn = 0;
     152            6092 :     ++p; // skip '/'
     153            6092 :     auto const p0 = p;
     154           31779 :     while(p != end)
     155                 :     {
     156           28672 :         if(*p == '/')
     157            2985 :             break;
     158           25687 :         if(*p != '%')
     159                 :         {
     160           24649 :             ++p;
     161           24649 :             continue;
     162                 :         }
     163            1038 :         p += 3;
     164            1038 :         dn += 2;
     165                 :     }
     166            6092 :     next = p - ref.data();
     167            6092 :     dn = p - p0 - dn;
     168            6092 :     s_ = make_pct_string_view_unsafe(
     169            6092 :         p0, p - p0, dn);
     170                 : }
     171                 : 
     172                 : inline
     173                 : void
     174            1979 : segments_iter_impl::
     175                 : decrement() noexcept
     176                 : {
     177            1979 :     BOOST_ASSERT(index != 0);
     178            1979 :     auto const current_dn = dn;
     179            1979 :     auto const current_index = index;
     180                 :     // remove the decoded length of the segment we're leaving
     181            1979 :     decoded_prefix -= current_dn;
     182            1979 :     if(current_index > 0 && decoded_prefix > 0)
     183                 :         // drop the '/' separator when stepping left of it
     184            1979 :         --decoded_prefix;
     185            1979 :     --index;
     186            1979 :     if(index == 0)
     187                 :     {
     188             794 :         pos = path_prefix(ref.buffer());
     189             794 :         decoded_prefix = pos;
     190             794 :         update();
     191             794 :         BOOST_ASSERT(! s_.ends_with('/'));
     192             794 :         return;
     193                 :     }
     194                 :     // scan backwards to find the '/' before
     195                 :     // the previous segment
     196            1185 :     auto const begin = ref.data() +
     197            1185 :         path_prefix(ref.buffer());
     198            1185 :     auto p = ref.data() + pos;
     199            1185 :     BOOST_ASSERT(p != begin);
     200            4738 :     while(p != begin)
     201                 :     {
     202            4738 :         --p;
     203            4738 :         if(*p == '/')
     204            1185 :             break;
     205                 :     }
     206            1185 :     pos = p - ref.data() + 1;
     207            1185 :     update();
     208            1185 :     --pos;
     209                 : }
     210                 : 
     211                 : } // detail
     212                 : } // urls
     213                 : } // boost
     214                 : 
     215                 : #endif
        

Generated by: LCOV version 2.3