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

            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         2322 : segments_iter_impl::
      25              : segments_iter_impl(
      26         2322 :     detail::path_ref const& ref_) noexcept
      27         2322 :     : ref(ref_)
      28              : {
      29         2322 :     pos = path_prefix(ref.buffer());
      30              :     // begin() starts after any malleable prefix but remembers decoded chars skipped
      31         2322 :     decoded_prefix = pos;
      32         2322 :     update();
      33         2322 : }
      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            0 :     update();
      95              : }
      96              : 
      97              : inline
      98              : void
      99         2760 : segments_iter_impl::
     100              : update() noexcept
     101              : {
     102         2760 :     auto const end = ref.end();
     103              :     char const* const p0 =
     104         2760 :         ref.data() + pos;
     105         2760 :     dn = 0;
     106         2760 :     auto p = p0;
     107        10644 :     while(p != end)
     108              :     {
     109         9508 :         if(*p == '/')
     110         1624 :             break;
     111         7884 :         if(*p != '%')
     112              :         {
     113         7516 :             ++p;
     114         7516 :             continue;
     115              :         }
     116          368 :         p += 3;
     117          368 :         dn += 2;
     118              :     }
     119         2760 :     next = p - ref.data();
     120         2760 :     dn = p - p0 - dn;
     121         2760 :     s_ = make_pct_string_view_unsafe(
     122         2760 :         p0, p - p0, dn);
     123         2760 : }
     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