100.00% Lines (39/39) 100.00% Functions (4/4)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2025 Alan de Freitas (alandefreitas@gmail.com) 2   // Copyright (c) 2025 Alan de Freitas (alandefreitas@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/boostorg/url 7   // Official repository: https://github.com/boostorg/url
8   // 8   //
9   9  
10   #ifndef BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP 10   #ifndef BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP
11   #define BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP 11   #define BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP
12   12  
13   #include <boost/url/detail/config.hpp> 13   #include <boost/url/detail/config.hpp>
14   #include <boost/url/detail/url_impl.hpp> 14   #include <boost/url/detail/url_impl.hpp>
15   #include <boost/url/segments_base.hpp> 15   #include <boost/url/segments_base.hpp>
16   #include <boost/url/segments_encoded_base.hpp> 16   #include <boost/url/segments_encoded_base.hpp>
17   #include <boost/core/detail/string_view.hpp> 17   #include <boost/core/detail/string_view.hpp>
18   #include <boost/assert.hpp> 18   #include <boost/assert.hpp>
19   19  
20   namespace boost { 20   namespace boost {
21   namespace urls { 21   namespace urls {
22   namespace detail { 22   namespace detail {
23   23  
24   struct segments_iter_access 24   struct segments_iter_access
25   { 25   {
26   static 26   static
27   segments_iter_impl const& 27   segments_iter_impl const&
HITCBC 28   40 impl(segments_base::iterator const& it) noexcept 28   40 impl(segments_base::iterator const& it) noexcept
29   { 29   {
HITCBC 30   40 return it.it_; 30   40 return it.it_;
31   } 31   }
32   32  
33   static 33   static
34   segments_iter_impl const& 34   segments_iter_impl const&
HITCBC 35   6 impl(segments_encoded_base::iterator const& it) noexcept 35   6 impl(segments_encoded_base::iterator const& it) noexcept
36   { 36   {
HITCBC 37   6 return it.it_; 37   6 return it.it_;
38   } 38   }
39   }; 39   };
40   40  
41   inline 41   inline
42   path_ref 42   path_ref
HITCBC 43   23 make_subref_from_impls( 43   23 make_subref_from_impls(
44   segments_iter_impl const& first, 44   segments_iter_impl const& first,
45   segments_iter_impl const& last) noexcept 45   segments_iter_impl const& last) noexcept
46   { 46   {
HITCBC 47   23 BOOST_ASSERT(first.ref.alias_of(last.ref)); 47   23 BOOST_ASSERT(first.ref.alias_of(last.ref));
HITCBC 48   23 path_ref const& ref = first.ref; 48   23 path_ref const& ref = first.ref;
49   49  
HITCBC 50   23 std::size_t const i0 = first.index; 50   23 std::size_t const i0 = first.index;
HITCBC 51   23 std::size_t const i1 = last.index; 51   23 std::size_t const i1 = last.index;
HITCBC 52   23 BOOST_ASSERT(i0 <= i1); 52   23 BOOST_ASSERT(i0 <= i1);
HITCBC 53   23 std::size_t const nseg = i1 - i0; 53   23 std::size_t const nseg = i1 - i0;
54   54  
HITCBC 55   23 bool const absolute = ref.buffer().starts_with('/'); 55   23 bool const absolute = ref.buffer().starts_with('/');
56   56  
57   // Empty range 57   // Empty range
HITCBC 58   23 if (nseg == 0) 58   23 if (nseg == 0)
59   { 59   {
60   std::size_t off0; 60   std::size_t off0;
HITCBC 61   6 if (i0 == 0) 61   6 if (i0 == 0)
62   { 62   {
63   // [begin, begin): don't include the leading '/' 63   // [begin, begin): don't include the leading '/'
64   // for absolute, start right after the leading '/'; 64   // for absolute, start right after the leading '/';
HITCBC 65   3 if (absolute) 65   3 if (absolute)
66   { 66   {
HITCBC 67   2 off0 = 1; 67   2 off0 = 1;
68   } 68   }
69   // for relative, start at the first segment character. 69   // for relative, start at the first segment character.
70   else 70   else
71   { 71   {
HITCBC 72   1 off0 = first.pos; 72   1 off0 = first.pos;
73   } 73   }
74   } 74   }
75   else 75   else
76   { 76   {
77   // [it, it) in the middle: 77   // [it, it) in the middle:
78   // skip the separator before segment i0 78   // skip the separator before segment i0
HITCBC 79   3 off0 = first.pos + 1; 79   3 off0 = first.pos + 1;
80   } 80   }
81   81  
HITCBC 82   6 core::string_view const sub(ref.data() + off0, 0); 82   6 core::string_view const sub(ref.data() + off0, 0);
HITCBC 83   6 return {sub, 0, 0}; 83   6 return {sub, 0, 0};
84   } 84   }
85   85  
86   // General case: non-empty range 86   // General case: non-empty range
87   // Start offset 87   // Start offset
88   std::size_t off0; 88   std::size_t off0;
HITCBC 89   17 if (i0 == 0) 89   17 if (i0 == 0)
90   { 90   {
HITCBC 91   10 if (absolute) 91   10 if (absolute)
92   { 92   {
93   // include leading '/' 93   // include leading '/'
HITCBC 94   5 off0 = 0; 94   5 off0 = 0;
95   } 95   }
96   else 96   else
97   { 97   {
98   // relative: start at first segment 98   // relative: start at first segment
HITCBC 99   5 off0 = first.pos; 99   5 off0 = first.pos;
100   } 100   }
101   } 101   }
102   else 102   else
103   { 103   {
104   // include the separator preceding segment i0 104   // include the separator preceding segment i0
HITCBC 105   7 off0 = first.pos; 105   7 off0 = first.pos;
106   } 106   }
107   107  
108   // End offset 108   // End offset
109   std::size_t off1; 109   std::size_t off1;
HITCBC 110   17 if(i1 == ref.nseg()) 110   17 if(i1 == ref.nseg())
111   { 111   {
HITCBC 112   9 off1 = ref.size(); 112   9 off1 = ref.size();
113   } 113   }
114   else 114   else
115   { 115   {
116   // stop before the slash preceding i1 116   // stop before the slash preceding i1
HITCBC 117   8 off1 = last.pos; 117   8 off1 = last.pos;
118   } 118   }
119   119  
HITCBC 120   17 BOOST_ASSERT(off1 >= off0); 120   17 BOOST_ASSERT(off1 >= off0);
HITCBC 121   17 core::string_view const sub(ref.data() + off0, off1 - off0); 121   17 core::string_view const sub(ref.data() + off0, off1 - off0);
122   122  
123   // decoded sizes reuse iterator bookkeeping instead of rescanning 123   // decoded sizes reuse iterator bookkeeping instead of rescanning
HITCBC 124   17 std::size_t start_dn = (i0 == 0) ? 0 : first.decoded_prefix_size(); 124   17 std::size_t start_dn = (i0 == 0) ? 0 : first.decoded_prefix_size();
HITCBC 125   17 std::size_t const end_dn = last.decoded_prefix_size(); // already excludes segment at `last` 125   17 std::size_t const end_dn = last.decoded_prefix_size(); // already excludes segment at `last`
HITCBC 126   17 BOOST_ASSERT(end_dn >= start_dn); 126   17 BOOST_ASSERT(end_dn >= start_dn);
HITCBC 127   17 std::size_t const dn_sum = end_dn - start_dn; 127   17 std::size_t const dn_sum = end_dn - start_dn;
128   128  
HITCBC 129   17 return {sub, dn_sum, nseg}; 129   17 return {sub, dn_sum, nseg};
130   } 130   }
131   131  
132   template<class Iter> 132   template<class Iter>
133   inline 133   inline
134   path_ref 134   path_ref
HITCBC 135   23 make_subref(Iter const& first, Iter const& last) noexcept 135   23 make_subref(Iter const& first, Iter const& last) noexcept
136   { 136   {
HITCBC 137   23 auto const& f = segments_iter_access::impl(first); 137   23 auto const& f = segments_iter_access::impl(first);
HITCBC 138   23 auto const& l = segments_iter_access::impl(last); 138   23 auto const& l = segments_iter_access::impl(last);
HITCBC 139   23 return make_subref_from_impls(f, l); 139   23 return make_subref_from_impls(f, l);
140   } 140   }
141   141  
142   } // detail 142   } // detail
143   } // urls 143   } // urls
144   } // boost 144   } // boost
145   145  
146   #endif 146   #endif