LCOV - code coverage report
Current view: top level - libs/url/src/detail/segments_iter_impl.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 99.2 % 124 123
Test Date: 2025-11-10 19:06:20 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              : 
      12              : #include <boost/url/detail/config.hpp>
      13              : #include "path.hpp"
      14              : #include "decode.hpp"
      15              : #include <boost/url/detail/segments_iter_impl.hpp>
      16              : #include "boost/url/rfc/detail/path_rules.hpp"
      17              : #include <boost/assert.hpp>
      18              : 
      19              : namespace boost {
      20              : namespace urls {
      21              : namespace detail {
      22              : 
      23              : // begin
      24         2286 : segments_iter_impl::
      25              : segments_iter_impl(
      26         2286 :     detail::path_ref const& ref_) noexcept
      27         2286 :     : ref(ref_)
      28              : {
      29         2286 :     pos = path_prefix(ref.buffer());
      30              :     // begin() starts after any malleable prefix but remembers decoded chars skipped
      31         2286 :     decoded_prefix = pos;
      32         2286 :     update();
      33         2286 : }
      34              : 
      35              : // end
      36         1854 : segments_iter_impl::
      37              : segments_iter_impl(
      38              :     detail::path_ref const& ref_,
      39         1854 :     int) noexcept
      40         1854 :     : ref(ref_)
      41         1854 :     , pos(ref.size())
      42         1854 :     , next(ref.size())
      43         1854 :     , index(ref.nseg())
      44              : {
      45              :     // end() carries the total decoded length for O(1) range math
      46         1854 :     decoded_prefix = ref.decoded_size();
      47         1854 : }
      48              : 
      49          595 : segments_iter_impl::
      50              : segments_iter_impl(
      51              :     url_impl const& u_,
      52              :     std::size_t pos_,
      53          595 :     std::size_t index_) noexcept
      54          595 :     : ref(u_)
      55          595 :     , pos(pos_)
      56          595 :     , index(index_)
      57              : {
      58          595 :     auto const total = ref.nseg();
      59          595 :     if(index >= total)
      60              :     {
      61          158 :         pos = ref.size();
      62          158 :         next = ref.size();
      63          158 :         decoded_prefix = ref.decoded_size();
      64              :         // iterator equal to end: nothing to decode
      65          158 :         dn = 0;
      66          158 :         return;
      67              :     }
      68              : 
      69          437 :     if(index == 0)
      70              :     {
      71          238 :         pos = path_prefix(ref.buffer());
      72              :         // first segment inherits the prefix size (including leading '/')
      73          238 :         decoded_prefix = pos;
      74          238 :         update();
      75          238 :         return;
      76              :     }
      77              : 
      78          199 :     BOOST_ASSERT(pos <= ref.size());
      79              :     // compute decoded prefix by scanning once up to the encoded offset
      80          199 :     decoded_prefix = detail::decode_bytes_unsafe(
      81              :         core::string_view(ref.data(), pos));
      82          199 :     if(pos != ref.size())
      83              :     {
      84          199 :         BOOST_ASSERT(
      85              :             ref.data()[pos] == '/');
      86          199 :         ++pos; // skip '/'
      87          199 :         update();
      88          199 :         --pos;
      89          199 :         return;
      90              :     }
      91              : 
      92            0 :     update();
      93              : }
      94              : 
      95              : void
      96         2723 : segments_iter_impl::
      97              : update() noexcept
      98              : {
      99         2723 :     auto const end = ref.end();
     100              :     char const* const p0 =
     101         2723 :         ref.data() + pos;
     102         2723 :     dn = 0;
     103         2723 :     auto p = p0;
     104        10455 :     while(p != end)
     105              :     {
     106         9322 :         if(*p == '/')
     107         1590 :             break;
     108         7732 :         if(*p != '%')
     109              :         {
     110         7364 :             ++p;
     111         7364 :             continue;
     112              :         }
     113          368 :         p += 3;
     114          368 :         dn += 2;
     115              :     }
     116         2723 :     next = p - ref.data();
     117         2723 :     dn = p - p0 - dn;
     118         2723 :     s_ = make_pct_string_view_unsafe(
     119         2723 :         p0, p - p0, dn);
     120         2723 : }
     121              : 
     122              : void
     123         2775 : segments_iter_impl::
     124              : increment() noexcept
     125              : {
     126         2775 :     BOOST_ASSERT(
     127              :         index != ref.nseg());
     128         2775 :     auto const old_index = index;
     129         2775 :     auto const old_dn = dn;
     130              :     // add decoded length of previous segment
     131         2775 :     decoded_prefix += old_dn;
     132         2775 :     if(old_index > 0)
     133              :         // account for the '/' separator we just crossed
     134         1579 :         ++decoded_prefix;
     135         2775 :     ++index;
     136         2775 :     pos = next;
     137         2775 :     if(index == ref.nseg())
     138         1135 :         return;
     139              :     // "/" segment
     140         1640 :     auto const end = ref.end();
     141         1640 :     auto p = ref.data() + pos;
     142         1640 :     BOOST_ASSERT(p != end);
     143         1640 :     BOOST_ASSERT(*p == '/');
     144         1640 :     dn = 0;
     145         1640 :     ++p; // skip '/'
     146         1640 :     auto const p0 = p;
     147         7185 :     while(p != end)
     148              :     {
     149         6493 :         if(*p == '/')
     150          948 :             break;
     151         5545 :         if(*p != '%')
     152              :         {
     153         5433 :             ++p;
     154         5433 :             continue;
     155              :         }
     156          112 :         p += 3;
     157          112 :         dn += 2;
     158              :     }
     159         1640 :     next = p - ref.data();
     160         1640 :     dn = p - p0 - dn;
     161         1640 :     s_ = make_pct_string_view_unsafe(
     162         1640 :         p0, p - p0, dn);
     163              : }
     164              : 
     165              : void
     166         1584 : segments_iter_impl::
     167              : decrement() noexcept
     168              : {
     169         1584 :     BOOST_ASSERT(index != 0);
     170         1584 :     auto const current_dn = dn;
     171         1584 :     auto const current_index = index;
     172              :     // remove the decoded length of the segment we're leaving
     173         1584 :     decoded_prefix -= current_dn;
     174         1584 :     if(current_index > 0 && decoded_prefix > 0)
     175              :         // drop the '/' separator when stepping left of it
     176         1584 :         --decoded_prefix;
     177         1584 :     --index;
     178         1584 :     if(index == 0)
     179              :     {
     180          549 :         next = pos;
     181          549 :         pos = path_prefix(ref.buffer());
     182          549 :         decoded_prefix = pos;
     183          549 :         s_ = core::string_view(
     184          549 :             ref.data() + pos,
     185          549 :             next - pos);
     186          549 :         BOOST_ASSERT(! s_.ends_with('/'));
     187          549 :         return;
     188              :     }
     189         1035 :     auto const begin = ref.data() +
     190         1035 :         path_prefix(ref.buffer());
     191         1035 :     next = pos;
     192         1035 :     auto p = ref.data() + next;
     193         1035 :     auto const p1 = p;
     194         1035 :     BOOST_ASSERT(p != begin);
     195         1035 :     dn = 0;
     196         3188 :     while(p != begin)
     197              :     {
     198         3188 :         --p;
     199         3188 :         if(*p == '/')
     200              :         {
     201         1035 :             ++dn;
     202         1035 :             break;
     203              :         }
     204         2153 :         if(*p == '%')
     205           28 :             dn += 2;
     206              :     }
     207         1035 :     dn = p1 - p - dn;
     208         1035 :     pos = p - ref.data();
     209              :     // keep decoded_prefix consistent with new pos
     210              :     // (already adjusted above)
     211         1035 :     s_ = make_pct_string_view_unsafe(
     212         1035 :         p + 1, p1 - p - 1, dn);
     213              : }
     214              : 
     215              : } // detail
     216              : } // url
     217              : } // boost
        

Generated by: LCOV version 2.1